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, \
607 int width,
int height,
609 const uint8_t* data,
size_t size,
620 int width,
int height,
690 size_t element_size);
703 size_t max_elements);
752 const sg_shader_desc* (*get_shader_desc)(sg_backend backend);
753 int (*get_attr_slot)(
const char* attr_name);
754 int (*get_img_slot)(
const char* name);
755 int (*get_smp_slot)(
const char* name);
756 int (*get_uniformblock_slot)(
const char* ub_name);
757 size_t (*get_uniformblock_size)(
const char* ub_name);
768#ifdef PICO_GFX_IMPLEMENTATION
776#ifndef PICO_GFX_STACK_MAX_SIZE
777#define PICO_GFX_STACK_MAX_SIZE 16
780#ifndef PICO_GFX_HASHTABLE_KEY_SIZE
781#define PICO_GFX_HASHTABLE_KEY_SIZE 16
789 #define PICO_GFX_ASSERT(expr) ((void)0)
791 #ifndef PICO_GFX_ASSERT
793 #define PICO_GFX_ASSERT(expr) (assert(expr))
797#if !defined(PICO_GFX_MALLOC) || !defined(PICO_GFX_REALLOC) || !defined(PICO_GFX_FREE)
799#define PICO_GFX_MALLOC(size, ctx) (malloc(size))
800#define PICO_GFX_REALLOC(ptr, size, ctx) (realloc(ptr, size))
801#define PICO_GFX_FREE(ptr, ctx) (free(ptr))
806 #define PICO_GFX_LOG(...) (pg_log(__VA_ARGS__))
813static void pg_alloc_uniform_block(
pg_shader_t* shader,
const char* name);
817 PG_BUFFER_TYPE_VERTEX,
818 PG_BUFFER_TYPE_INDEX,
821static sg_primitive_type pg_map_primitive(
pg_primitive_t primitive);
827static sg_buffer_type pg_map_buffer_type(pg_buffer_type_t type);
829static void pg_log_sg(
const char* tag,
831 uint32_t log_item_id,
832 const char* message_or_null,
834 const char* filename_or_null,
837static void pg_log(
const char* fmt, ...);
844 typedef uint32_t pg_hash_t;
846 typedef uint64_t pg_hash_t;
849typedef struct pg_hashtable_t pg_hashtable_t;
850typedef struct pg_hashtable_iterator_t pg_hashtable_iterator_t;
852typedef void (*pg_hashtable_iterator_fn)(pg_hashtable_iterator_t* iterator,
856static pg_hashtable_t* pg_hashtable_new(
size_t capacity,
size_t key_size,
857 size_t value_size,
void* mem_ctx);
859static void pg_hashtable_free(pg_hashtable_t* ht);
861static void pg_hashtable_init_iterator(
const pg_hashtable_t* ht,
862 pg_hashtable_iterator_t* iterator);
864static bool pg_hashtable_iterator_next(pg_hashtable_iterator_t* iterator,
865 char** key,
void** value);
867static void pg_hashtable_put(pg_hashtable_t* ht,
871static void* pg_hashtable_get(
const pg_hashtable_t* ht,
const char* key);
873struct pg_hashtable_iterator_t
875 const pg_hashtable_t* ht;
884typedef struct pg_arena_t pg_arena_t;
886static pg_arena_t* pg_arena_create(
size_t block_size,
void* mem_ctx);
887static void* pg_arena_malloc(pg_arena_t* arena,
size_t size);
889static void pg_arena_destroy(pg_arena_t* arena);
895static void* pg_malloc(
size_t size,
void* ctx)
898 return PICO_GFX_MALLOC(size, ctx);
901static void pg_free(
void* ptr,
void* ctx)
904 PICO_GFX_FREE(ptr, ctx);
907typedef struct pg_rect_t
909 int x, y, width, height;
912typedef struct pg_state_t
914 sg_color clear_color;
926 sg_swapchain swapchain;
932 sg_pass default_pass;
934 pg_state_t state_stack[PICO_GFX_STACK_MAX_SIZE];
952 const sg_shader_desc* desc;
957 pg_hashtable_t* uniform_blocks;
975 sg_image depth_handle;
976 sg_attachments attachments;
989 pg_buffer_type_t type;
1001 .logger.func = pg_log_sg,
1004 .alloc_fn = pg_malloc,
1008 .environment.defaults.color_format = SG_PIXELFORMAT_RGBA8,
1021 if (!ctx)
return NULL;
1025 ctx->mem_ctx = mem_ctx;
1026 ctx->window_width = window_width;
1027 ctx->window_height = window_height;
1031 ctx->swapchain = (sg_swapchain)
1033 .width = window_width,
1034 .height = window_height,
1042 PICO_GFX_ASSERT(ctx);
1043 PICO_GFX_FREE(ctx, ctx->mem_ctx);
1048 #if defined (PICO_GFX_GL)
1050 #elif defined (PICO_GFX_GLES)
1052 #elif defined (PICO_GFX_D3D)
1054 #elif defined (PICO_GFX_METAL)
1056 #elif defined (PICO_GFX_WEBGPU)
1059 #error "Unknown GFX backend"
1065 ctx->swapchain.width = ctx->window_width = width;
1066 ctx->swapchain.height = ctx->window_height = height;
1078 *width = ctx->window_width;
1081 *height = ctx->window_height;
1086 PICO_GFX_ASSERT(ctx);
1087 PICO_GFX_ASSERT(!ctx->pass_active);
1089 sg_pass_action action = { 0 };
1093 sg_color color = ctx->state.clear_color;
1095 action.colors[0] = (sg_color_attachment_action)
1097 .load_action = SG_LOADACTION_CLEAR,
1098 .clear_value = color
1102 sg_pass pass = { .action = action };
1106 pass.attachments = target->attachments;
1107 ctx->target = target;
1112 pass.swapchain = ctx->swapchain;
1115 sg_begin_pass(&pass);
1120 ctx->pass_active =
true;
1127 ctx->pass_active =
false;
1138 PICO_GFX_ASSERT(ctx);
1139 PICO_GFX_ASSERT(ctx->stack_size < PICO_GFX_STACK_MAX_SIZE);
1141 ctx->state_stack[ctx->stack_size] = ctx->state;
1147 PICO_GFX_ASSERT(ctx);
1148 PICO_GFX_ASSERT(ctx->stack_size > 0);
1150 ctx->state = ctx->state_stack[ctx->stack_size - 1];
1156 PICO_GFX_ASSERT(ctx);
1157 ctx->state.clear_color = (sg_color){ r, g, b, a};
1162 PICO_GFX_ASSERT(ctx);
1168 PICO_GFX_ASSERT(ctx);
1169 ctx->state.viewport = (pg_rect_t){ x, y, w, h};
1174 PICO_GFX_ASSERT(ctx);
1189 PICO_GFX_ASSERT(ctx);
1190 ctx->state.scissor = (pg_rect_t){ x, y, w, h};
1195 PICO_GFX_ASSERT(ctx);
1204 pg_set_scissor(ctx, 0, 0, ctx->window_width, ctx->window_height);
1210 PICO_GFX_ASSERT(ctx);
1211 ctx->state.pipeline = pipeline;
1216 PICO_GFX_ASSERT(ctx);
1222 PICO_GFX_ASSERT(ctx);
1223 PICO_GFX_ASSERT(!buffer || buffer->type == PG_BUFFER_TYPE_VERTEX);
1225 PICO_GFX_ASSERT(slot >= 0);
1228 ctx->state.buffers[slot] = buffer;
1233 PICO_GFX_ASSERT(ctx);
1234 memset(&ctx->state.buffers, 0,
sizeof(ctx->state.buffers));
1239 PICO_GFX_ASSERT(ctx);
1240 PICO_GFX_ASSERT(!buffer || buffer->type == PG_BUFFER_TYPE_INDEX);
1241 ctx->state.index_buffer = buffer;
1246 PICO_GFX_ASSERT(ctx);
1247 ctx->state.index_buffer = NULL;
1252 PICO_GFX_ASSERT(shader);
1253 PICO_GFX_ASSERT(name);
1255 int slot = shader->internal.get_img_slot(name);
1257 PICO_GFX_ASSERT(slot >= 0);
1260 shader->textures[slot] = texture;
1265 PICO_GFX_ASSERT(shader);
1266 memset(shader->textures, 0,
sizeof(shader->textures));
1271 PICO_GFX_ASSERT(shader);
1272 PICO_GFX_ASSERT(name);
1274 int slot = shader->internal.get_smp_slot(name);
1276 PICO_GFX_ASSERT(slot >= 0);
1279 shader->samplers[slot] = sampler;
1284 PICO_GFX_ASSERT(shader);
1285 memset(shader->samplers, 0,
sizeof(shader->samplers));
1290 PICO_GFX_ASSERT(ctx);
1292 memset(&ctx->state, 0,
sizeof(pg_state_t));
1308 desc->layout.attrs[slot] = (sg_vertex_attr_state)
1310 .format = pg_map_vertex_format(layout->
attrs[slot].
format),
1322 int step = layout->
bufs[slot].
step;
1326 desc->layout.buffers[slot] = (sg_vertex_buffer_layout_state)
1328 .step_func = SG_VERTEXSTEP_PER_INSTANCE,
1332 desc->layout.buffers[slot].step_rate = (step >= 1) ? step : 1;
1333 desc->layout.buffers[slot].stride = layout->
bufs[slot].
stride;
1341 PICO_GFX_ASSERT(shader);
1342 PICO_GFX_ASSERT(opts);
1346 sg_pipeline_desc desc = { 0 };
1348 pg_set_attributes(&opts->
layout, &desc);
1349 pg_set_buffers(&opts->
layout, &desc);
1351 desc.primitive_type = pg_map_primitive(opts->
primitive);
1353 pipeline->blend_enabled =
false;
1357 pipeline->blend_enabled =
true;
1358 pipeline->blend_mode = opts->
blend;
1361 desc.colors[0].blend.enabled =
true;
1362 desc.colors[0].blend.src_factor_rgb = pg_map_blend_factor(blend_mode->
color_src);
1363 desc.colors[0].blend.dst_factor_rgb = pg_map_blend_factor(blend_mode->
color_dst);
1364 desc.colors[0].blend.src_factor_alpha = pg_map_blend_factor(blend_mode->
alpha_src);
1365 desc.colors[0].blend.dst_factor_alpha = pg_map_blend_factor(blend_mode->
alpha_dst);
1366 desc.colors[0].blend.op_rgb = pg_map_blend_eq(blend_mode->
color_eq);
1367 desc.colors[0].blend.op_alpha = pg_map_blend_eq(blend_mode->
alpha_eq);
1370 desc.colors[0].pixel_format = SG_PIXELFORMAT_RGBA8;
1373 desc.index_type = SG_INDEXTYPE_UINT32;
1375 desc.index_type = SG_INDEXTYPE_NONE;
1379 desc.depth.pixel_format = SG_PIXELFORMAT_DEPTH;
1380 desc.depth.write_enabled =
true;
1385 desc.face_winding = SG_FACEWINDING_CCW;
1386 desc.shader = shader->handle;
1388 pipeline->ctx = ctx;
1389 pipeline->handle = sg_make_pipeline(&desc);
1390 pipeline->indexed = opts->
indexed;
1391 pipeline->shader = shader;
1393 PICO_GFX_ASSERT(sg_query_pipeline_state(pipeline->handle) == SG_RESOURCESTATE_VALID);
1400 PICO_GFX_ASSERT(pipeline);
1401 sg_destroy_pipeline(pipeline->handle);
1402 PICO_GFX_FREE(pipeline, pipeline->ctx->mem_ctx);
1407 PICO_GFX_ASSERT(pipeline);
1408 return pipeline->shader;
1413 PICO_GFX_ASSERT(pipeline);
1415 if (pipeline->blend_enabled)
1416 return &pipeline->blend_mode;
1429 shader->internal = internal;
1432 PICO_GFX_ASSERT(shader->desc);
1434 shader->handle = sg_make_shader(shader->desc);
1436 shader->uniform_blocks = pg_hashtable_new(16, PICO_GFX_HASHTABLE_KEY_SIZE,
1437 sizeof(pg_uniform_block_t),
1440 shader->arena = pg_arena_create(512, ctx->mem_ctx);
1447 PICO_GFX_ASSERT(shader);
1448 sg_destroy_shader(shader->handle);
1449 pg_hashtable_free(shader->uniform_blocks);
1450 pg_arena_destroy(shader->arena);
1451 PICO_GFX_FREE(shader, shader->ctx->mem_ctx);
1456 PICO_GFX_ASSERT(shader);
1457 return shader->handle.id;
1464 PICO_GFX_ASSERT(shader);
1465 PICO_GFX_ASSERT(name);
1466 PICO_GFX_ASSERT(data);
1468 pg_uniform_block_t* block = pg_hashtable_get(shader->uniform_blocks, name);
1472 pg_alloc_uniform_block(shader, name);
1473 block = pg_hashtable_get(shader->uniform_blocks, name);
1476 PICO_GFX_ASSERT(block);
1478 memcpy(block->data, data, block->size);
1482 int width,
int height,
1484 const uint8_t* data,
size_t size,
1487 PICO_GFX_ASSERT(width > 0);
1488 PICO_GFX_ASSERT(height > 0);
1489 PICO_GFX_ASSERT(data);
1490 PICO_GFX_ASSERT(size > 0);
1495 PICO_GFX_ASSERT(opts->
mipmaps >= 0);
1498 texture->format = format;
1500 sg_image_desc desc = { 0 };
1502 desc.pixel_format = pg_map_pixel_format(format);
1504 desc.width = texture->width = width;
1505 desc.height = texture->height = height;
1507 desc.num_mipmaps = opts->
mipmaps;
1508 desc.data.subimage[0][0] = (sg_range){ .ptr = data, .size = size };
1511 texture->target =
false;
1512 texture->handle = sg_make_image(&desc);
1514 PICO_GFX_ASSERT(sg_query_image_state(texture->handle) == SG_RESOURCESTATE_VALID);
1520 int width,
int height,
1524 PICO_GFX_ASSERT(width > 0);
1525 PICO_GFX_ASSERT(height > 0);
1530 PICO_GFX_ASSERT(opts->
mipmaps >= 0);
1533 texture->format = format;
1535 sg_image_desc desc = { 0 };
1537 desc.render_target =
true;
1538 desc.pixel_format = pg_map_pixel_format(format);
1539 desc.width = texture->width = width;
1540 desc.height = texture->height = height;
1542 desc.num_mipmaps = opts->
mipmaps;
1545 texture->handle = sg_make_image(&desc);
1546 texture->target =
true;
1548 PICO_GFX_ASSERT(sg_query_image_state(texture->handle) == SG_RESOURCESTATE_VALID);
1550 desc.pixel_format = SG_PIXELFORMAT_DEPTH;
1551 texture->depth_handle = sg_make_image(&desc);
1553 PICO_GFX_ASSERT(sg_query_image_state(texture->depth_handle) == SG_RESOURCESTATE_VALID);
1556 texture->attachments = sg_make_attachments(&(sg_attachments_desc)
1558 .colors[0].image = texture->handle,
1559 .depth_stencil.image = texture->depth_handle,
1567 if (texture->target)
1569 sg_destroy_image(texture->depth_handle);
1572 sg_destroy_image(texture->handle);
1573 PICO_GFX_FREE(texture, texture->ctx->mem_ctx);
1579 sg_image_data img_data = { 0 };
1580 img_data.subimage[0][0].ptr = data;
1581 img_data.subimage[0][0].size = (size_t)(width * height);
1582 sg_update_image(texture->handle, &img_data);
1583 texture->width = width;
1584 texture->height = height;
1589 PICO_GFX_ASSERT(texture);
1590 return texture->handle.id;
1595 PICO_GFX_ASSERT(texture);
1598 *width = texture->width;
1601 *height = texture->height;
1611 sg_sampler_desc desc = { 0 };
1613 desc.min_filter = (opts->
smooth) ? SG_FILTER_LINEAR : SG_FILTER_NEAREST;
1614 desc.mag_filter = (opts->
smooth) ? SG_FILTER_LINEAR : SG_FILTER_NEAREST;
1616 desc.wrap_u = (opts->
repeat_u) ? SG_WRAP_REPEAT : SG_WRAP_CLAMP_TO_EDGE;
1617 desc.wrap_v = (opts->
repeat_v) ? SG_WRAP_REPEAT : SG_WRAP_CLAMP_TO_EDGE;
1620 sampler->handle = sg_make_sampler(&desc);
1627 sg_destroy_sampler(sampler->handle);
1628 PICO_GFX_FREE(sampler, sampler->ctx->mem_ctx);
1633 PICO_GFX_ASSERT(shader);
1635 pg_hashtable_iterator_t iterator;
1636 pg_hashtable_init_iterator(shader->uniform_blocks, &iterator);
1641 while (pg_hashtable_iterator_next(&iterator, &key, &value))
1643 pg_uniform_block_t* block = (pg_uniform_block_t*)value;
1645 sg_range range = { .ptr = block->data, .size = block->size };
1647 sg_apply_uniforms(block->slot, &range);
1655 size_t max_elements,
1656 size_t element_size)
1658 PICO_GFX_ASSERT(ctx);
1663 buffer->type = PG_BUFFER_TYPE_VERTEX;
1664 buffer->usage = usage;
1665 buffer->count = count;
1666 buffer->element_size = element_size;
1667 buffer->size = max_elements * element_size;
1670 buffer->handle = sg_make_buffer(&(sg_buffer_desc)
1672 .type = SG_BUFFERTYPE_VERTEXBUFFER,
1673 .usage = pg_map_usage(usage),
1674 .data = { .ptr = data, .size = count * element_size },
1675 .size = buffer->size
1678 PICO_GFX_ASSERT(sg_query_buffer_state(buffer->handle) == SG_RESOURCESTATE_VALID);
1687 size_t max_elements)
1689 PICO_GFX_ASSERT(ctx);
1694 buffer->type = PG_BUFFER_TYPE_INDEX;
1695 buffer->usage = usage;
1696 buffer->count = count;
1697 buffer->size = max_elements *
sizeof(uint32_t);
1700 buffer->handle = sg_make_buffer(&(sg_buffer_desc)
1702 .type = SG_BUFFERTYPE_INDEXBUFFER,
1703 .usage = pg_map_usage(usage),
1704 .data = { .ptr = data, .size = count *
sizeof(uint32_t) },
1705 .size = buffer->size
1708 PICO_GFX_ASSERT(sg_query_buffer_state(buffer->handle) == SG_RESOURCESTATE_VALID);
1715 PICO_GFX_ASSERT(buffer);
1716 PICO_GFX_ASSERT(data);
1717 PICO_GFX_ASSERT(count > 0);
1719 sg_update_buffer(buffer->handle, &(sg_range)
1722 .size = count * buffer->element_size
1725 buffer->count = count;
1731 PICO_GFX_ASSERT(buffer);
1732 PICO_GFX_ASSERT(data);
1733 PICO_GFX_ASSERT(count > 0);
1735 int offset = sg_append_buffer(buffer->handle, &(sg_range)
1738 .size = count * buffer->element_size
1741 buffer->count = count;
1742 buffer->offset = offset;
1749 PICO_GFX_ASSERT(buffer);
1750 return buffer->offset;
1755 PICO_GFX_ASSERT(buffer);
1756 buffer->offset = offset;
1761 PICO_GFX_ASSERT(buffer);
1763 sg_destroy_buffer(buffer->handle);
1765 buffer->handle = sg_make_buffer(&(sg_buffer_desc)
1767 .type = pg_map_buffer_type(buffer->type),
1768 .usage = pg_map_usage(buffer->usage),
1769 .data = { .ptr = NULL, .size = 0 },
1770 .size = buffer->size
1773 PICO_GFX_ASSERT(sg_query_buffer_state(buffer->handle) == SG_RESOURCESTATE_VALID);
1778 PICO_GFX_ASSERT(buffer);
1779 sg_destroy_buffer(buffer->handle);
1780 PICO_GFX_FREE(buffer, buffer->ctx->mem_ctx);
1783static void pg_apply_view_state(
const pg_ctx_t* ctx)
1785 const pg_rect_t* vp_rect = &ctx->state.viewport;
1786 sg_apply_viewport(vp_rect->x, vp_rect->y, vp_rect->width, vp_rect->height,
true);
1788 const pg_rect_t* s_rect = &ctx->state.scissor;
1789 sg_apply_scissor_rect(s_rect->x, s_rect->y, s_rect->width, s_rect->height,
true);
1792static void pg_apply_textures(
const pg_shader_t* shader, sg_bindings* bindings)
1796 if (!shader->textures[i])
1799 bindings->images[i] = shader->textures[i]->handle;
1803static void pg_apply_samplers(
const pg_shader_t* shader, sg_bindings* bindings)
1807 if (!shader->samplers[i])
1810 bindings->samplers[i] = shader->samplers[i]->handle;
1814static void pg_apply_buffers(
const pg_ctx_t* ctx, sg_bindings* bindings)
1818 for (
int slot = 0; buffers[slot] != NULL; slot++)
1820 bindings->vertex_buffer_offsets[slot] = buffers[slot]->offset;
1821 bindings->vertex_buffers[slot] = buffers[slot]->handle;
1825void pg_draw(
const pg_ctx_t* ctx,
size_t start,
size_t count,
size_t instances)
1827 PICO_GFX_ASSERT(ctx);
1828 PICO_GFX_ASSERT(ctx->pass_active);
1830 sg_bindings bindings = { 0 };
1834 pg_apply_textures(pipeline->shader, &bindings);
1835 pg_apply_samplers(pipeline->shader, &bindings);
1837 pg_apply_buffers(ctx, &bindings);
1838 pg_apply_view_state(ctx);
1840 if (ctx->state.index_buffer)
1842 bindings.index_buffer_offset = ctx->state.index_buffer->offset;
1843 bindings.index_buffer = ctx->state.index_buffer->handle;
1846 sg_apply_pipeline(pipeline->handle);
1847 sg_apply_bindings(&bindings);
1848 pg_apply_uniforms(pipeline->shader);
1850 sg_draw(start, count, instances);
1857static void pg_alloc_uniform_block(
pg_shader_t* shader,
const char* name)
1859 PICO_GFX_ASSERT(shader);
1860 PICO_GFX_ASSERT(name);
1862 size_t size = shader->internal.get_uniformblock_size(name);
1864 pg_uniform_block_t block =
1866 .slot = shader->internal.get_uniformblock_slot(name),
1867 .data = pg_arena_malloc(shader->arena, size),
1871 pg_hashtable_put(shader->uniform_blocks, name, &block);
1874static sg_primitive_type pg_map_primitive(
pg_primitive_t primitive)
1881 case PG_POINTS:
return SG_PRIMITIVETYPE_POINTS;
1882 case PG_LINES:
return SG_PRIMITIVETYPE_LINES;
1886 default: PICO_GFX_ASSERT(
false);
return SG_PRIMITIVETYPE_TRIANGLES;
1897 case PG_ZERO:
return SG_BLENDFACTOR_ZERO;
1898 case PG_ONE:
return SG_BLENDFACTOR_ONE;
1907 default: PICO_GFX_ASSERT(
false);
return SG_BLENDFACTOR_ONE;
1918 case PG_ADD:
return SG_BLENDOP_ADD;
1921 default: PICO_GFX_ASSERT(
false);
return SG_BLENDOP_ADD;
1947 default: PICO_GFX_ASSERT(
false);
return SG_VERTEXFORMAT_INVALID;
1960 default: PICO_GFX_ASSERT(
false);
return SG_PIXELFORMAT_NONE;
1971 default: PICO_GFX_ASSERT(
false);
return SG_USAGE_IMMUTABLE;
1975static sg_buffer_type pg_map_buffer_type(pg_buffer_type_t type)
1979 case PG_BUFFER_TYPE_VERTEX:
return SG_BUFFERTYPE_VERTEXBUFFER;
1980 case PG_BUFFER_TYPE_INDEX:
return SG_BUFFERTYPE_INDEXBUFFER;
1981 default: PICO_GFX_ASSERT(
false);
return SG_BUFFERTYPE_VERTEXBUFFER;
1985static void pg_log(
const char* fmt, ...)
1987 PICO_GFX_ASSERT(fmt);
1990 va_start(args, fmt);
1997static void pg_log_sg(
const char* tag,
1999 uint32_t log_item_id,
2000 const char* message_or_null,
2002 const char* filename_or_null,
2008 static const char* level[] =
2018 if (message_or_null && !filename_or_null)
2020 PICO_GFX_LOG(
"Tag: %s, Level: %s, Message: %s",
2021 tag, level[log_level], message_or_null);
2024 if (!message_or_null && filename_or_null)
2026 PICO_GFX_LOG(
"Tag: %s, Level: %s, File: %s, Line: %d",
2027 tag, level[log_level], filename_or_null, line_nr);
2030 if (message_or_null && filename_or_null)
2032 PICO_GFX_LOG(
"Tag: %s, Level: %s, File: %s, Line: %d, Message: %s",
2033 tag, level[log_level], filename_or_null, line_nr, message_or_null);
2046} pg_hashtable_entry_t;
2048struct pg_hashtable_t
2054 pg_hashtable_entry_t* entries;
2067static size_t pg_hashtable_compute_hash(
const pg_hashtable_t* ht,
2070static bool pg_hashtable_key_equal(
const pg_hashtable_t* ht,
2074static void pg_hashtable_copy_value(pg_hashtable_t* ht,
2075 pg_hashtable_entry_t* entry,
2078static void pg_hashtable_swap_size(
size_t* a,
size_t* b);
2079static void pg_hashtable_swap_ptr(
void** a,
void** b);
2080static void pg_hashtable_swap(pg_hashtable_t* ht1, pg_hashtable_t* ht2);
2081static void pg_hashtable_rehash(pg_hashtable_t* ht);
2087static pg_hashtable_t* pg_hashtable_new(
size_t capacity,
2092 bool power_of_two = (0 == (capacity & (capacity - 1)));
2094 PICO_GFX_ASSERT(capacity > 2 && power_of_two);
2095 PICO_GFX_ASSERT(key_size > 0);
2096 PICO_GFX_ASSERT(value_size > 0);
2098 if (capacity <= 2 || !power_of_two)
2101 if (0 == key_size || 0 == value_size)
2104 pg_hashtable_t* ht = PICO_GFX_MALLOC(
sizeof(pg_hashtable_t), mem_ctx);
2109 ht->mem_ctx = mem_ctx;
2110 ht->capacity = capacity;
2112 ht->key_size = key_size;
2113 ht->value_size = value_size;
2115 ht->entries = PICO_GFX_MALLOC(capacity *
sizeof(pg_hashtable_entry_t), mem_ctx);
2119 PICO_GFX_FREE(ht, mem_ctx);
2123 ht->keys = PICO_GFX_MALLOC(capacity * key_size, mem_ctx);
2127 PICO_GFX_FREE(ht->entries, mem_ctx);
2128 PICO_GFX_FREE(ht, mem_ctx);
2133 ht->values = PICO_GFX_MALLOC(capacity * value_size, mem_ctx);
2137 PICO_GFX_FREE(ht->entries, mem_ctx);
2138 PICO_GFX_FREE(ht->keys, mem_ctx);
2139 PICO_GFX_FREE(ht, mem_ctx);
2143 for (
size_t i = 0; i < capacity; i++)
2145 pg_hashtable_entry_t* entry = &ht->entries[i];
2147 entry->key = (
char*)ht->keys + i * key_size;
2148 entry->value = (
char*)ht->values + i * value_size;
2154static void pg_hashtable_free(pg_hashtable_t* ht)
2156 PICO_GFX_ASSERT(NULL != ht);
2158 PICO_GFX_FREE(ht->entries, ht->mem_ctx);
2159 PICO_GFX_FREE(ht->keys, ht->mem_ctx);
2160 PICO_GFX_FREE(ht->values, ht->mem_ctx);
2161 PICO_GFX_FREE(ht, ht->mem_ctx);
2164static void pg_hashtable_init_iterator(
const pg_hashtable_t* ht,
2165 pg_hashtable_iterator_t* iterator)
2167 PICO_GFX_ASSERT(NULL != ht);
2169 iterator->index = 0;
2170 iterator->count = 0;
2173static bool pg_hashtable_iterator_next(pg_hashtable_iterator_t* iterator,
2174 char** key,
void** value)
2176 PICO_GFX_ASSERT(NULL != iterator);
2178 const pg_hashtable_t* ht = iterator->ht;
2180 if (iterator->count >= ht->capacity)
2183 while (iterator->index < ht->capacity)
2185 pg_hashtable_entry_t* entry = &ht->entries[iterator->index];
2187 if (entry->hash != 0)
2193 *value = entry->value;
2207static void pg_hashtable_put(pg_hashtable_t* ht,
2211 PICO_GFX_ASSERT(NULL != ht);
2213 if (ht->size == ht->capacity)
2215 pg_hashtable_rehash(ht);
2216 PICO_GFX_ASSERT(ht->capacity > 0);
2219 pg_hash_t hash = pg_hashtable_compute_hash(ht, key);
2221 PICO_GFX_ASSERT(hash > 0);
2223 size_t start_index = hash % ht->capacity;
2224 size_t index = start_index;
2228 pg_hashtable_entry_t* entry = &ht->entries[index];
2230 if (entry->hash == hash && pg_hashtable_key_equal(ht, key, entry->key))
2232 pg_hashtable_copy_value(ht, entry, value);
2236 if (entry->hash == 0)
2240 strncpy(entry->key, key, ht->key_size);
2241 pg_hashtable_copy_value(ht, entry, value);
2248 index = (index + 1) % ht->capacity;
2250 }
while (index != start_index);
2252 start_index = index;
2253 index = (index + 1) % ht->capacity;
2255 while (index != start_index)
2257 pg_hashtable_entry_t* entry = &ht->entries[index];
2259 if (entry->hash == hash && pg_hashtable_key_equal(ht, key, entry->key))
2266 index = (index + 1) % ht->capacity;
2270static void* pg_hashtable_get(
const pg_hashtable_t* ht,
const char* key)
2272 PICO_GFX_ASSERT(NULL != ht);
2274 pg_hash_t hash = pg_hashtable_compute_hash(ht, key);
2276 PICO_GFX_ASSERT(hash > 0);
2278 size_t start_index = hash % ht->capacity;
2279 size_t index = start_index;
2283 pg_hashtable_entry_t* entry = &ht->entries[index];
2285 if (entry->hash == hash && pg_hashtable_key_equal(ht, key, entry->key))
2287 return entry->value;
2290 index = (index + 1) % ht->capacity;
2292 }
while (index != start_index);
2301static bool pg_hashtable_key_equal(
const pg_hashtable_t* ht,
2305 return 0 == strncmp(key1, key2, ht->key_size);
2308static void pg_hashtable_copy_value(pg_hashtable_t* ht,
2309 pg_hashtable_entry_t* entry,
2312 memcpy(entry->value, value, ht->value_size);
2315static void pg_hashtable_swap_size(
size_t* a,
size_t* b)
2322static void pg_hashtable_swap_ptr(
void** a,
void** b)
2329static void pg_hashtable_swap(pg_hashtable_t* ht1, pg_hashtable_t* ht2)
2331 pg_hashtable_swap_size(&ht1->capacity, &ht2->capacity);
2332 pg_hashtable_swap_size(&ht1->size, &ht2->size);
2334 pg_hashtable_swap_ptr((
void**)&ht1->entries, (
void**)&ht2->entries);
2336 pg_hashtable_swap_size(&ht1->key_size, &ht2->key_size);
2337 pg_hashtable_swap_ptr((
void**)&ht1->keys, (
void**)&ht2->keys);
2339 pg_hashtable_swap_size(&ht1->value_size, &ht2->value_size);
2340 pg_hashtable_swap_ptr(&ht1->values, &ht2->values);
2343static void pg_hashtable_rehash(pg_hashtable_t* ht)
2345 pg_hashtable_t* new_ht = pg_hashtable_new(ht->capacity * 2,
2350 pg_hashtable_iterator_t iterator;
2351 pg_hashtable_init_iterator(ht, &iterator);
2356 while (pg_hashtable_iterator_next(&iterator, &key, &value))
2358 pg_hashtable_put(new_ht, key, value);
2361 pg_hashtable_swap(ht, new_ht);
2363 pg_hashtable_free(new_ht);
2370static size_t pg_hashtable_compute_hash(
const pg_hashtable_t* ht,
const char* key)
2373#ifdef PICO_GFX_32BIT
2374 static const uint32_t offset_basis = 0x811C9DC5;
2375 static const uint32_t prime = 0x1000193;
2377 static const uint64_t offset_basis = 0xCBF29CE484222325;
2378 static const uint64_t prime = 0x100000001B3;
2381 const char* data = key;
2383 pg_hash_t hash = offset_basis;
2385 for (
size_t i = 0; i < ht->key_size; i++) {
2386 hash ^= (pg_hash_t)data[i];
2402typedef struct pg_block_t
2404 struct pg_block_t* next;
2407 unsigned char data[];
2414 pg_block_t* current;
2419pg_arena_t* pg_arena_create(
size_t block_size,
void* mem_ctx)
2421 PICO_GFX_ASSERT(block_size > 0);
2423 pg_arena_t* arena = PICO_GFX_MALLOC(
sizeof(*arena), mem_ctx);
2430 arena->first = NULL;
2431 arena->current = NULL;
2432 arena->block_size = block_size;
2433 arena->mem_ctx = mem_ctx;
2438void pg_arena_destroy(pg_arena_t* arena) {
2439 PICO_GFX_ASSERT(arena);
2446 pg_block_t* block = arena->first;
2450 pg_block_t* next = block->next;
2451 PICO_GFX_FREE(block, arena->mem_ctx);
2455 PICO_GFX_FREE(arena, arena->mem_ctx);
2458void* pg_arena_malloc(pg_arena_t* arena,
size_t size)
2460 if (!arena || size == 0)
2466 size = (size + 7) & ~7;
2469 if (arena->current && arena->current->used + size <= arena->current->size)
2471 void* ptr = arena->current->data + arena->current->used;
2472 arena->current->used += size;
2477 size_t block_size = size > arena->block_size ? size : arena->block_size;
2478 pg_block_t* block = PICO_GFX_MALLOC(
sizeof(pg_block_t) + block_size, arena->mem_ctx);
2486 block->size = block_size;
2492 arena->first = block;
2496 arena->current->next = block;
2499 arena->current = block;
2506void pg_arena_reset(pg_arena_t* arena)
2513 pg_block_t* block = arena->first;
2518 block = block->next;
2521 arena->current = arena->first;
2526#define SOKOL_GFX_IMPL
2527#include "sokol_gfx.h"
pg_texture_t * pg_create_texture(pg_ctx_t *ctx, int width, int height, pg_pixel_format_t format, const uint8_t *data, size_t size, const pg_texture_opts_t *opts)
Creates a texture from an RGBA8 image.
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:671
@ PG_USAGE_STATIC
Buffer is immutable (cannot be updated)
Definition pico_gfx.h:672
@ PG_USAGE_STREAM
Buffer is updated possibly more than once per frame.
Definition pico_gfx.h:674
@ PG_USAGE_DYNAMIC
Buffer is updated on average less than once per frame.
Definition pico_gfx.h:673
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.
pg_texture_t * pg_create_render_texture(pg_ctx_t *ctx, int width, int height, pg_pixel_format_t format, const pg_texture_opts_t *opts)
Creates a render target.
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_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...
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.
pg_pixel_format_t
Texture pixel formats.
Definition pico_gfx.h:514
@ PG_PIXEL_FORMAT_RGBA
Definition pico_gfx.h:517
@ PG_PIXEL_FORMAT_RED
Definition pico_gfx.h:516
@ PG_PIXEL_FORMAT_BGRA
Definition pico_gfx.h:518
@ PG_PIXEL_FORMAT_DEFAULT
Definition pico_gfx.h:515
@ PG_PIXEL_FORMAT_SRGBA
Definition pico_gfx.h:519
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:546
pg_vertex_buf_t bufs[PG_MAX_VERTEX_BUFFERS]
Vertex buffer descriptions.
Definition pico_gfx.h:547
pg_vertex_attr_t attrs[PG_MAX_VERTEX_ATTRIBUTES]
Vertex buffer attribute definitions.
Definition pico_gfx.h:548
Pipeline creation options.
Definition pico_gfx.h:555
pg_pipeline_layout_t layout
Attribute information.
Definition pico_gfx.h:557
bool indexed
Indexed drawing.
Definition pico_gfx.h:559
pg_blend_mode_t blend
Blend mode.
Definition pico_gfx.h:561
bool blend_enabled
Enables blending.
Definition pico_gfx.h:560
bool target
Drawing to render target.
Definition pico_gfx.h:558
pg_primitive_t primitive
Rendering primitive.
Definition pico_gfx.h:556
Sampler options.
Definition pico_gfx.h:649
bool repeat_u
Repeat if true, clamp-to-edge otherwise.
Definition pico_gfx.h:651
bool smooth
Linear filtering if true, nearest otherwise.
Definition pico_gfx.h:650
bool repeat_v
Repeat if true, clamp-to-edge otherwise.
Definition pico_gfx.h:652
Definition pico_gfx.h:751
const sg_shader_desc *(* get_shader_desc)(sg_backend backend)
Definition pico_gfx.h:752
Texture creation options.
Definition pico_gfx.h:593
int mipmaps
Mipmap level.
Definition pico_gfx.h:594
Vertex attribute description.
Definition pico_gfx.h:536
int offset
Attribute offset into the vertex buffer.
Definition pico_gfx.h:539
pg_vertex_format_t format
Vertex pixel format (see above)
Definition pico_gfx.h:538
int buffer_index
The vertex buffer bind slot.
Definition pico_gfx.h:537
Vertex buffer description.
Definition pico_gfx.h:526
bool instanced
True if the buffer will be used for instanced rendering.
Definition pico_gfx.h:527
int step
The step rate (default is 1)
Definition pico_gfx.h:528
int stride
Size of an element in the vertex array.
Definition pico_gfx.h:529