143#if defined (PICO_GFX_GL)
145#elif defined (PICO_GFX_GLES)
147#elif defined (PICO_GFX_D3D)
149#elif defined (PICO_GFX_METAL)
151#elif defined (PICO_GFX_WEBGPU)
154 #error "GFX backend must be specified"
157#include "sokol_gfx.h"
163#define PG_MAX_VERTEX_ATTRIBUTES SG_MAX_VERTEX_ATTRIBUTES
164#define PG_MAX_VERTEX_BUFFERS SG_MAX_VERTEXBUFFER_BINDSLOTS
165#define PG_MAX_TEXTURE_SLOTS SG_MAX_IMAGE_BINDSLOTS
166#define PG_MAX_SAMPLER_SLOTS SG_MAX_SAMPLER_BINDSLOTS
453#define pg_create_shader(ctx, prefix) \
454 pg_create_shader_internal( \
456 (pg_shader_internal_t) \
458 prefix##_shader_desc, \
459 prefix##_attr_slot, \
460 prefix##_image_slot, \
461 prefix##_sampler_slot, \
462 prefix##_uniformblock_slot, \
463 prefix##_uniformblock_size, \
594 int width,
int height,
595 const uint8_t* data,
size_t size,
606 int width,
int height,
675 size_t element_size);
688 size_t max_elements);
737 const sg_shader_desc* (*get_shader_desc)(sg_backend backend);
738 int (*get_attr_slot)(
const char* attr_name);
739 int (*get_img_slot)(
const char* name);
740 int (*get_smp_slot)(
const char* name);
741 int (*get_uniformblock_slot)(
const char* ub_name);
742 size_t (*get_uniformblock_size)(
const char* ub_name);
753#ifdef PICO_GFX_IMPLEMENTATION
761#ifndef PICO_GFX_STACK_MAX_SIZE
762#define PICO_GFX_STACK_MAX_SIZE 16
765#ifndef PICO_GFX_HASHTABLE_KEY_SIZE
766#define PICO_GFX_HASHTABLE_KEY_SIZE 16
774 #define PICO_GFX_ASSERT(expr) ((void)0)
776 #ifndef PICO_GFX_ASSERT
778 #define PICO_GFX_ASSERT(expr) (assert(expr))
782#if !defined(PICO_GFX_MALLOC) || !defined(PICO_GFX_REALLOC) || !defined(PICO_GFX_FREE)
784#define PICO_GFX_MALLOC(size, ctx) (malloc(size))
785#define PICO_GFX_REALLOC(ptr, size, ctx) (realloc(ptr, size))
786#define PICO_GFX_FREE(ptr, ctx) (free(ptr))
791 #define PICO_GFX_LOG(...) (pg_log(__VA_ARGS__))
798static void pg_alloc_uniform_block(
pg_shader_t* shader,
const char* name);
802 PG_BUFFER_TYPE_VERTEX,
803 PG_BUFFER_TYPE_INDEX,
806static sg_primitive_type pg_map_primitive(
pg_primitive_t primitive);
811static sg_buffer_type pg_map_buffer_type(pg_buffer_type_t type);
813static void pg_log_sg(
const char* tag,
815 uint32_t log_item_id,
816 const char* message_or_null,
818 const char* filename_or_null,
821static void pg_log(
const char* fmt, ...);
828 typedef uint32_t pg_hash_t;
830 typedef uint64_t pg_hash_t;
833typedef struct pg_hashtable_t pg_hashtable_t;
834typedef struct pg_hashtable_iterator_t pg_hashtable_iterator_t;
836typedef void (*pg_hashtable_iterator_fn)(pg_hashtable_iterator_t* iterator,
840static pg_hashtable_t* pg_hashtable_new(
size_t capacity,
size_t key_size,
841 size_t value_size,
void* mem_ctx);
843static void pg_hashtable_free(pg_hashtable_t* ht);
845static void pg_hashtable_init_iterator(
const pg_hashtable_t* ht,
846 pg_hashtable_iterator_t* iterator);
848static bool pg_hashtable_iterator_next(pg_hashtable_iterator_t* iterator,
849 char** key,
void** value);
851static void pg_hashtable_put(pg_hashtable_t* ht,
855static void* pg_hashtable_get(
const pg_hashtable_t* ht,
const char* key);
857struct pg_hashtable_iterator_t
859 const pg_hashtable_t* ht;
868typedef struct pg_arena_t pg_arena_t;
870static pg_arena_t* pg_arena_create(
size_t block_size,
void* mem_ctx);
871static void* pg_arena_malloc(pg_arena_t* arena,
size_t size);
873static void pg_arena_destroy(pg_arena_t* arena);
879static void* pg_malloc(
size_t size,
void* ctx)
882 return PICO_GFX_MALLOC(size, ctx);
885static void pg_free(
void* ptr,
void* ctx)
888 PICO_GFX_FREE(ptr, ctx);
891typedef struct pg_rect_t
893 int x, y, width, height;
896typedef struct pg_state_t
898 sg_color clear_color;
910 sg_swapchain swapchain;
916 sg_pass default_pass;
918 pg_state_t state_stack[PICO_GFX_STACK_MAX_SIZE];
936 const sg_shader_desc* desc;
941 pg_hashtable_t* uniform_blocks;
958 sg_image depth_handle;
959 sg_attachments attachments;
972 pg_buffer_type_t type;
984 .logger.func = pg_log_sg,
987 .alloc_fn = pg_malloc,
991 .environment.defaults.color_format = SG_PIXELFORMAT_RGBA8,
1004 if (!ctx)
return NULL;
1008 ctx->mem_ctx = mem_ctx;
1009 ctx->window_width = window_width;
1010 ctx->window_height = window_height;
1014 ctx->swapchain = (sg_swapchain)
1016 .width = window_width,
1017 .height = window_height,
1025 PICO_GFX_ASSERT(ctx);
1026 PICO_GFX_FREE(ctx, ctx->mem_ctx);
1031 #if defined (PICO_GFX_GL)
1033 #elif defined (PICO_GFX_GLES)
1035 #elif defined (PICO_GFX_D3D)
1037 #elif defined (PICO_GFX_METAL)
1039 #elif defined (PICO_GFX_WEBGPU)
1042 #error "Unknown GFX backend"
1048 ctx->swapchain.width = ctx->window_width = width;
1049 ctx->swapchain.height = ctx->window_height = height;
1061 *width = ctx->window_width;
1064 *height = ctx->window_height;
1069 PICO_GFX_ASSERT(ctx);
1070 PICO_GFX_ASSERT(!ctx->pass_active);
1072 sg_pass_action action = { 0 };
1076 sg_color color = ctx->state.clear_color;
1078 action.colors[0] = (sg_color_attachment_action)
1080 .load_action = SG_LOADACTION_CLEAR,
1081 .clear_value = color
1085 sg_pass pass = { .action = action };
1089 pass.attachments = target->attachments;
1090 ctx->target = target;
1095 pass.swapchain = ctx->swapchain;
1098 sg_begin_pass(&pass);
1103 ctx->pass_active =
true;
1110 ctx->pass_active =
false;
1121 PICO_GFX_ASSERT(ctx);
1122 PICO_GFX_ASSERT(ctx->stack_size < PICO_GFX_STACK_MAX_SIZE);
1124 ctx->state_stack[ctx->stack_size] = ctx->state;
1130 PICO_GFX_ASSERT(ctx);
1131 PICO_GFX_ASSERT(ctx->stack_size > 0);
1133 ctx->state = ctx->state_stack[ctx->stack_size - 1];
1139 PICO_GFX_ASSERT(ctx);
1140 ctx->state.clear_color = (sg_color){ r, g, b, a};
1145 PICO_GFX_ASSERT(ctx);
1151 PICO_GFX_ASSERT(ctx);
1152 ctx->state.viewport = (pg_rect_t){ x, y, w, h};
1157 PICO_GFX_ASSERT(ctx);
1172 PICO_GFX_ASSERT(ctx);
1173 ctx->state.scissor = (pg_rect_t){ x, y, w, h};
1178 PICO_GFX_ASSERT(ctx);
1187 pg_set_scissor(ctx, 0, 0, ctx->window_width, ctx->window_height);
1193 PICO_GFX_ASSERT(ctx);
1194 ctx->state.pipeline = pipeline;
1199 PICO_GFX_ASSERT(ctx);
1205 PICO_GFX_ASSERT(ctx);
1206 PICO_GFX_ASSERT(!buffer || buffer->type == PG_BUFFER_TYPE_VERTEX);
1208 PICO_GFX_ASSERT(slot >= 0);
1211 ctx->state.buffers[slot] = buffer;
1216 PICO_GFX_ASSERT(ctx);
1217 memset(&ctx->state.buffers, 0,
sizeof(ctx->state.buffers));
1222 PICO_GFX_ASSERT(ctx);
1223 PICO_GFX_ASSERT(!buffer || buffer->type == PG_BUFFER_TYPE_INDEX);
1224 ctx->state.index_buffer = buffer;
1229 PICO_GFX_ASSERT(ctx);
1230 ctx->state.index_buffer = NULL;
1235 PICO_GFX_ASSERT(shader);
1236 PICO_GFX_ASSERT(name);
1238 int slot = shader->internal.get_img_slot(name);
1240 PICO_GFX_ASSERT(slot >= 0);
1243 shader->textures[slot] = texture;
1248 PICO_GFX_ASSERT(shader);
1249 memset(shader->textures, 0,
sizeof(shader->textures));
1254 PICO_GFX_ASSERT(shader);
1255 PICO_GFX_ASSERT(name);
1257 int slot = shader->internal.get_smp_slot(name);
1259 PICO_GFX_ASSERT(slot >= 0);
1262 shader->samplers[slot] = sampler;
1267 PICO_GFX_ASSERT(shader);
1268 memset(shader->samplers, 0,
sizeof(shader->samplers));
1273 PICO_GFX_ASSERT(ctx);
1275 memset(&ctx->state, 0,
sizeof(pg_state_t));
1291 desc->layout.attrs[slot] = (sg_vertex_attr_state)
1293 .format = pg_map_vertex_format(layout->
attrs[slot].
format),
1305 int step = layout->
bufs[slot].
step;
1309 desc->layout.buffers[slot] = (sg_vertex_buffer_layout_state)
1311 .step_func = SG_VERTEXSTEP_PER_INSTANCE,
1315 desc->layout.buffers[slot].step_rate = (step >= 1) ? step : 1;
1323 PICO_GFX_ASSERT(shader);
1324 PICO_GFX_ASSERT(opts);
1328 sg_pipeline_desc desc = { 0 };
1330 pg_set_attributes(&opts->
layout, &desc);
1331 pg_set_buffers(&opts->
layout, &desc);
1333 desc.primitive_type = pg_map_primitive(opts->
primitive);
1335 pipeline->blend_enabled =
false;
1339 pipeline->blend_enabled =
true;
1340 pipeline->blend_mode = opts->
blend;
1343 desc.colors[0].blend.enabled =
true;
1344 desc.colors[0].blend.src_factor_rgb = pg_map_blend_factor(blend_mode->
color_src);
1345 desc.colors[0].blend.dst_factor_rgb = pg_map_blend_factor(blend_mode->
color_dst);
1346 desc.colors[0].blend.src_factor_alpha = pg_map_blend_factor(blend_mode->
alpha_src);
1347 desc.colors[0].blend.dst_factor_alpha = pg_map_blend_factor(blend_mode->
alpha_dst);
1348 desc.colors[0].blend.op_rgb = pg_map_blend_eq(blend_mode->
color_eq);
1349 desc.colors[0].blend.op_alpha = pg_map_blend_eq(blend_mode->
alpha_eq);
1352 desc.colors[0].pixel_format = SG_PIXELFORMAT_RGBA8;
1355 desc.index_type = SG_INDEXTYPE_UINT32;
1357 desc.index_type = SG_INDEXTYPE_NONE;
1361 desc.depth.pixel_format = SG_PIXELFORMAT_DEPTH;
1362 desc.depth.write_enabled =
true;
1367 desc.face_winding = SG_FACEWINDING_CCW;
1368 desc.shader = shader->handle;
1370 pipeline->ctx = ctx;
1371 pipeline->handle = sg_make_pipeline(&desc);
1372 pipeline->indexed = opts->
indexed;
1373 pipeline->shader = shader;
1375 PICO_GFX_ASSERT(sg_query_pipeline_state(pipeline->handle) == SG_RESOURCESTATE_VALID);
1382 PICO_GFX_ASSERT(pipeline);
1383 sg_destroy_pipeline(pipeline->handle);
1384 PICO_GFX_FREE(pipeline, pipeline->ctx->mem_ctx);
1389 PICO_GFX_ASSERT(pipeline);
1390 return pipeline->shader;
1395 PICO_GFX_ASSERT(pipeline);
1397 if (pipeline->blend_enabled)
1398 return &pipeline->blend_mode;
1411 shader->internal = internal;
1414 PICO_GFX_ASSERT(shader->desc);
1416 shader->handle = sg_make_shader(shader->desc);
1418 shader->uniform_blocks = pg_hashtable_new(16, PICO_GFX_HASHTABLE_KEY_SIZE,
1419 sizeof(pg_uniform_block_t),
1422 shader->arena = pg_arena_create(512, ctx->mem_ctx);
1429 PICO_GFX_ASSERT(shader);
1430 sg_destroy_shader(shader->handle);
1431 pg_hashtable_free(shader->uniform_blocks);
1432 pg_arena_destroy(shader->arena);
1433 PICO_GFX_FREE(shader, shader->ctx->mem_ctx);
1438 PICO_GFX_ASSERT(shader);
1439 return shader->handle.id;
1446 PICO_GFX_ASSERT(shader);
1447 PICO_GFX_ASSERT(name);
1448 PICO_GFX_ASSERT(data);
1450 pg_uniform_block_t* block = pg_hashtable_get(shader->uniform_blocks, name);
1454 pg_alloc_uniform_block(shader, name);
1455 block = pg_hashtable_get(shader->uniform_blocks, name);
1458 PICO_GFX_ASSERT(block);
1460 memcpy(block->data, data, block->size);
1464 int width,
int height,
1465 const uint8_t* data,
size_t size,
1468 PICO_GFX_ASSERT(width > 0);
1469 PICO_GFX_ASSERT(height > 0);
1470 PICO_GFX_ASSERT(data);
1471 PICO_GFX_ASSERT(size > 0);
1476 PICO_GFX_ASSERT(opts->
mipmaps >= 0);
1480 sg_image_desc desc = { 0 };
1482 desc.pixel_format = SG_PIXELFORMAT_RGBA8;
1484 desc.width = texture->width = width;
1485 desc.height = texture->height = height;
1487 desc.num_mipmaps = opts->
mipmaps;
1488 desc.data.subimage[0][0] = (sg_range){ .ptr = data, .size = size };
1491 texture->target =
false;
1492 texture->handle = sg_make_image(&desc);
1494 PICO_GFX_ASSERT(sg_query_image_state(texture->handle) == SG_RESOURCESTATE_VALID);
1500 int width,
int height,
1503 PICO_GFX_ASSERT(width > 0);
1504 PICO_GFX_ASSERT(height > 0);
1509 PICO_GFX_ASSERT(opts->
mipmaps >= 0);
1513 sg_image_desc desc = { 0 };
1515 desc.render_target =
true;
1516 desc.pixel_format = SG_PIXELFORMAT_RGBA8;
1518 desc.width = texture->width = width;
1519 desc.height = texture->height = height;
1521 desc.num_mipmaps = opts->
mipmaps;
1524 texture->handle = sg_make_image(&desc);
1525 texture->target =
true;
1527 PICO_GFX_ASSERT(sg_query_image_state(texture->handle) == SG_RESOURCESTATE_VALID);
1529 desc.pixel_format = SG_PIXELFORMAT_DEPTH;
1530 texture->depth_handle = sg_make_image(&desc);
1532 PICO_GFX_ASSERT(sg_query_image_state(texture->depth_handle) == SG_RESOURCESTATE_VALID);
1535 texture->attachments = sg_make_attachments(&(sg_attachments_desc)
1537 .colors[0].image = texture->handle,
1538 .depth_stencil.image = texture->depth_handle,
1546 if (texture->target)
1548 sg_destroy_image(texture->depth_handle);
1551 sg_destroy_image(texture->handle);
1552 PICO_GFX_FREE(texture, texture->ctx->mem_ctx);
1558 sg_image_data img_data = { 0 };
1559 img_data.subimage[0][0].ptr = data;
1560 img_data.subimage[0][0].size = (size_t)(width * height);
1561 sg_update_image(texture->handle, &img_data);
1566 PICO_GFX_ASSERT(texture);
1567 return texture->handle.id;
1572 PICO_GFX_ASSERT(texture);
1575 *width = texture->width;
1578 *height = texture->height;
1588 sg_sampler_desc desc = { 0 };
1590 desc.min_filter = (opts->
smooth) ? SG_FILTER_LINEAR : SG_FILTER_NEAREST;
1591 desc.mag_filter = (opts->
smooth) ? SG_FILTER_LINEAR : SG_FILTER_NEAREST;
1593 desc.wrap_u = (opts->
repeat_u) ? SG_WRAP_REPEAT : SG_WRAP_CLAMP_TO_EDGE;
1594 desc.wrap_v = (opts->
repeat_v) ? SG_WRAP_REPEAT : SG_WRAP_CLAMP_TO_EDGE;
1597 sampler->handle = sg_make_sampler(&desc);
1604 sg_destroy_sampler(sampler->handle);
1605 PICO_GFX_FREE(sampler, sampler->ctx->mem_ctx);
1610 PICO_GFX_ASSERT(shader);
1612 pg_hashtable_iterator_t iterator;
1613 pg_hashtable_init_iterator(shader->uniform_blocks, &iterator);
1618 while (pg_hashtable_iterator_next(&iterator, &key, &value))
1620 pg_uniform_block_t* block = (pg_uniform_block_t*)value;
1622 sg_range range = { .ptr = block->data, .size = block->size };
1624 sg_apply_uniforms(block->slot, &range);
1632 size_t max_elements,
1633 size_t element_size)
1635 PICO_GFX_ASSERT(ctx);
1640 buffer->type = PG_BUFFER_TYPE_VERTEX;
1641 buffer->usage = usage;
1642 buffer->count = count;
1643 buffer->element_size = element_size;
1644 buffer->size = max_elements * element_size;
1647 buffer->handle = sg_make_buffer(&(sg_buffer_desc)
1649 .type = SG_BUFFERTYPE_VERTEXBUFFER,
1650 .usage = pg_map_usage(usage),
1651 .data = { .ptr = data, .size = count * element_size },
1652 .size = buffer->size
1655 PICO_GFX_ASSERT(sg_query_buffer_state(buffer->handle) == SG_RESOURCESTATE_VALID);
1664 size_t max_elements)
1666 PICO_GFX_ASSERT(ctx);
1671 buffer->type = PG_BUFFER_TYPE_INDEX;
1672 buffer->usage = usage;
1673 buffer->count = count;
1674 buffer->size = max_elements *
sizeof(uint32_t);
1677 buffer->handle = sg_make_buffer(&(sg_buffer_desc)
1679 .type = SG_BUFFERTYPE_INDEXBUFFER,
1680 .usage = pg_map_usage(usage),
1681 .data = { .ptr = data, .size = count *
sizeof(uint32_t) },
1682 .size = buffer->size
1685 PICO_GFX_ASSERT(sg_query_buffer_state(buffer->handle) == SG_RESOURCESTATE_VALID);
1692 PICO_GFX_ASSERT(buffer);
1693 PICO_GFX_ASSERT(data);
1694 PICO_GFX_ASSERT(count > 0);
1696 sg_update_buffer(buffer->handle, &(sg_range)
1699 .size = count * buffer->element_size
1702 buffer->count = count;
1708 PICO_GFX_ASSERT(buffer);
1709 PICO_GFX_ASSERT(data);
1710 PICO_GFX_ASSERT(count > 0);
1712 int offset = sg_append_buffer(buffer->handle, &(sg_range)
1715 .size = count * buffer->element_size
1718 buffer->count = count;
1719 buffer->offset = offset;
1726 PICO_GFX_ASSERT(buffer);
1727 return buffer->offset;
1732 PICO_GFX_ASSERT(buffer);
1733 buffer->offset = offset;
1738 PICO_GFX_ASSERT(buffer);
1740 sg_destroy_buffer(buffer->handle);
1742 buffer->handle = sg_make_buffer(&(sg_buffer_desc)
1744 .type = pg_map_buffer_type(buffer->type),
1745 .usage = pg_map_usage(buffer->usage),
1746 .data = { .ptr = NULL, .size = 0 },
1747 .size = buffer->size
1750 PICO_GFX_ASSERT(sg_query_buffer_state(buffer->handle) == SG_RESOURCESTATE_VALID);
1755 PICO_GFX_ASSERT(buffer);
1756 sg_destroy_buffer(buffer->handle);
1757 PICO_GFX_FREE(buffer, buffer->ctx->mem_ctx);
1760static void pg_apply_view_state(
const pg_ctx_t* ctx)
1762 const pg_rect_t* vp_rect = &ctx->state.viewport;
1763 sg_apply_viewport(vp_rect->x, vp_rect->y, vp_rect->width, vp_rect->height,
true);
1765 const pg_rect_t* s_rect = &ctx->state.scissor;
1766 sg_apply_scissor_rect(s_rect->x, s_rect->y, s_rect->width, s_rect->height,
true);
1769static void pg_apply_textures(
const pg_shader_t* shader, sg_bindings* bindings)
1773 if (!shader->textures[i])
1776 bindings->images[i] = shader->textures[i]->handle;
1780static void pg_apply_samplers(
const pg_shader_t* shader, sg_bindings* bindings)
1784 if (!shader->samplers[i])
1787 bindings->samplers[i] = shader->samplers[i]->handle;
1791static void pg_apply_buffers(
const pg_ctx_t* ctx, sg_bindings* bindings)
1795 for (
int slot = 0; buffers[slot] != NULL; slot++)
1797 bindings->vertex_buffer_offsets[slot] = buffers[slot]->offset;
1798 bindings->vertex_buffers[slot] = buffers[slot]->handle;
1802void pg_draw(
const pg_ctx_t* ctx,
size_t start,
size_t count,
size_t instances)
1804 PICO_GFX_ASSERT(ctx);
1805 PICO_GFX_ASSERT(ctx->pass_active);
1807 sg_bindings bindings = { 0 };
1811 pg_apply_textures(pipeline->shader, &bindings);
1812 pg_apply_samplers(pipeline->shader, &bindings);
1814 pg_apply_buffers(ctx, &bindings);
1815 pg_apply_view_state(ctx);
1817 if (ctx->state.index_buffer)
1819 bindings.index_buffer_offset = ctx->state.index_buffer->offset;
1820 bindings.index_buffer = ctx->state.index_buffer->handle;
1823 sg_apply_pipeline(pipeline->handle);
1824 sg_apply_bindings(&bindings);
1825 pg_apply_uniforms(pipeline->shader);
1827 sg_draw(start, count, instances);
1834static void pg_alloc_uniform_block(
pg_shader_t* shader,
const char* name)
1836 PICO_GFX_ASSERT(shader);
1837 PICO_GFX_ASSERT(name);
1839 size_t size = shader->internal.get_uniformblock_size(name);
1841 pg_uniform_block_t block =
1843 .slot = shader->internal.get_uniformblock_slot(name),
1844 .data = pg_arena_malloc(shader->arena, size),
1848 pg_hashtable_put(shader->uniform_blocks, name, &block);
1851static sg_primitive_type pg_map_primitive(
pg_primitive_t primitive)
1858 case PG_POINTS:
return SG_PRIMITIVETYPE_POINTS;
1859 case PG_LINES:
return SG_PRIMITIVETYPE_LINES;
1863 default: PICO_GFX_ASSERT(
false);
return SG_PRIMITIVETYPE_TRIANGLES;
1874 case PG_ZERO:
return SG_BLENDFACTOR_ZERO;
1875 case PG_ONE:
return SG_BLENDFACTOR_ONE;
1884 default: PICO_GFX_ASSERT(
false);
return SG_BLENDFACTOR_ONE;
1895 case PG_ADD:
return SG_BLENDOP_ADD;
1898 default: PICO_GFX_ASSERT(
false);
return SG_BLENDOP_ADD;
1924 default: PICO_GFX_ASSERT(
false);
return SG_VERTEXFORMAT_INVALID;
1935 default: PICO_GFX_ASSERT(
false);
return SG_USAGE_IMMUTABLE;
1939static sg_buffer_type pg_map_buffer_type(pg_buffer_type_t type)
1943 case PG_BUFFER_TYPE_VERTEX:
return SG_BUFFERTYPE_VERTEXBUFFER;
1944 case PG_BUFFER_TYPE_INDEX:
return SG_BUFFERTYPE_INDEXBUFFER;
1945 default: PICO_GFX_ASSERT(
false);
return SG_BUFFERTYPE_VERTEXBUFFER;
1949static void pg_log(
const char* fmt, ...)
1951 PICO_GFX_ASSERT(fmt);
1954 va_start(args, fmt);
1961static void pg_log_sg(
const char* tag,
1963 uint32_t log_item_id,
1964 const char* message_or_null,
1966 const char* filename_or_null,
1972 static const char* level[] =
1982 if (message_or_null && !filename_or_null)
1984 PICO_GFX_LOG(
"Tag: %s, Level: %s, Message: %s",
1985 tag, level[log_level], message_or_null);
1988 if (!message_or_null && filename_or_null)
1990 PICO_GFX_LOG(
"Tag: %s, Level: %s, File: %s, Line: %d",
1991 tag, level[log_level], filename_or_null, line_nr);
1994 if (message_or_null && filename_or_null)
1996 PICO_GFX_LOG(
"Tag: %s, Level: %s, File: %s, Line: %d, Message: %s",
1997 tag, level[log_level], filename_or_null, line_nr, message_or_null);
2010} pg_hashtable_entry_t;
2012struct pg_hashtable_t
2018 pg_hashtable_entry_t* entries;
2031static size_t pg_hashtable_compute_hash(
const pg_hashtable_t* ht,
2034static bool pg_hashtable_key_equal(
const pg_hashtable_t* ht,
2038static void pg_hashtable_copy_value(pg_hashtable_t* ht,
2039 pg_hashtable_entry_t* entry,
2042static void pg_hashtable_swap_size(
size_t* a,
size_t* b);
2043static void pg_hashtable_swap_ptr(
void** a,
void** b);
2044static void pg_hashtable_swap(pg_hashtable_t* ht1, pg_hashtable_t* ht2);
2045static void pg_hashtable_rehash(pg_hashtable_t* ht);
2051static pg_hashtable_t* pg_hashtable_new(
size_t capacity,
2056 bool power_of_two = (0 == (capacity & (capacity - 1)));
2058 PICO_GFX_ASSERT(capacity > 2 && power_of_two);
2059 PICO_GFX_ASSERT(key_size > 0);
2060 PICO_GFX_ASSERT(value_size > 0);
2062 if (capacity <= 2 || !power_of_two)
2065 if (0 == key_size || 0 == value_size)
2068 pg_hashtable_t* ht = PICO_GFX_MALLOC(
sizeof(pg_hashtable_t), mem_ctx);
2073 ht->mem_ctx = mem_ctx;
2074 ht->capacity = capacity;
2076 ht->key_size = key_size;
2077 ht->value_size = value_size;
2079 ht->entries = PICO_GFX_MALLOC(capacity *
sizeof(pg_hashtable_entry_t), mem_ctx);
2083 PICO_GFX_FREE(ht, mem_ctx);
2087 ht->keys = PICO_GFX_MALLOC(capacity * key_size, mem_ctx);
2091 PICO_GFX_FREE(ht->entries, mem_ctx);
2092 PICO_GFX_FREE(ht, mem_ctx);
2097 ht->values = PICO_GFX_MALLOC(capacity * value_size, mem_ctx);
2101 PICO_GFX_FREE(ht->entries, mem_ctx);
2102 PICO_GFX_FREE(ht->keys, mem_ctx);
2103 PICO_GFX_FREE(ht, mem_ctx);
2107 for (
size_t i = 0; i < capacity; i++)
2109 pg_hashtable_entry_t* entry = &ht->entries[i];
2111 entry->key = (
char*)ht->keys + i * key_size;
2112 entry->value = (
char*)ht->values + i * value_size;
2118static void pg_hashtable_free(pg_hashtable_t* ht)
2120 PICO_GFX_ASSERT(NULL != ht);
2122 PICO_GFX_FREE(ht->entries, ht->mem_ctx);
2123 PICO_GFX_FREE(ht->keys, ht->mem_ctx);
2124 PICO_GFX_FREE(ht->values, ht->mem_ctx);
2125 PICO_GFX_FREE(ht, ht->mem_ctx);
2128static void pg_hashtable_init_iterator(
const pg_hashtable_t* ht,
2129 pg_hashtable_iterator_t* iterator)
2131 PICO_GFX_ASSERT(NULL != ht);
2133 iterator->index = 0;
2134 iterator->count = 0;
2137static bool pg_hashtable_iterator_next(pg_hashtable_iterator_t* iterator,
2138 char** key,
void** value)
2140 PICO_GFX_ASSERT(NULL != iterator);
2142 const pg_hashtable_t* ht = iterator->ht;
2144 if (iterator->count >= ht->capacity)
2147 while (iterator->index < ht->capacity)
2149 pg_hashtable_entry_t* entry = &ht->entries[iterator->index];
2151 if (entry->hash != 0)
2157 *value = entry->value;
2171static void pg_hashtable_put(pg_hashtable_t* ht,
2175 PICO_GFX_ASSERT(NULL != ht);
2177 if (ht->size == ht->capacity)
2179 pg_hashtable_rehash(ht);
2180 PICO_GFX_ASSERT(ht->capacity > 0);
2183 pg_hash_t hash = pg_hashtable_compute_hash(ht, key);
2185 PICO_GFX_ASSERT(hash > 0);
2187 size_t start_index = hash % ht->capacity;
2188 size_t index = start_index;
2192 pg_hashtable_entry_t* entry = &ht->entries[index];
2194 if (entry->hash == hash && pg_hashtable_key_equal(ht, key, entry->key))
2196 pg_hashtable_copy_value(ht, entry, value);
2200 if (entry->hash == 0)
2204 strncpy(entry->key, key, ht->key_size);
2205 pg_hashtable_copy_value(ht, entry, value);
2212 index = (index + 1) % ht->capacity;
2214 }
while (index != start_index);
2216 start_index = index;
2217 index = (index + 1) % ht->capacity;
2219 while (index != start_index)
2221 pg_hashtable_entry_t* entry = &ht->entries[index];
2223 if (entry->hash == hash && pg_hashtable_key_equal(ht, key, entry->key))
2230 index = (index + 1) % ht->capacity;
2234static void* pg_hashtable_get(
const pg_hashtable_t* ht,
const char* key)
2236 PICO_GFX_ASSERT(NULL != ht);
2238 pg_hash_t hash = pg_hashtable_compute_hash(ht, key);
2240 PICO_GFX_ASSERT(hash > 0);
2242 size_t start_index = hash % ht->capacity;
2243 size_t index = start_index;
2247 pg_hashtable_entry_t* entry = &ht->entries[index];
2249 if (entry->hash == hash && pg_hashtable_key_equal(ht, key, entry->key))
2251 return entry->value;
2254 index = (index + 1) % ht->capacity;
2256 }
while (index != start_index);
2265static bool pg_hashtable_key_equal(
const pg_hashtable_t* ht,
2269 return 0 == strncmp(key1, key2, ht->key_size);
2272static void pg_hashtable_copy_value(pg_hashtable_t* ht,
2273 pg_hashtable_entry_t* entry,
2276 memcpy(entry->value, value, ht->value_size);
2279static void pg_hashtable_swap_size(
size_t* a,
size_t* b)
2286static void pg_hashtable_swap_ptr(
void** a,
void** b)
2293static void pg_hashtable_swap(pg_hashtable_t* ht1, pg_hashtable_t* ht2)
2295 pg_hashtable_swap_size(&ht1->capacity, &ht2->capacity);
2296 pg_hashtable_swap_size(&ht1->size, &ht2->size);
2298 pg_hashtable_swap_ptr((
void**)&ht1->entries, (
void**)&ht2->entries);
2300 pg_hashtable_swap_size(&ht1->key_size, &ht2->key_size);
2301 pg_hashtable_swap_ptr((
void**)&ht1->keys, (
void**)&ht2->keys);
2303 pg_hashtable_swap_size(&ht1->value_size, &ht2->value_size);
2304 pg_hashtable_swap_ptr(&ht1->values, &ht2->values);
2307static void pg_hashtable_rehash(pg_hashtable_t* ht)
2309 pg_hashtable_t* new_ht = pg_hashtable_new(ht->capacity * 2,
2314 pg_hashtable_iterator_t iterator;
2315 pg_hashtable_init_iterator(ht, &iterator);
2320 while (pg_hashtable_iterator_next(&iterator, &key, &value))
2322 pg_hashtable_put(new_ht, key, value);
2325 pg_hashtable_swap(ht, new_ht);
2327 pg_hashtable_free(new_ht);
2334static size_t pg_hashtable_compute_hash(
const pg_hashtable_t* ht,
const char* key)
2337#ifdef PICO_GFX_32BIT
2338 static const uint32_t offset_basis = 0x811C9DC5;
2339 static const uint32_t prime = 0x1000193;
2341 static const uint64_t offset_basis = 0xCBF29CE484222325;
2342 static const uint64_t prime = 0x100000001B3;
2345 const char* data = key;
2347 pg_hash_t hash = offset_basis;
2349 for (
size_t i = 0; i < ht->key_size; i++) {
2350 hash ^= (pg_hash_t)data[i];
2366typedef struct pg_block_t
2368 struct pg_block_t* next;
2371 unsigned char data[];
2378 pg_block_t* current;
2383pg_arena_t* pg_arena_create(
size_t block_size,
void* mem_ctx)
2385 PICO_GFX_ASSERT(block_size > 0);
2387 pg_arena_t* arena = PICO_GFX_MALLOC(
sizeof(*arena), mem_ctx);
2394 arena->first = NULL;
2395 arena->current = NULL;
2396 arena->block_size = block_size;
2397 arena->mem_ctx = mem_ctx;
2402void pg_arena_destroy(pg_arena_t* arena) {
2403 PICO_GFX_ASSERT(arena);
2410 pg_block_t* block = arena->first;
2414 pg_block_t* next = block->next;
2415 PICO_GFX_FREE(block, arena->mem_ctx);
2419 PICO_GFX_FREE(arena, arena->mem_ctx);
2422void* pg_arena_malloc(pg_arena_t* arena,
size_t size)
2424 if (!arena || size == 0)
2430 size = (size + 7) & ~7;
2433 if (arena->current && arena->current->used + size <= arena->current->size)
2435 void* ptr = arena->current->data + arena->current->used;
2436 arena->current->used += size;
2441 size_t block_size = size > arena->block_size ? size : arena->block_size;
2442 pg_block_t* block = PICO_GFX_MALLOC(
sizeof(pg_block_t) + block_size, arena->mem_ctx);
2450 block->size = block_size;
2456 arena->first = block;
2460 arena->current->next = block;
2463 arena->current = block;
2470void pg_arena_reset(pg_arena_t* arena)
2477 pg_block_t* block = arena->first;
2482 block = block->next;
2485 arena->current = arena->first;
2490#define SOKOL_GFX_IMPL
2491#include "sokol_gfx.h"
pg_backend_t
Graphics backends.
Definition pico_gfx.h:172
@ PG_BACKEND_WGPU
Definition pico_gfx.h:177
@ PG_BACKEND_D3D
Definition pico_gfx.h:175
@ PG_BACKEND_METAL
Definition pico_gfx.h:176
@ PG_BACKEND_GL
Definition pico_gfx.h:173
@ PG_BACKEND_GLES
Definition pico_gfx.h:174
pg_shader_t * pg_get_shader(const pg_pipeline_t *pipeline)
Returns the shader associated with the pipeline.
#define PG_MAX_TEXTURE_SLOTS
Definition pico_gfx.h:165
void pg_destroy_context(pg_ctx_t *ctx)
Destroys a graphics context.
struct pg_sampler_t pg_sampler_t
Represents sampler.
Definition pico_gfx.h:260
#define PG_MAX_VERTEX_ATTRIBUTES
Definition pico_gfx.h:163
pg_vertex_format_t
Vertex attribute pixel formats.
Definition pico_gfx.h:489
@ PG_VERTEX_FORMAT_INVALID
Definition pico_gfx.h:490
@ PG_VERTEX_FORMAT_BYTE4
Definition pico_gfx.h:495
@ PG_VERTEX_FORMAT_FLOAT
Definition pico_gfx.h:491
@ PG_VERTEX_FORMAT_USHORT4N
Definition pico_gfx.h:504
@ PG_VERTEX_FORMAT_FLOAT2
Definition pico_gfx.h:492
@ PG_VERTEX_FORMAT_FLOAT4
Definition pico_gfx.h:494
@ PG_VERTEX_FORMAT_HALF2
Definition pico_gfx.h:506
@ PG_VERTEX_FORMAT_SHORT2
Definition pico_gfx.h:499
@ PG_VERTEX_FORMAT_UBYTE4N
Definition pico_gfx.h:498
@ PG_VERTEX_FORMAT_UINT10_N2
Definition pico_gfx.h:505
@ PG_VERTEX_FORMAT_SHORT4
Definition pico_gfx.h:502
@ PG_VERTEX_FORMAT_USHORT2N
Definition pico_gfx.h:501
@ PG_VERTEX_FORMAT_HALF4
Definition pico_gfx.h:507
@ PG_VERTEX_FORMAT_FLOAT3
Definition pico_gfx.h:493
@ PG_VERTEX_FORMAT_UBYTE4
Definition pico_gfx.h:497
@ PG_VERTEX_FORMAT_SHORT2N
Definition pico_gfx.h:500
@ PG_VERTEX_FORMAT_BYTE4N
Definition pico_gfx.h:496
@ PG_VERTEX_FORMAT_SHORT4N
Definition pico_gfx.h:503
void pg_destroy_texture(pg_texture_t *texture)
Destroys a texture.
void pg_reset_textures(pg_shader_t *shader)
Resets the texture bindings for the current state.
pg_buffer_t * pg_create_index_buffer(pg_ctx_t *ctx, pg_buffer_usage_t usage, const void *data, size_t count, size_t max_elements)
Creates a vertex buffer.
pg_buffer_usage_t
Buffer update criteria.
Definition pico_gfx.h:656
@ PG_USAGE_STATIC
Buffer is immutable (cannot be updated)
Definition pico_gfx.h:657
@ PG_USAGE_STREAM
Buffer is updated possibly more than once per frame.
Definition pico_gfx.h:659
@ PG_USAGE_DYNAMIC
Buffer is updated on average less than once per frame.
Definition pico_gfx.h:658
void pg_draw(const pg_ctx_t *ctx, size_t start, size_t count, size_t instances)
Draws from the buffers that are bound to the current state.
void pg_end_pass(pg_ctx_t *ctx)
Ends a render pass (mandatory)
void pg_set_pipeline(pg_ctx_t *ctx, pg_pipeline_t *pipeline)
Sets the pipeline state.
int pg_get_buffer_offset(pg_buffer_t *buffer)
Returns the buffer offset.
void pg_reset_state(pg_ctx_t *ctx)
Resets the active state to defaults.
void pg_reset_buffers(pg_ctx_t *ctx)
Clears buffer bindings.
void pg_set_scissor(pg_ctx_t *ctx, int x, int y, int w, int h)
Sets the scissor state to be placed at the top of the state stack.
uint32_t pg_get_shader_id(const pg_shader_t *shader)
Returns a shader ID.
void pg_init(void)
Loads pico_gfx and sokol_gfx.
void pg_set_uniform_block(pg_shader_t *shader, const char *name, const void *data)
Sets a uniform block (UB)
void pg_reset_samplers(pg_shader_t *shader)
Resets the sampler bindings for the current state.
void pg_reset_buffer(pg_buffer_t *buffer)
Destroys and recreates buffer.
void pg_push_state(pg_ctx_t *ctx)
Pushes the active state onto the stack.
void pg_shutdown(void)
Tears down pico_gfx and sokol_gfx.
pg_shader_t * pg_create_shader_internal(pg_ctx_t *ctx, pg_shader_internal_t internal)
const pg_blend_mode_t * pg_get_blend_mode(const pg_pipeline_t *pipeline)
Returns the blend mode associated with the pipeline.
void pg_get_texture_size(const pg_texture_t *texture, int *width, int *height)
Gets a texture's dimensions.
struct pg_pipeline_t pg_pipeline_t
Render state information.
Definition pico_gfx.h:245
void pg_reset_clear_color(pg_ctx_t *ctx)
pg_texture_t * pg_create_texture(pg_ctx_t *ctx, int width, int height, const uint8_t *data, size_t size, const pg_texture_opts_t *opts)
Creates a texture from an RGBA8 image.
pg_buffer_t * pg_create_vertex_buffer(pg_ctx_t *ctx, pg_buffer_usage_t usage, const void *data, size_t count, size_t max_elements, size_t element_size)
Creates a vertex buffer.
pg_backend_t pg_backend(void)
Returns the backend in use at runtime.
void pg_set_window_size(pg_ctx_t *ctx, int width, int height, bool reset)
Sets the window dimensions.
#define PG_MAX_VERTEX_BUFFERS
Definition pico_gfx.h:164
struct pg_buffer_t pg_buffer_t
A vertex or index array buffer.
Definition pico_gfx.h:265
void pg_reset_viewport(pg_ctx_t *ctx)
void pg_reset_scissor(pg_ctx_t *ctx)
void pg_destroy_pipeline(pg_pipeline_t *pipeline)
Destroys a render pipeline.
void pg_set_clear_color(pg_ctx_t *ctx, float r, float g, float b, float a)
Sets the clear color state to be placed at the top of the state stack.
pg_sampler_t * pg_create_sampler(pg_ctx_t *ctx, const pg_sampler_opts_t *opts)
Creates a sampler represents an object that can control how shaders transform and filter texture reso...
void pg_bind_sampler(pg_shader_t *shader, const char *name, pg_sampler_t *sampler)
Binds a sampler to a slot in the current state.
void pg_flush(pg_ctx_t *ctx)
Flush commands.
void pg_set_viewport(pg_ctx_t *ctx, int x, int y, int w, int h)
Sets the viewport state to be placed at the top of the state stack.
void pg_destroy_buffer(pg_buffer_t *buffer)
Destroys a vertex or index buffer.
void pg_begin_pass(pg_ctx_t *ctx, pg_texture_t *target, bool clear)
Starts a render pass (mandatory)
struct pg_texture_t pg_texture_t
Represents an image or render target in VRAM.
Definition pico_gfx.h:255
struct pg_shader_t pg_shader_t
Vertex/fragment shader program.
Definition pico_gfx.h:250
pg_blend_factor_t
Blend factors.
Definition pico_gfx.h:197
@ PG_ONE_MINUS_SRC_COLOR
(1, 1, 1, 1) - (src.r, src.g, src.b, src.a)
Definition pico_gfx.h:202
@ PG_ONE
(1, 1, 1, 1)
Definition pico_gfx.h:200
@ PG_SRC_ALPHA
(src.a, src.a, src.a, src.a)
Definition pico_gfx.h:205
@ PG_DEFAULT_BLEND_FACTOR
Definition pico_gfx.h:198
@ PG_DST_COLOR
(dst.r, dst.g, dst.b, dst.a)
Definition pico_gfx.h:203
@ PG_ZERO
(0, 0, 0, 0)
Definition pico_gfx.h:199
@ PG_DST_ALPHA
(dst.a, dst.a, dst.a, dst.a)
Definition pico_gfx.h:207
@ PG_SRC_COLOR
(src.r, src.g, src.b, src.a)
Definition pico_gfx.h:201
@ PG_ONE_MINUS_DST_ALPHA
(1, 1, 1, 1) - (dst.a, dst.a, dst.a, dst.a)
Definition pico_gfx.h:208
@ PG_ONE_MINUS_DST_COLOR
(1, 1, 1, 1) - (dst.r, dst.g, dst.b, dst.a)
Definition pico_gfx.h:204
@ PG_ONE_MINUS_SRC_ALPHA
(1, 1, 1, 1) - (src.a, src.a, src.a, src.a)
Definition pico_gfx.h:206
void pg_reset_pipeline(pg_ctx_t *ctx)
void pg_update_texture(pg_texture_t *texture, char *data, int width, int height)
Updates a texture with the given data. This can only be called once per frame.
int pg_append_buffer(pg_buffer_t *buffer, void *data, size_t count)
Appends data to a buffer. This can happen more than once per frame, and cannot happen after an update...
pg_texture_t * pg_create_render_texture(pg_ctx_t *ctx, int width, int height, const pg_texture_opts_t *opts)
Creates a render target.
void pg_set_buffer_offset(pg_buffer_t *buffer, int offset)
Sets the buffer offset.
void pg_destroy_shader(pg_shader_t *shader)
Destroys a shader.
struct pg_ctx_t pg_ctx_t
Contains core data/state for an instance of the graphics library.
Definition pico_gfx.h:240
void pg_pop_state(pg_ctx_t *ctx)
Pops a state off the stack and makes it the active state.
void pg_get_window_size(pg_ctx_t *ctx, int *width, int *height)
Gets the window size.
void pg_bind_buffer(pg_ctx_t *ctx, int slot, pg_buffer_t *buffer)
Binds a buffer to the specified slot.
pg_pipeline_t * pg_create_pipeline(pg_ctx_t *ctx, pg_shader_t *shader, const pg_pipeline_opts_t *opts)
Creates a rendering pipeline (encapsulates render state)
pg_primitive_t
Drawing primitives.
Definition pico_gfx.h:184
@ PG_TRIANGLES
Each adjacent triple forms an individual triangle.
Definition pico_gfx.h:189
@ PG_TRIANGLE_STRIP
Array of points where every triple forms a triangle.
Definition pico_gfx.h:190
@ PG_POINTS
Array of points.
Definition pico_gfx.h:186
@ PG_LINE_STRIP
Array of points where every pair forms a lines.
Definition pico_gfx.h:188
@ PG_DEFAULT_PRIMITIVE
Definition pico_gfx.h:185
@ PG_LINES
Each adjacent pair of points forms a line.
Definition pico_gfx.h:187
void pg_update_buffer(pg_buffer_t *buffer, void *data, size_t count)
void pg_bind_texture(pg_shader_t *shader, const char *name, pg_texture_t *texture)
Binds a texture to a slot in the current state.
void pg_set_index_buffer(pg_ctx_t *ctx, pg_buffer_t *buffer)
Sets the active index buffer.
void pg_destroy_sampler(pg_sampler_t *sampler)
Destroys a sampler object.
pg_blend_eq_t
Blend equations.
Definition pico_gfx.h:215
@ PG_DEFAULT_BLEND_EQ
Definition pico_gfx.h:216
@ PG_ADD
result = src * src_factor + dst * dst_factor
Definition pico_gfx.h:217
@ PG_REVERSE_SUBTRACT
result = dst * dst_factor - src * src_factor
Definition pico_gfx.h:219
@ PG_SUBTRACT
result = src * src_factor - dst * dst_factor
Definition pico_gfx.h:218
uint32_t pg_get_texture_id(const pg_texture_t *texture)
Returns a texture ID.
pg_ctx_t * pg_create_context(int window_width, int window_height, void *mem_ctx)
Creates a graphics context.
#define PG_MAX_SAMPLER_SLOTS
Definition pico_gfx.h:166
void pg_reset_index_buffer(pg_ctx_t *ctx)
Disables indexed rednering.
Blend mode.
Definition pico_gfx.h:228
pg_blend_eq_t color_eq
Equation for blending colors.
Definition pico_gfx.h:231
pg_blend_eq_t alpha_eq
Equation for blending alpha values.
Definition pico_gfx.h:234
pg_blend_factor_t color_dst
Color dsestination blending factor.
Definition pico_gfx.h:230
pg_blend_factor_t color_src
Color source blending factor.
Definition pico_gfx.h:229
pg_blend_factor_t alpha_dst
Alpha destination blending factor.
Definition pico_gfx.h:233
pg_blend_factor_t alpha_src
Alpha source blending factor.
Definition pico_gfx.h:232
Pipeline layout.
Definition pico_gfx.h:533
pg_vertex_buf_t bufs[PG_MAX_VERTEX_BUFFERS]
Vertex buffer descriptions.
Definition pico_gfx.h:534
pg_vertex_attr_t attrs[PG_MAX_VERTEX_ATTRIBUTES]
Vertex buffer attribute definitions.
Definition pico_gfx.h:535
Pipeline creation options.
Definition pico_gfx.h:542
pg_pipeline_layout_t layout
Attribute information.
Definition pico_gfx.h:544
bool indexed
Indexed drawing.
Definition pico_gfx.h:546
pg_blend_mode_t blend
Blend mode.
Definition pico_gfx.h:548
bool blend_enabled
Enables blending.
Definition pico_gfx.h:547
bool target
Drawing to render target.
Definition pico_gfx.h:545
pg_primitive_t primitive
Rendering primitive.
Definition pico_gfx.h:543
Sampler options.
Definition pico_gfx.h:634
bool repeat_u
Repeat if true, clamp-to-edge otherwise.
Definition pico_gfx.h:636
bool smooth
Linear filtering if true, nearest otherwise.
Definition pico_gfx.h:635
bool repeat_v
Repeat if true, clamp-to-edge otherwise.
Definition pico_gfx.h:637
Definition pico_gfx.h:736
const sg_shader_desc *(* get_shader_desc)(sg_backend backend)
Definition pico_gfx.h:737
Texture creation options.
Definition pico_gfx.h:580
int mipmaps
Mipmap level.
Definition pico_gfx.h:581
Vertex attribute description.
Definition pico_gfx.h:523
int offset
Attribute offset into the vertex buffer.
Definition pico_gfx.h:526
pg_vertex_format_t format
Vertex pixel format (see above)
Definition pico_gfx.h:525
int buffer_index
The vertex buffer bind slot.
Definition pico_gfx.h:524
Vertex buffer description.
Definition pico_gfx.h:514
bool instanced
True if the buffer will be used for instanced rendering.
Definition pico_gfx.h:515
int step
The step rate (default is 1)
Definition pico_gfx.h:516