M42P6OZSMOI5NNVLH5BZXFA3PIDU42E4PRXAFXUUYNWSQTXFLAOQC
RLQCP6HZ5VXDNVJCYA3EXDWFFPUGYZRKGAKY7TZS4QGA5ZL4OPBAC
BEU5APLPKXWD7RKKWDR6ACTC7KIVWPV4F62OLQPLCLKPRIWBUZ2QC
4NQZS5AA733EBLXMD4RE35T37RG3CDACEBBQ37RYPDTMMH2JLMNQC
6NZ7BPIVATMXFWPLIRMTU2GQPYEWSZQ4TSIN6MW3OJWLHEYXR6KAC
7KS22PCEQW4NFNBIGVRIPLZ4VZL4W7WPNPGA7B23CYUIXZB37IBQC
Q7P6NO6DTAU3Z7JQ6HNQIQPGWPQHW37RRI5A5HDJYNC7IJCQ4XSQC
P62ZBEHGLDMT6JPMSFQBV6TFPW42JR6LNRJUV4NQZUJXPTWNYTMQC
FSOVA5GJECIC6SQYUX6IK2FGMUDBHPIDMOEAET7HAVNPHHS5UYRAC
#ifndef __GL_THIN_CPP_H__
#define __GL_THIN_CPP_H__
#include "alias/cpp.h"
#include <stdint.h>
#include "gl_thin.h"
// --------------------------------------------------------------------------------------------------------------------
#define THIN_GL_SNIPPET_REQUIRE_require(NAME) &GL_##NAME##_snippet,
#define THIN_GL_SNIPPET_REQUIRE_code(CODE)
#define THIN_GL_SNIPPET_REQUIRE_string(CODE)
#define THIN_GL_SNIPPET_REQUIRE_(ITEM) ALIAS_CPP_CAT(THIN_GL_SNIPPET_REQUIRE_, ITEM)
#define THIN_GL_SNIPPET_CODE_require(NAME)
#define THIN_GL_SNIPPET_CODE_code(CODE) #CODE
#define THIN_GL_SNIPPET_CODE_string(CODE) CODE
#define THIN_GL_SNIPPET_CODE_(ITEM) ALIAS_CPP_CAT(THIN_GL_SNIPPET_CODE_, ITEM)
#define THIN_GL_DECLARE_SNIPPET(NAME, ...) extern struct GL_ShaderSnippet GL_##NAME##_snippet;
#define THIN_GL_IMPL_SNIPPET(NAME, ...) \
struct GL_ShaderSnippet GL_##NAME##_snippet = { \
.requires = {ALIAS_CPP_EVAL(ALIAS_CPP_MAP(THIN_GL_SNIPPET_REQUIRE_, __VA_ARGS__))}, \
.code = ALIAS_CPP_EVAL(ALIAS_CPP_MAP(THIN_GL_SNIPPET_CODE_, __VA_ARGS__))};
#define THIN_GL_SNIPPET(NAME, ...) THIN_GL_IMPL_SNIPPET(NAME, __VA_ARGS__)
// --------------------------------------------------------------------------------------------------------------------
#define THIN_GL_SHADER_REQUIRE_require(NAME) &GL_##NAME##_snippet,
#define THIN_GL_SHADER_REQUIRE_code(CODE)
#define THIN_GL_SHADER_REQUIRE_string(CODE)
#define THIN_GL_SHADER_REQUIRE_main(CODE)
#define THIN_GL_SHADER_REQUIRE_(ITEM) ALIAS_CPP_CAT(THIN_GL_SHADER_REQUIRE_, ITEM)
#define THIN_GL_SHADER_CODE_require(NAME)
#define THIN_GL_SHADER_CODE_code(CODE) #CODE
#define THIN_GL_SHADER_CODE_string(CODE) CODE
#define THIN_GL_SHADER_CODE_main(CODE) "void main() {" #CODE "}"
#define THIN_GL_SHADER_CODE_(ITEM) ALIAS_CPP_CAT(THIN_GL_SHADER_CODE_, ITEM)
#define THIN_GL_SHADER(NAME, ...) \
static struct GL_Shader NAME##_shader = { \
.requires = {ALIAS_CPP_EVAL(ALIAS_CPP_MAP(THIN_GL_SHADER_REQUIRE_, __VA_ARGS__))}, \
.code = ALIAS_CPP_EVAL(ALIAS_CPP_MAP(THIN_GL_SHADER_CODE_, __VA_ARGS__))};
// --------------------------------------------------------------------------------------------------------------------
#define THIN_GL_ALIGNED(X) __attribute__((aligned(X)))
#define THIN_GL_STRUCT_TO_C_require(NAME)
#define THIN_GL_STRUCT_TO_C_unorm8(NAME) uint8_t NAME[4] THIN_GL_ALIGNED(4); // uint (4, 4) -> float
#define THIN_GL_STRUCT_TO_C_unorm8x2(NAME) uint8_t NAME[4] THIN_GL_ALIGNED(4); // uint (4, 4) -> vec2
#define THIN_GL_STRUCT_TO_C_unorm8x3(NAME) uint8_t NAME[4] THIN_GL_ALIGNED(4); // uint (4, 4) -> vec3
#define THIN_GL_STRUCT_TO_C_unorm8x4(NAME) uint8_t NAME[4] THIN_GL_ALIGNED(4); // uint (4, 4) -> vec4
#define THIN_GL_STRUCT_TO_C_unorm16(NAME) uint16_t NAME[2] THIN_GL_ALIGNED(4); // uint (4, 4) -> float
#define THIN_GL_STRUCT_TO_C_unorm16x2(NAME) uint16_t NAME[2] THIN_GL_ALIGNED(4); // uint (4, 4) -> vec2
#define THIN_GL_STRUCT_TO_C_unorm16x3(NAME) uint16_t NAME[4] THIN_GL_ALIGNED(8); // uvec2 (8, 8) -> vec3
#define THIN_GL_STRUCT_TO_C_unorm16x4(NAME) uint16_t NAME[4] THIN_GL_ALIGNED(8); // uvec2 (8, 8) -> vec4
#define THIN_GL_STRUCT_TO_C_snorm16(NAME) int16_t NAME[2] THIN_GL_ALIGNED(4); // uint (4, 4) -> float
#define THIN_GL_STRUCT_TO_C_snorm16x2(NAME) int16_t NAME[2] THIN_GL_ALIGNED(4); // uint (4, 4) -> vec2
#define THIN_GL_STRUCT_TO_C_snorm16x3(NAME) int16_t NAME[4] THIN_GL_ALIGNED(8); // uvec2 (8, 8) -> vec3
#define THIN_GL_STRUCT_TO_C_snorm16x4(NAME) int16_t NAME[4] THIN_GL_ALIGNED(8); // uvec2 (8, 8) -> vec4
#define THIN_GL_STRUCT_TO_C_uint32(NAME) uint32_t NAME THIN_GL_ALIGNED(4); // uint (4, 4) -> uint
#define THIN_GL_STRUCT_TO_C_int32(NAME) int32_t NAME THIN_GL_ALIGNED(4); // int (4, 4) -> int
#define THIN_GL_STRUCT_TO_C_float32(NAME) float NAME THIN_GL_ALIGNED(4); // float (4, 4) -> float
#define THIN_GL_STRUCT_TO_C_float32x2(NAME) float NAME[2] THIN_GL_ALIGNED(8); // vec2 (8, 8) -> vec2
#define THIN_GL_STRUCT_TO_C_float32x3(NAME) float NAME[3] THIN_GL_ALIGNED(16); // vec3 (16, 16) -> vec3
#define THIN_GL_STRUCT_TO_C_float32x4(NAME) float NAME[4] THIN_GL_ALIGNED(16); // vec4 (16, 16) -> vec4
#define THIN_GL_STRUCT_TO_C_struct(TYPE, NAME) struct GL_##TYPE NAME;
#define THIN_GL_STRUCT_TO_C_unsized_array(TYPE)
#define THIN_GL_STRUCT_TO_C_(ITEM) ALIAS_CPP_CAT(THIN_GL_STRUCT_TO_C_, ITEM)
#define THIN_GL_STRUCT_TO_C(NAME, ...) \
struct GL_##NAME { \
ALIAS_CPP_EVAL(ALIAS_CPP_MAP(THIN_GL_STRUCT_TO_C_, __VA_ARGS__)) \
};
#define THIN_GL_STRUCT_TO_GLSL_PACKED_require(NAME) "//"
#define THIN_GL_STRUCT_TO_GLSL_PACKED_unorm8(NAME) "uint " #NAME
#define THIN_GL_STRUCT_TO_GLSL_PACKED_unorm8x2(NAME) "uint " #NAME
#define THIN_GL_STRUCT_TO_GLSL_PACKED_unorm8x3(NAME) "uint " #NAME
#define THIN_GL_STRUCT_TO_GLSL_PACKED_unorm8x4(NAME) "uint " #NAME
#define THIN_GL_STRUCT_TO_GLSL_PACKED_unorm16(NAME) "uint " #NAME
#define THIN_GL_STRUCT_TO_GLSL_PACKED_unorm16x2(NAME) "uint " #NAME
#define THIN_GL_STRUCT_TO_GLSL_PACKED_unorm16x3(NAME) "uvec2 " #NAME
#define THIN_GL_STRUCT_TO_GLSL_PACKED_unorm16x4(NAME) "uvec2 " #NAME
#define THIN_GL_STRUCT_TO_GLSL_PACKED_snorm16(NAME) "uint " #NAME
#define THIN_GL_STRUCT_TO_GLSL_PACKED_snorm16x2(NAME) "uint " #NAME
#define THIN_GL_STRUCT_TO_GLSL_PACKED_snorm16x3(NAME) "uvec2 " #NAME
#define THIN_GL_STRUCT_TO_GLSL_PACKED_snorm16x4(NAME) "uvec2 " #NAME
#define THIN_GL_STRUCT_TO_GLSL_PACKED_uint32(NAME) "uint " #NAME
#define THIN_GL_STRUCT_TO_GLSL_PACKED_int32(NAME) "int " #NAME
#define THIN_GL_STRUCT_TO_GLSL_PACKED_float32(NAME) "float " #NAME
#define THIN_GL_STRUCT_TO_GLSL_PACKED_float32x2(NAME) "vec2 " #NAME
#define THIN_GL_STRUCT_TO_GLSL_PACKED_float32x3(NAME) "vec3 " #NAME
#define THIN_GL_STRUCT_TO_GLSL_PACKED_float32x4(NAME) "vec4 " #NAME
#define THIN_GL_STRUCT_TO_GLSL_PACKED_struct(TYPE, NAME) #TYPE "Packed " #NAME
#define THIN_GL_STRUCT_TO_GLSL_PACKED_(ITEM) " " ALIAS_CPP_CAT(THIN_GL_STRUCT_TO_GLSL_PACKED_, ITEM) ";\n"
#define THIN_GL_STRUCT_TO_GLSL_UNPACKED_require(NAME) "//"
#define THIN_GL_STRUCT_TO_GLSL_UNPACKED_unorm8(NAME) "float " #NAME
#define THIN_GL_STRUCT_TO_GLSL_UNPACKED_unorm8x2(NAME) "vec2 " #NAME
#define THIN_GL_STRUCT_TO_GLSL_UNPACKED_unorm8x3(NAME) "vec3 " #NAME
#define THIN_GL_STRUCT_TO_GLSL_UNPACKED_unorm8x4(NAME) "vec4 " #NAME
#define THIN_GL_STRUCT_TO_GLSL_UNPACKED_unorm16(NAME) "float " #NAME
#define THIN_GL_STRUCT_TO_GLSL_UNPACKED_unorm16x2(NAME) "vec2 " #NAME
#define THIN_GL_STRUCT_TO_GLSL_UNPACKED_unorm16x3(NAME) "vec3 " #NAME
#define THIN_GL_STRUCT_TO_GLSL_UNPACKED_unorm16x4(NAME) "vec4 " #NAME
#define THIN_GL_STRUCT_TO_GLSL_UNPACKED_snorm16(NAME) "float " #NAME
#define THIN_GL_STRUCT_TO_GLSL_UNPACKED_snorm16x2(NAME) "vec2 " #NAME
#define THIN_GL_STRUCT_TO_GLSL_UNPACKED_snorm16x3(NAME) "vec3 " #NAME
#define THIN_GL_STRUCT_TO_GLSL_UNPACKED_snorm16x4(NAME) "vec4 " #NAME
#define THIN_GL_STRUCT_TO_GLSL_UNPACKED_uint32(NAME) "uint " #NAME
#define THIN_GL_STRUCT_TO_GLSL_UNPACKED_int32(NAME) "int " #NAME
#define THIN_GL_STRUCT_TO_GLSL_UNPACKED_float32(NAME) "float " #NAME
#define THIN_GL_STRUCT_TO_GLSL_UNPACKED_float32x2(NAME) "vec2 " #NAME
#define THIN_GL_STRUCT_TO_GLSL_UNPACKED_float32x3(NAME) "vec3 " #NAME
#define THIN_GL_STRUCT_TO_GLSL_UNPACKED_float32x4(NAME) "vec4 " #NAME
#define THIN_GL_STRUCT_TO_GLSL_UNPACKED_struct(TYPE, NAME) #TYPE " " #NAME
#define THIN_GL_STRUCT_TO_GLSL_UNPACKED_(ITEM) " " ALIAS_CPP_CAT(THIN_GL_STRUCT_TO_GLSL_UNPACKED_, ITEM) ";\n"
#define THIN_GL_STRUCT_TO_GLSL_PACK_require(NAME) "//"
#define THIN_GL_STRUCT_TO_GLSL_PACK_unorm8(NAME) "packUnorm4x8(vec4(unpack." #NAME ", 0, 0, 0))"
#define THIN_GL_STRUCT_TO_GLSL_PACK_unorm8x2(NAME) "packUnorm4x8(vec4(unpack." #NAME ", 0, 0))"
#define THIN_GL_STRUCT_TO_GLSL_PACK_unorm8x3(NAME) "packUnorm4x8(vec4(unpack." #NAME ", 0))"
#define THIN_GL_STRUCT_TO_GLSL_PACK_unorm8x4(NAME) "packUnorm4x8(unpack." #NAME ")"
#define THIN_GL_STRUCT_TO_GLSL_PACK_unorm16(NAME) "packUnorm2x16(vec2(unpack." #NAME ", 0))"
#define THIN_GL_STRUCT_TO_GLSL_PACK_unorm16x2(NAME) "packUnorm2x16(unpack." #NAME ")"
#define THIN_GL_STRUCT_TO_GLSL_PACK_unorm16x3(NAME) \
"uvec2(packUnorm2x16(unpack." #NAME ".xy), packUnorm2x16(vec2(unpack." #NAME ".z, 0)))"
#define THIN_GL_STRUCT_TO_GLSL_PACK_unorm16x4(NAME) \
"uvec2(packUnorm2x16(unpack." #NAME ".xy), packUnorm2x16(unpack." #NAME ".zw))"
#define THIN_GL_STRUCT_TO_GLSL_PACK_snorm16(NAME) "packSnorm2x16(vec2(unpack." #NAME ", 0))"
#define THIN_GL_STRUCT_TO_GLSL_PACK_snorm16x2(NAME) "packSnorm2x16(unpack." #NAME ")"
#define THIN_GL_STRUCT_TO_GLSL_PACK_snorm16x3(NAME) \
"uvec2(packSnorm2x16(unpack." #NAME ".xy), packSnorm2x16(vec2(unpack." #NAME ".z, 0)))"
#define THIN_GL_STRUCT_TO_GLSL_PACK_snorm16x4(NAME) \
"uvec2(packSnorm2x16(unpack." #NAME ".xy), packSnorm2x16(unpack." #NAME ".zw))"
#define THIN_GL_STRUCT_TO_GLSL_PACK_uint32(NAME) "unpack." #NAME
#define THIN_GL_STRUCT_TO_GLSL_PACK_int32(NAME) "unpack." #NAME
#define THIN_GL_STRUCT_TO_GLSL_PACK_float32(NAME) "unpack." #NAME
#define THIN_GL_STRUCT_TO_GLSL_PACK_float32x2(NAME) "unpack." #NAME
#define THIN_GL_STRUCT_TO_GLSL_PACK_float32x3(NAME) "unpack." #NAME
#define THIN_GL_STRUCT_TO_GLSL_PACK_float32x4(NAME) "unpack." #NAME
#define THIN_GL_STRUCT_TO_GLSL_PACK_struct(TYPE, NAME) #TYPE "_pack(unpack." #NAME ")"
#define THIN_GL_STRUCT_TO_GLSL_PACK_(ITEM) ",\n " ALIAS_CPP_CAT(THIN_GL_STRUCT_TO_GLSL_PACK_, ITEM)
#define THIN_GL_STRUCT_TO_GLSL_UNPACK_require(NAME) "//"
#define THIN_GL_STRUCT_TO_GLSL_UNPACK_unorm8(NAME) "unpackUnorm4x8(pack." #NAME ").x"
#define THIN_GL_STRUCT_TO_GLSL_UNPACK_unorm8x2(NAME) "unpackUnorm4x8(pack." #NAME ").xy"
#define THIN_GL_STRUCT_TO_GLSL_UNPACK_unorm8x3(NAME) "unpackUnorm4x8(pack." #NAME ").xyz"
#define THIN_GL_STRUCT_TO_GLSL_UNPACK_unorm8x4(NAME) "unpackUnorm4x8(pack." #NAME ")"
#define THIN_GL_STRUCT_TO_GLSL_UNPACK_unorm16(NAME) "unpackUnorm2x16(pack." #NAME ").x"
#define THIN_GL_STRUCT_TO_GLSL_UNPACK_unorm16x2(NAME) "unpackUnorm2x16(pack." #NAME ")"
#define THIN_GL_STRUCT_TO_GLSL_UNPACK_unorm16x3(NAME) \
"vec3(unpackUnorm2x16(pack." #NAME ".x), unpackUnorm2x16(pack." #NAME ".y).x)"
#define THIN_GL_STRUCT_TO_GLSL_UNPACK_unorm16x4(NAME) \
"vec4(unpackUnorm2x16(pack." #NAME ".x), unpackUnorm2x16(pack." #NAME ".y))"
#define THIN_GL_STRUCT_TO_GLSL_UNPACK_snorm16(NAME) "unpackSnorm2x16(pack." #NAME ")"
#define THIN_GL_STRUCT_TO_GLSL_UNPACK_snorm16x2(NAME) "unpackSnorm2x16(pack." #NAME ")"
#define THIN_GL_STRUCT_TO_GLSL_UNPACK_snorm16x3(NAME) \
"vec3(unpackSnorm2x16(pack." #NAME ".x), unpackSnorm2x16(pack." #NAME ".y).x)"
#define THIN_GL_STRUCT_TO_GLSL_UNPACK_snorm16x4(NAME) \
"vec4(unpackSnorm2x16(pack." #NAME ".x), unpackSnorm2x16(pack." #NAME ".y))"
#define THIN_GL_STRUCT_TO_GLSL_UNPACK_uint32(NAME) "pack." #NAME
#define THIN_GL_STRUCT_TO_GLSL_UNPACK_int32(NAME) "pack." #NAME
#define THIN_GL_STRUCT_TO_GLSL_UNPACK_float32(NAME) "pack." #NAME
#define THIN_GL_STRUCT_TO_GLSL_UNPACK_float32x2(NAME) "pack." #NAME
#define THIN_GL_STRUCT_TO_GLSL_UNPACK_float32x3(NAME) "pack." #NAME
#define THIN_GL_STRUCT_TO_GLSL_UNPACK_float32x4(NAME) "pack." #NAME
#define THIN_GL_STRUCT_TO_GLSL_UNPACK_struct(TYPE, NAME) #TYPE "_unpack(pack." #NAME ")"
#define THIN_GL_STRUCT_TO_GLSL_UNPACK_(ITEM) ",\n " ALIAS_CPP_CAT(THIN_GL_STRUCT_TO_GLSL_UNPACK_, ITEM)
// clang-format off
#define THIN_GL_STRUCT_TO_GLSL(NAME, ...) \
static const char GL_##NAME##_glsl[] = \
"struct " #NAME " {\n" ALIAS_CPP_EVAL(ALIAS_CPP_MAP(THIN_GL_STRUCT_TO_GLSL_UNPACKED_, __VA_ARGS__)) "};\n" \
"struct " #NAME "Packed {\n" ALIAS_CPP_EVAL(ALIAS_CPP_MAP(THIN_GL_STRUCT_TO_GLSL_PACKED_, __VA_ARGS__)) "};\n" \
#NAME "Packed " #NAME "_pack(in " #NAME " unpack) {\n" \
" return " #NAME "Packed(//" \
ALIAS_CPP_EVAL(ALIAS_CPP_MAP(THIN_GL_STRUCT_TO_GLSL_PACK_, __VA_ARGS__)) \
" );\n" \
"}\n" \
#NAME " " #NAME "_unpack(in " #NAME "Packed pack) {\n" \
" return " #NAME "(//" \
ALIAS_CPP_EVAL(ALIAS_CPP_MAP(THIN_GL_STRUCT_TO_GLSL_UNPACK_, __VA_ARGS__)) \
" );\n" \
"}\n";
// clang-format on
#define THIN_GL_STRUCT_TO_DESC_require(NAME) &GL_##NAME##_snippet,
#define THIN_GL_STRUCT_TO_DESC_unorm8(NAME)
#define THIN_GL_STRUCT_TO_DESC_unorm8x2(NAME)
#define THIN_GL_STRUCT_TO_DESC_unorm8x3(NAME)
#define THIN_GL_STRUCT_TO_DESC_unorm8x4(NAME)
#define THIN_GL_STRUCT_TO_DESC_unorm16(NAME)
#define THIN_GL_STRUCT_TO_DESC_unorm16x2(NAME)
#define THIN_GL_STRUCT_TO_DESC_unorm16x3(NAME)
#define THIN_GL_STRUCT_TO_DESC_unorm16x4(NAME)
#define THIN_GL_STRUCT_TO_DESC_snorm16(NAME)
#define THIN_GL_STRUCT_TO_DESC_snorm16x2(NAME)
#define THIN_GL_STRUCT_TO_DESC_snorm16x3(NAME)
#define THIN_GL_STRUCT_TO_DESC_snorm16x4(NAME)
#define THIN_GL_STRUCT_TO_DESC_uint32(NAME)
#define THIN_GL_STRUCT_TO_DESC_int32(NAME)
#define THIN_GL_STRUCT_TO_DESC_float32(NAME)
#define THIN_GL_STRUCT_TO_DESC_float32x2(NAME)
#define THIN_GL_STRUCT_TO_DESC_float32x3(NAME)
#define THIN_GL_STRUCT_TO_DESC_float32x4(NAME)
#define THIN_GL_STRUCT_TO_DESC_struct(TYPE, NAME)
#define THIN_GL_STRUCT_TO_DESC_unsized_array(TYPE)
#define THIN_GL_STRUCT_TO_DESC_(ITEM) ALIAS_CPP_CAT(THIN_GL_STRUCT_TO_DESC_, ITEM)
#define THIN_GL_STRUCT_TO_DESC(NAME, ...) \
struct GL_ShaderSnippet GL_##NAME##_snippet = { \
.requires = {ALIAS_CPP_EVAL(ALIAS_CPP_MAP(THIN_GL_STRUCT_TO_DESC_, __VA_ARGS__)) NULL}, \
.code = GL_##NAME##_glsl, \
.structure_size = sizeof(struct GL_##NAME)};
#define THIN_GL_DECLARE_STRUCT(NAME, ...) \
THIN_GL_STRUCT_TO_C(NAME, __VA_ARGS__) \
extern struct GL_ShaderSnippet GL_##NAME##_snippet;
#define THIN_GL_IMPL_STRUCT(NAME, ...) \
THIN_GL_STRUCT_TO_GLSL(NAME, __VA_ARGS__) \
THIN_GL_STRUCT_TO_DESC(NAME, __VA_ARGS__)
#define THIN_GL_STRUCT(NAME, ...) \
THIN_GL_STRUCT_TO_C(NAME, __VA_ARGS__) \
THIN_GL_STRUCT_TO_GLSL(NAME, __VA_ARGS__) \
THIN_GL_STRUCT_TO_DESC(NAME, __VA_ARGS__)
THIN_GL_DECLARE_STRUCT(DrawArraysIndirectCommand, uint32(count), uint32(instance_count), uint32(first),
uint32(base_instance))
THIN_GL_DECLARE_STRUCT(DrawElementsIndirectCommand, uint32(count), uint32(instance_count), uint32(first_index),
uint32(base_vertex), uint32(base_instance))
THIN_GL_DECLARE_STRUCT(DispatchIndirectCommand, uint32(num_groups_x), uint32(num_groups_y), uint32(num_groups_z))
#define THIN_GL_BLOCK_TO_C(NAME, ...) THIN_GL_STRUCT_TO_C(NAME, __VA_ARGS__)
#define THIN_GL_BLOCK_TO_DESC(NAME, ...) THIN_GL_STRUCT_TO_DESC(NAME, __VA_ARGS__)
#define THIN_GL_CAT(A, ...) THIN_GL_CAT_(A, ##__VA_ARGS__)
#define THIN_GL_CAT_(A, ...) A##__VA_ARGS__
#define THIN_GL_BLOCK_TO_GLSL_require(NAME) " //"
#define THIN_GL_BLOCK_TO_GLSL_uint32(NAME) " uint " #NAME
#define THIN_GL_BLOCK_TO_GLSL_int32(NAME) " int " #NAME
#define THIN_GL_BLOCK_TO_GLSL_float32(NAME) " float " #NAME
#define THIN_GL_BLOCK_TO_GLSL_float32x2(NAME) " vec2 " #NAME
#define THIN_GL_BLOCK_TO_GLSL_float32x3(NAME) " vec3 " #NAME
#define THIN_GL_BLOCK_TO_GLSL_float32x4(NAME) " vec4 " #NAME
#define THIN_GL_BLOCK_TO_GLSL_struct(TYPE, NAME) " " #TYPE " " #NAME
#define THIN_GL_BLOCK_TO_GLSL_unsized_array(TYPE) THIN_GL_CAT(THIN_GL_BLOCK_TO_GLSL_, TYPE) "[]"
#define THIN_GL_BLOCK_TO_GLSL_(ITEM) ALIAS_CPP_CAT(THIN_GL_BLOCK_TO_GLSL_, ITEM) ";\n"
#define THIN_GL_BLOCK_TO_GLSL(NAME, ...) \
static const char GL_##NAME##_glsl[] = \
"buffer " #NAME " {\n" ALIAS_CPP_EVAL(ALIAS_CPP_MAP(THIN_GL_BLOCK_TO_GLSL_, __VA_ARGS__)) "} ";
#define THIN_GL_DECLARE_BLOCK(NAME, ...) \
THIN_GL_BLOCK_TO_C(NAME, __VA_ARGS__) \
extern struct GL_ShaderSnippet GL_##NAME##_snippet;
#define THIN_GL_IMPL_BLOCK(NAME, ...) \
THIN_GL_BLOCK_TO_GLSL(NAME, __VA_ARGS__) \
THIN_GL_BLOCK_TO_DESC(NAME, __VA_ARGS__)
#define THIN_GL_BLOCK(NAME, ...) \
THIN_GL_BLOCK_TO_C(NAME, __VA_ARGS__) \
THIN_GL_BLOCK_TO_GLSL(NAME, __VA_ARGS__) \
THIN_GL_BLOCK_TO_DESC(NAME, __VA_ARGS__)
#endif
.flags = 0 ALIAS_CPP_EVAL(ALIAS_CPP_MAP(THIN_GL_SHADER_FLAGS_, __VA_ARGS__)), \
#define THIN_GL_SHADER_CODE_flag(NAME)
#define THIN_GL_SHADER_REQUIRE_flag(NAME)
#define THIN_GL_SHADER_FLAGS_require(NAME)
#define THIN_GL_SHADER_FLAGS_flag(NAME) | THIN_GL_SHADER_FLAG_ ## NAME
#define THIN_GL_SHADER_FLAGS_code(CODE)
#define THIN_GL_SHADER_FLAGS_string(CODE)
#define THIN_GL_SHADER_FLAGS_main(CODE)
#define THIN_GL_SHADER_FLAGS_(ITEM) ALIAS_CPP_CAT(THIN_GL_SHADER_FLAGS_, ITEM)
.flags = 0 ALIAS_CPP_EVAL(ALIAS_CPP_MAP(THIN_GL_SNIPPET_FLAGS_, __VA_ARGS__)), \
#define THIN_GL_SNIPPET_CODE_flag(NAME)
#define THIN_GL_SNIPPET_REQUIRE_flag(NAME)
#define THIN_GL_SNIPPET_FLAGS_require(NAME)
#define THIN_GL_SNIPPET_FLAGS_flag(NAME) | THIN_GL_SHADER_FLAG_ ## NAME
#define THIN_GL_SNIPPET_FLAGS_code(CODE)
#define THIN_GL_SNIPPET_FLAGS_string(CODE)
#define THIN_GL_SNIPPET_FLAGS_(ITEM) ALIAS_CPP_CAT(THIN_GL_SNIPPET_FLAGS_, ITEM)
#ifndef __GL_THIN_H__
#define __GL_THIN_H__
#include "glad.h"
#include <alias/memory.h>
#include <alias/math.h>
#include <stdbool.h>
#define THIN_GL_MAX_ATTRIBUTES 16
#define THIN_GL_MAX_BINDINGS 2
#define THIN_GL_MAX_UNIFORMS 16
#define THIN_GL_MAX_IMAGES 16
#define THIN_GL_MAX_BUFFERS 16
#define THIN_GL_VERTEX_BIT 0x01
#define THIN_GL_GEOMETRY_BIT 0x02
#define THIN_GL_TESSC_BIT 0x04
#define THIN_GL_TESSE_BIT 0x08
#define THIN_GL_FRAGMENT_BIT 0x10
#define THIN_GL_LOCAL_GROUP_SIZE_SUBGROUP_SIZE 0xFFFFFFFF
typedef void (*GL_VoidFn)(void);
// --------------------------------------------------------------------------------------------------------------------
// C to OpenGL data format
enum GL_Type {
GL_Type_Unused,
GL_Type_Float,
GL_Type_Float2,
GL_Type_Float3,
GL_Type_Float4,
GL_Type_Double,
GL_Type_Double2,
GL_Type_Double3,
GL_Type_Double4,
GL_Type_Int,
GL_Type_Int2,
GL_Type_Int3,
GL_Type_Int4,
GL_Type_Uint,
GL_Type_Uint2,
GL_Type_Uint3,
GL_Type_Uint4,
GL_Type_Bool,
GL_Type_Bool2,
GL_Type_Bool3,
GL_Type_Bool4,
GL_Type_Float2x2,
GL_Type_Float3x3,
GL_Type_Float4x4,
GL_Type_Float2x3,
GL_Type_Float2x4,
GL_Type_Float3x2,
GL_Type_Float3x4,
GL_Type_Float4x2,
GL_Type_Float4x3,
GL_Type_Double2x2,
GL_Type_Double3x3,
GL_Type_Double4x4,
GL_Type_Double2x3,
GL_Type_Double2x4,
GL_Type_Double3x2,
GL_Type_Double3x4,
GL_Type_Double4x2,
GL_Type_Double4x3,
GL_Type_Sampler1D,
GL_Type_Sampler2D,
GL_Type_Sampler3D,
GL_Type_SamplerCube,
GL_Type_Sampler1DShadow,
GL_Type_Sampler2DShadow,
GL_Type_Sampler1DArray,
GL_Type_Sampler2DArray,
GL_Type_SamplerCubeArray,
GL_Type_Sampler1DArrayShadow,
GL_Type_Sampler2DArrayShadow,
GL_Type_Sampler2DMultisample,
GL_Type_Sampler2DMultisampleArray,
GL_Type_SamplerCubeShadow,
GL_Type_SamplerCubeArrayShadow,
GL_Type_SamplerBuffer,
GL_Type_Sampler2DRect,
GL_Type_Sampler2DRectShadow,
GL_Type_IntSampler1D,
GL_Type_IntSampler2D,
GL_Type_IntSampler3D,
GL_Type_IntSamplerCube,
GL_Type_IntSampler1DArray,
GL_Type_IntSampler2DArray,
GL_Type_IntSamplerCubeMapArray,
GL_Type_IntSampler2DMultisample,
GL_Type_IntSampler2DMultisampleArray,
GL_Type_IntSamplerBuffer,
GL_Type_IntSampler2DRect,
GL_Type_UintSampler1D,
GL_Type_UintSampler2D,
GL_Type_UintSampler3D,
GL_Type_UintSamplerCube,
GL_Type_UintSampler1DArray,
GL_Type_UintSampler2DArray,
GL_Type_UintSamplerCubeMapArray,
GL_Type_UintSampler2DMultisample,
GL_Type_UintSampler2DMultisampleArray,
GL_Type_UintSamplerBuffer,
GL_Type_UintSampler2DRect,
GL_Type_Image1D,
GL_Type_Image2D,
GL_Type_Image3D,
GL_Type_Image2DRect,
GL_Type_ImageCube,
GL_Type_ImageBuffer,
GL_Type_Image1DArray,
GL_Type_Image2DArray,
GL_Type_ImageCubeArray,
GL_Type_Image2DMultisample,
GL_Type_Image2DMultisampleArray,
GL_Type_IntImage1D,
GL_Type_IntImage2D,
GL_Type_IntImage3D,
GL_Type_IntImage2DRect,
GL_Type_IntImageCube,
GL_Type_IntImageBuffer,
GL_Type_IntImage1DArray,
GL_Type_IntImage2DArray,
GL_Type_IntImageCubeArray,
GL_Type_IntImage2DMultisample,
GL_Type_IntImage2DMultisampleArray,
GL_Type_UintImage1D,
GL_Type_UintImage2D,
GL_Type_UintImage3D,
GL_Type_UintImage2DRect,
GL_Type_UintImageCube,
GL_Type_UintImageBuffer,
GL_Type_UintImage1DArray,
GL_Type_UintImage2DArray,
GL_Type_UintImageCubeArray,
GL_Type_UintImage2DMultisample,
GL_Type_UintImage2DMultisampleArray,
GL_Type_AtomicUint,
GL_Type_InlineStructure, // valid in THIN_GL_STRUCT and THIN_GL_BLOCK
GL_Type_ShaderStorageBuffer
};
struct GL_UniformData {
const void *pointer;
GLboolean transpose;
const struct GL_Buffer *buffer;
union {
float _float;
float vec[4];
float mat[16];
GLint _int;
GLint ivec[4];
GLint imat[16];
GLuint uint;
GLuint uvec[4];
GLuint umat[16];
};
};
struct GL_ShaderSnippet {
const struct GL_ShaderSnippet *requires[8];
const char *code;
/* internal */
uint32_t structure_size;
GLuint emit_index;
};
struct GL_Shader {
const struct GL_ShaderSnippet *requires[8];
const char *code;
/* internal */
GLuint object;
};
struct GL_ShaderResource {
enum GL_Type type;
const char *name;
GLsizei count;
union {
struct {
GL_VoidFn prepare;
uint32_t prepare_draw_index;
struct GL_UniformData data;
} uniform;
struct {
struct GL_ShaderSnippet *snippet;
union {
struct GL_Buffer *buffer;
struct GL_Buffer *buffers[THIN_GL_MAX_BUFFERS];
};
} block;
};
};
// --------------------------------------------------------------------------------------------------------------------
// state setup for draw/compute
// - interface defined in C ensures GLSL and C expect the same thing
#define THIN_GL_PIPILINE_STATE_FIELDS \
struct { \
GLbitfield stage_bits; \
enum GL_Type type; \
const char *name; \
GLsizei count; \
const struct GL_ShaderSnippet *struture; \
} uniform[THIN_GL_MAX_UNIFORMS]; \
struct { \
GLbitfield stage_bits; \
struct GL_ShaderResource *resource; \
} global[THIN_GL_MAX_UNIFORMS]; \
struct { \
GLbitfield stage_bits; \
enum GL_Type type; \
const char *name; \
} image[THIN_GL_MAX_IMAGES]; \
/* internal */ \
GLuint program_object;
struct GL_PipelineState {
THIN_GL_PIPILINE_STATE_FIELDS
};
#define THIN_GL_STAGE_FIELDS \
const char *source; \
/* internal */ \
GLuint shader_object;
struct GL_VertexStage {
THIN_GL_STAGE_FIELDS
GLenum primitive;
struct {
GLuint binding;
alias_memory_Format format;
GLint size;
const GLchar *name;
GLuint offset;
} attribute[THIN_GL_MAX_ATTRIBUTES];
struct {
GLsizei stride;
GLuint divisor;
} binding[THIN_GL_MAX_BINDINGS];
// internal
GLuint vertex_array_object;
};
struct GL_DrawState {
THIN_GL_PIPILINE_STATE_FIELDS
GLenum primitive;
struct {
GLuint binding;
alias_memory_Format format;
GLint size;
const GLchar *name;
GLuint offset;
} attribute[THIN_GL_MAX_ATTRIBUTES];
struct {
GLsizei stride;
GLuint divisor;
} binding[THIN_GL_MAX_BINDINGS];
const struct GL_Shader *vertex_shader;
bool depth_test_enable;
bool depth_mask;
float depth_range_min;
float depth_range_max;
const struct GL_Shader *fragment_shader;
bool blend_enable;
GLenum blend_src_factor;
GLenum blend_dst_factor;
/* internal */
GLuint vertex_shader_object;
GLuint fragment_shader_object;
GLuint vertex_array_object;
};
struct GL_ComputeState {
THIN_GL_PIPILINE_STATE_FIELDS
const struct GL_Shader *shader;
GLuint local_group_x;
GLuint local_group_y;
GLuint local_group_z;
/* internal */
GLuint shader_object;
};
// --------------------------------------------------------------------------------------------------------------------
// asset
struct GL_Buffer {
enum {
GL_Buffer_Static, // never changes, lives on the GPU
GL_Buffer_Temporary, // The buffer used to send information from the CPU to GPU once
GL_Buffer_GPU, // only lives on the GPU
GL_Buffer_CPU, // A buffer persantly mapped and bound, updated by the CPU many times
} kind;
GLuint buffer;
GLsizei size;
void *mapping;
GLintptr offset;
bool dirty;
};
// --------------------------------------------------------------------------------------------------------------------
// asset reference collection needed for a draw/compute
#define THIN_GL_PIPILINE_ASSETS_FIELDS \
GLuint image[THIN_GL_MAX_IMAGES]; \
struct GL_UniformData uniforms[THIN_GL_MAX_UNIFORMS];
struct GL_PipelineAssets {
THIN_GL_PIPILINE_ASSETS_FIELDS
};
struct GL_DrawAssets {
THIN_GL_PIPILINE_ASSETS_FIELDS
const struct GL_Buffer *element_buffer;
uint32_t element_buffer_offset;
const struct GL_Buffer *vertex_buffers[THIN_GL_MAX_BINDINGS];
};
struct GL_ComputeAssets {
THIN_GL_PIPILINE_ASSETS_FIELDS
};
// --------------------------------------------------------------------------------------------------------------------
// draw
void GL_initialize_draw_state(const struct GL_DrawState *state);
GLbitfield GL_apply_draw_state(const struct GL_DrawState *state);
GLbitfield GL_apply_draw_assets(const struct GL_DrawState *state, const struct GL_DrawAssets *assets);
void GL_draw_arrays(const struct GL_DrawState *state, const struct GL_DrawAssets *assets, GLint first, GLsizei count,
GLsizei instancecount, GLuint baseinstance);
void GL_draw_elements(const struct GL_DrawState *state, const struct GL_DrawAssets *assets, GLsizei count,
GLsizei instancecount, GLint basevertex, GLuint baseinstance);
void GL_draw_elements_indirect(const struct GL_DrawState *state, const struct GL_DrawAssets *assets,
const struct GL_Buffer *indirect, GLsizei indirect_offset);
// --------------------------------------------------------------------------------------------------------------------
// compute
void GL_initialize_compute_state(const struct GL_ComputeState *state);
GLbitfield GL_apply_compute_state(const struct GL_ComputeState *state);
GLbitfield GL_apply_compute_assets(const struct GL_ComputeState *state, const struct GL_ComputeAssets *assets);
void GL_compute(const struct GL_ComputeState *state, const struct GL_ComputeAssets *assets, GLuint num_groups_x,
GLuint num_groups_y, GLuint num_groups_z);
void GL_compute_indirect(const struct GL_ComputeState *state, const struct GL_ComputeAssets *assets,
const struct GL_Buffer *indirect, GLsizei indirect_offset);
// --------------------------------------------------------------------------------------------------------------------
// resource data
struct GL_Buffer GL_allocate_static_buffer(GLenum type, GLsizei size, const void *data);
struct GL_Buffer GL_allocate_temporary_buffer(GLenum type, GLsizei size);
struct GL_Buffer GL_allocate_temporary_buffer_from(GLenum type, GLsizei size, const void *data);
void *GL_update_buffer_begin(const struct GL_Buffer *buffer, GLintptr offset, GLsizei size);
void GL_update_buffer_end(const struct GL_Buffer *buffer, GLintptr offset, GLsizei size);
GLbitfield GL_flush_buffer(const struct GL_Buffer *buffer, GLbitfield read_barrier_bits);
void GL_free_buffer(const struct GL_Buffer *buffer);
void GL_reset_temporary_buffers(void);
void GL_temporary_buffer_stats(GLenum type, uint32_t *total_allocated, uint32_t *used);
void GL_destroy_buffer(const struct GL_Buffer *buffer);
// --------------------------------------------------------------------------------------------------------------------
// resource
void GL_ShaderResource_prepare(const struct GL_ShaderResource *resource);
// mimic OpenGL's matrix
static inline void GL_matrix_construct(float xx, float yx, float zx, float wx, float xy, float yy, float zy, float wy,
float xz, float yz, float zz, float wz, float xw, float yw, float zw, float ww,
float result[16]) {
result[0] = xx;
result[1] = xy;
result[2] = xz;
result[3] = xw;
result[4] = yx;
result[5] = yy;
result[6] = yz;
result[7] = yw;
result[8] = zx;
result[9] = zy;
result[10] = zz;
result[11] = zw;
result[12] = wx;
result[13] = wy;
result[14] = wz;
result[15] = ww;
}
static inline void GL_matrix_identity(float result[16]) {
// clang-format off
GL_matrix_construct(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
result
);
// clang-format on
}
static inline void GL_matrix_translation(float x, float y, float z, float result[16]) {
// clang-format off
GL_matrix_construct(
1, 0, 0, x,
0, 1, 0, y,
0, 0, 1, z,
0, 0, 0, 1,
result
);
// clang-format on
}
static inline void GL_matrix_rotation(float angle, float x, float y, float z, float result[16]) {
double magnitude = sqrt(x * x + y * y + z * z);
if(magnitude < alias_R_MIN) {
GL_matrix_identity(result);
return;
}
double one_over_magnitude = 1.0 / magnitude;
double a = angle * 0.01745329251;
x *= one_over_magnitude;
y *= one_over_magnitude;
z *= one_over_magnitude;
double s = sin(a);
double c = cos(a);
double one_minus_c = 1.0 - c;
double xs = x * s;
double ys = y * s;
double zs = z * s;
double xc = x * one_minus_c;
double yc = y * one_minus_c;
double zc = z * one_minus_c;
double m_xx = (xc * x) + c;
double m_xy = (xc * y) + zs;
double m_xz = (xc * z) - ys;
double m_yx = (yc * x) - zs;
double m_yy = (yc * y) + c;
double m_yz = (yc * z) + xs;
double m_zx = (zc * x) + ys;
double m_zy = (zc * y) - xs;
double m_zz = (zc * z) + c;
// clang-format off
GL_matrix_construct(
m_xx, m_yx, m_zx, 0,
m_xy, m_yy, m_zy, 0,
m_xz, m_yz, m_zz, 0,
0, 0, 0, 1,
result
);
// clang-format on
}
static inline void GL_matrix_rotation_x(float angle, float result[16]) {
float a = angle * 0.01745329251;
float s = sin(a);
float c = cos(a);
// clang-format off
GL_matrix_construct(
1, 0, 0, 0,
0, c, -s, 0,
0, s, c, 0,
0, 0, 0, 1,
result
);
// clang-format on
}
static inline void GL_matrix_rotation_y(float angle, float result[16]) {
float a = angle * 0.01745329251;
float s = sin(a);
float c = cos(a);
// clang-format off
GL_matrix_construct(
c, 0, s, 0,
0, 1, 0, 0,
-s, 0, c, 0,
0, 0, 0, 1,
result
);
// clang-format on
}
static inline void GL_matrix_rotation_z(float angle, float result[16]) {
float a = angle * 0.01745329251;
float s = sin(a);
float c = cos(a);
// clang-format off
GL_matrix_construct(
c, -s, 0, 0,
s, c, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
result
);
// clang-format on
}
static inline void GL_matrix_frustum(float left, float right, float bottom, float top, float near, float far,
float result[16]) {
float x = (2 * near) / (right - left);
float y = (2 * near) / (top - bottom);
float a = (right + left) / (right - left);
float b = (top + bottom) / (top - bottom);
float c = -(far + near) / (far - near);
float d = -(2 * far * near) / (far - near);
// clang-format off
GL_matrix_construct(
x, 0, a, 0,
0, y, b, 0,
0, 0, c, d,
0, 0, -1, 0,
result
);
// clang-format on
}
static inline void GL_matrix_ortho(float left, float right, float bottom, float top, float near, float far,
float result[16]) {
float x = 2 / (right - left);
float y = 2 / (top - bottom);
float z = -2 / (far - near);
float a = -(right + left) / (right - left);
float b = -(top + bottom) / (top - bottom);
float c = -(far + near) / (far - near);
// clang-format off
GL_matrix_construct(
x, 0, 0, a,
0, y, 0, b,
0, 0, z, c,
0, 0, 0, 1,
result
);
// clang-format on
}
static inline void GL_matrix_multiply(const float a[16], const float b[16], float result[16]) {
float m[16];
for(uint32_t i = 0; i < 4; i++) {
float row[4] = {a[0 + i], a[4 + i], a[8 + i], a[12 + i]};
// clang-format off
m[ 0 + i] = row[0] * b[ 0 + 0] + row[1] * b[ 0 + 1] + row[2] * b[ 0 + 2] + row[3] * b[ 0 + 3];
m[ 4 + i] = row[0] * b[ 4 + 0] + row[1] * b[ 4 + 1] + row[2] * b[ 4 + 2] + row[3] * b[ 4 + 3];
m[ 8 + i] = row[0] * b[ 8 + 0] + row[1] * b[ 8 + 1] + row[2] * b[ 8 + 2] + row[3] * b[ 8 + 3];
m[12 + i] = row[0] * b[12 + 0] + row[1] * b[12 + 1] + row[2] * b[12 + 2] + row[3] * b[12 + 3];
// clang-format on
}
alias_memory_copy(result, sizeof(float) * 16, m, sizeof(float) * 16);
}
static inline void GL_translate(float matrix[16], float x, float y, float z) {
float temp[16];
GL_matrix_translation(x, y, z, temp);
GL_matrix_multiply(matrix, temp, matrix);
}
static inline void GL_rotate(float matrix[16], float angle, float x, float y, float z) {
float temp[16];
GL_matrix_rotation(angle, x, y, z, temp);
GL_matrix_multiply(matrix, temp, matrix);
}
static inline void GL_rotate_x(float matrix[16], float angle) {
float temp[16];
GL_matrix_rotation_x(angle, temp);
GL_matrix_multiply(matrix, temp, matrix);
}
static inline void GL_rotate_y(float matrix[16], float angle) {
float temp[16];
GL_matrix_rotation_y(angle, temp);
GL_matrix_multiply(matrix, temp, matrix);
}
static inline void GL_rotate_z(float matrix[16], float angle) {
float temp[16];
GL_matrix_rotation_z(angle, temp);
GL_matrix_multiply(matrix, temp, matrix);
}
#endif
uint32_t flags;
uint32_t flags;
#define THIN_GL_SHADER_FLAG_SUBGROUP_ARITHMETIC 0x00000001
#define THIN_GL_SHADER_FLAG_ARITHMETIC_INT64 0x00000002
#include "gl_thin_cpp.h"
#include "gl_local.h"
THIN_GL_IMPL_STRUCT(DrawArraysIndirectCommand, uint32(count), uint32(instance_count), uint32(first),
uint32(base_instance))
THIN_GL_IMPL_STRUCT(DrawElementsIndirectCommand, uint32(count), uint32(instance_count), uint32(first_index),
uint32(base_vertex), uint32(base_instance))
THIN_GL_IMPL_STRUCT(DispatchIndirectCommand, uint32(num_groups_x), uint32(num_groups_y), uint32(num_groups_z))
struct GL_TypeInfo {
const char *name;
GLenum target;
};
static struct GL_TypeInfo type_info[] = {
[GL_Type_Float] = {"float"},
[GL_Type_Float2] = {"vec2"},
[GL_Type_Float3] = {"vec3"},
[GL_Type_Float4] = {"vec4"},
[GL_Type_Int] = {"int"},
[GL_Type_Int2] = {"ivec2"},
[GL_Type_Int3] = {"ivec3"},
[GL_Type_Int4] = {"ivec4"},
[GL_Type_Uint] = {"uint"},
[GL_Type_Uint2] = {"uvec2"},
[GL_Type_Uint3] = {"uvec3"},
[GL_Type_Uint4] = {"uvec4"},
[GL_Type_Float2x2] = {"mat2"},
[GL_Type_Float3x3] = {"mat3"},
[GL_Type_Float4x4] = {"mat4"},
[GL_Type_Float2x3] = {"mat2x3"},
[GL_Type_Float3x2] = {"mat3x2"},
[GL_Type_Float2x4] = {"mat2x4"},
[GL_Type_Float4x2] = {"mat4x2"},
[GL_Type_Float3x4] = {"mat3x4"},
[GL_Type_Float4x3] = {"mat4x3"},
[GL_Type_Sampler1D] =
{
.name = "sampler1D",
.target = GL_TEXTURE_1D,
},
[GL_Type_Image1D] =
{
.name = "image1D",
.target = GL_TEXTURE_1D,
},
[GL_Type_Sampler1DShadow] =
{
.name = "sampler1DShadow",
.target = GL_TEXTURE_1D_ARRAY,
},
[GL_Type_Sampler1DArray] =
{
.name = "sampler1DArray",
.target = GL_TEXTURE_1D_ARRAY,
},
[GL_Type_Sampler1DArrayShadow] =
{
.name = "sampler1DArrayShadow",
.target = GL_TEXTURE_1D_ARRAY,
},
[GL_Type_Sampler2D] =
{
.name = "sampler2D",
.target = GL_TEXTURE_2D,
},
};
struct TemporaryBuffer {
GLuint buffer;
GLenum type;
GLsizei size;
GLsizei offset;
void *mapped_memory;
};
static struct {
uint32_t num_temporary_buffers;
struct TemporaryBuffer *temporary_buffers;
char *script_builder_ptr;
uint32_t script_builder_cap;
GLint script_builder_len;
uint32_t draw_index;
uint32_t emit_index;
} _ = {0, 0, 0, 0};
static void script_builder_init(void) {
_.script_builder_len = 0;
_.emit_index++;
}
static void script_builder_add(const char *format, ...) {
va_list ap;
va_start(ap, format);
uint32_t len = vsprintf(NULL, 0, format, ap);
va_end(ap);
if(_.script_builder_len + len + 1 > _.script_builder_cap) {
_.script_builder_cap = _.script_builder_len + len + 2;
_.script_builder_cap += _.script_builder_cap >> 1;
_.script_builder_ptr = realloc(_.script_builder_ptr, sizeof(*_.script_builder_ptr) * _.script_builder_cap);
}
va_start(ap, format);
vsprintf(_.script_builder_ptr + _.script_builder_len, _.script_builder_cap - _.script_builder_len, format, ap);
_.script_builder_len += len;
_.script_builder_ptr[_.script_builder_len] = 0;
va_end(ap);
}
static void script_builder_add_shader(const struct GL_ShaderSnippet *shader);
static void script_builder_add_shader_requisites(const struct GL_ShaderSnippet *shader) {
for(uint32_t i = 0; i < 8; i++) {
if(shader->requires[i] == NULL)
break;
script_builder_add_shader(shader->requires[i]);
}
}
static void script_builder_add_shader(const struct GL_ShaderSnippet *shader) {
if(shader->emit_index == _.emit_index)
return;
script_builder_add_shader_requisites(shader);
script_builder_add("%s\n", shader->code);
*(uint32_t *)(&shader->emit_index) = _.emit_index;
}
static void script_builder_add_vertex_format(const struct GL_DrawState *draw_state) {
for(int i = 0; i < THIN_GL_MAX_ATTRIBUTES; i++) {
if(draw_state->attribute[i].format == 0)
break;
script_builder_add("layout(location=%i) in ", i);
const char *type_name, *vec_name;
switch(draw_state->attribute[i].format) {
case alias_memory_Format_Uint8:
case alias_memory_Format_Uint16:
case alias_memory_Format_Uint32:
case alias_memory_Format_Uint64:
type_name = "uint";
vec_name = "uvec";
break;
case alias_memory_Format_Sint8:
case alias_memory_Format_Sint16:
case alias_memory_Format_Sint32:
case alias_memory_Format_Sint64:
type_name = "int";
vec_name = "ivec";
break;
case alias_memory_Format_Unorm8:
case alias_memory_Format_Unorm16:
case alias_memory_Format_Snorm8:
case alias_memory_Format_Snorm16:
case alias_memory_Format_Uscaled8:
case alias_memory_Format_Uscaled16:
case alias_memory_Format_Sscaled8:
case alias_memory_Format_Sscaled16:
case alias_memory_Format_Urgb8:
case alias_memory_Format_Float32:
type_name = "float";
vec_name = "vec";
break;
case alias_memory_Format_Float16:
type_name = "half_float";
vec_name = "hvec";
break;
case alias_memory_Format_Float64:
type_name = "double";
vec_name = "dvec";
break;
default:
// TODO error
break;
}
if(draw_state->attribute[i].size > 1) {
script_builder_add("%s%i in_%s;\n", vec_name, draw_state->attribute[i].size, draw_state->attribute[i].name);
} else {
script_builder_add("%s in_%s;\n", type_name, draw_state->attribute[i].name);
}
}
}
static void script_builder_add_uniform_format(const struct GL_PipelineState *pipeline_state, GLbitfield stage_bit) {
GLuint uniform_location = 0;
GLuint shader_storage_buffer_binding = 0;
GLuint location, binding;
for(uint32_t i = 0; i < THIN_GL_MAX_UNIFORMS; i++) {
if((stage_bit && !pipeline_state->uniform[i].stage_bits) || pipeline_state->uniform[i].type == GL_Type_Unused)
continue;
GLuint location = uniform_location++;
if((pipeline_state->uniform[i].stage_bits & stage_bit) != stage_bit)
continue;
script_builder_add("layout(location=%i) uniform %s u_%s;\n", location,
type_info[pipeline_state->uniform[i].type].name, pipeline_state->uniform[i].name);
}
for(uint32_t i = 0; i < THIN_GL_MAX_UNIFORMS; i++) {
if((stage_bit && !pipeline_state->global[i].stage_bits) || pipeline_state->global[i].resource == NULL)
continue;
uint32_t count = alias_max(pipeline_state->global[i].resource->count, 1);
if(pipeline_state->global[i].resource->type == GL_Type_ShaderStorageBuffer) {
binding = shader_storage_buffer_binding;
shader_storage_buffer_binding += count;
} else {
location = uniform_location++;
}
if((pipeline_state->global[i].stage_bits & stage_bit) != stage_bit)
continue;
if(pipeline_state->global[i].resource->type == GL_Type_ShaderStorageBuffer) {
script_builder_add_shader_requisites(pipeline_state->global[i].resource->block.snippet);
script_builder_add("layout(std430, binding=%i) %s u_%s", binding,
pipeline_state->global[i].resource->block.snippet->code,
pipeline_state->global[i].resource->name);
} else {
script_builder_add("layout(location=%i) uniform %s u_%s", location,
type_info[pipeline_state->global[i].resource->type].name,
pipeline_state->global[i].resource->name);
}
if(count > 1) {
script_builder_add("[%i];\n", count);
} else {
script_builder_add(";\n");
}
}
}
static void script_builder_add_images_format(const struct GL_PipelineState *pipeline_state, GLbitfield stage_bit) {
for(uint32_t i = 0; i < THIN_GL_MAX_IMAGES; i++) {
if(!(pipeline_state->image[i].stage_bits & stage_bit))
continue;
script_builder_add("layout(binding=%i) uniform %s u_%s;\n", i, type_info[pipeline_state->image[i].type].name,
pipeline_state->image[i].name);
}
}
void gl_compileShader(GLuint shader) {
glCompileShader(shader);
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if(status != GL_TRUE) {
GLint length;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
GLchar *info_log = malloc(length + 1);
glGetShaderInfoLog(shader, length + 1, NULL, info_log);
Com_Error(ERR_FATAL, "shader compile error: %s", info_log);
free(info_log);
}
}
void gl_linkProgram(GLuint program) {
glLinkProgram(program);
GLint status;
glGetProgramiv(program, GL_LINK_STATUS, &status);
if(status != GL_TRUE) {
GLint length = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
GLchar *info_log = malloc(length + 1);
glGetProgramInfoLog(program, length + 1, NULL, info_log);
Com_Error(ERR_FATAL, "program link error: %s", info_log);
free(info_log);
}
}
void glProgram_init(struct glProgram *prog, const char *vsource, const char *fsource) {
GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(vertex_shader, 1, &vsource, NULL);
glShaderSource(fragment_shader, 1, &fsource, NULL);
gl_compileShader(vertex_shader);
gl_compileShader(fragment_shader);
GLuint program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
gl_linkProgram(program);
prog->vertex_shader = vertex_shader;
prog->fragment_shader = fragment_shader;
prog->program = program;
}
void GL_initialize_draw_state(const struct GL_DrawState *state) {
if(state->vertex_shader != NULL && state->vertex_shader_object == 0) {
script_builder_init();
script_builder_add_prelude((const struct GL_ShaderSnippet *)state->vertex_shader);
script_builder_add_vertex_format(state);
script_builder_add_uniform_format((const struct GL_PipelineState *)state, THIN_GL_VERTEX_BIT);
script_builder_add_images_format((const struct GL_PipelineState *)state, THIN_GL_VERTEX_BIT);
script_builder_add_shader_requisites((const struct GL_ShaderSnippet *)state->vertex_shader);
script_builder_add("%s", state->vertex_shader->code);
GLuint shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(shader, 1, (const char *const *)&_.script_builder_ptr, &_.script_builder_len);
gl_compileShader(shader);
*(GLuint *)(&state->vertex_shader_object) = shader;
}
if(state->fragment_shader != NULL && state->fragment_shader_object == 0) {
script_builder_init();
script_builder_add_prelude((const struct GL_ShaderSnippet *)state->fragment_shader);
script_builder_add_uniform_format((const struct GL_PipelineState *)state, THIN_GL_FRAGMENT_BIT);
script_builder_add_images_format((const struct GL_PipelineState *)state, THIN_GL_FRAGMENT_BIT);
script_builder_add_shader_requisites((const struct GL_ShaderSnippet *)state->fragment_shader);
script_builder_add("%s", state->fragment_shader->code);
GLuint shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(shader, 1, (const char *const *)&_.script_builder_ptr, &_.script_builder_len);
gl_compileShader(shader);
*(GLuint *)(&state->fragment_shader_object) = shader;
}
if(state->vertex_shader_object != 0 && state->fragment_shader_object != 0 && state->program_object == 0) {
GLuint program = glCreateProgram();
glAttachShader(program, state->vertex_shader_object);
glAttachShader(program, state->fragment_shader_object);
gl_linkProgram(program);
*(GLuint *)(&state->program_object) = program;
}
if(state->attribute[0].format != 0 && state->vertex_array_object == 0) {
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
for(int i = 0; i < THIN_GL_MAX_ATTRIBUTES; i++) {
if(state->attribute[i].format == 0)
break;
glEnableVertexArrayAttrib(vao, i);
switch(state->attribute[i].format) {
case alias_memory_Format_Uint8:
glVertexArrayAttribIFormat(vao, i, state->attribute[i].size, GL_UNSIGNED_BYTE, state->attribute[i].offset);
break;
case alias_memory_Format_Uint16:
glVertexArrayAttribIFormat(vao, i, state->attribute[i].size, GL_UNSIGNED_SHORT, state->attribute[i].offset);
break;
case alias_memory_Format_Uint32:
glVertexArrayAttribIFormat(vao, i, state->attribute[i].size, GL_UNSIGNED_INT, state->attribute[i].offset);
break;
case alias_memory_Format_Uint64:
//
break;
case alias_memory_Format_Sint8:
glVertexArrayAttribIFormat(vao, i, state->attribute[i].size, GL_BYTE, state->attribute[i].offset);
break;
case alias_memory_Format_Sint16:
glVertexArrayAttribIFormat(vao, i, state->attribute[i].size, GL_SHORT, state->attribute[i].offset);
break;
case alias_memory_Format_Sint32:
glVertexArrayAttribIFormat(vao, i, state->attribute[i].size, GL_INT, state->attribute[i].offset);
break;
case alias_memory_Format_Sint64:
//
break;
case alias_memory_Format_Unorm8:
glVertexArrayAttribFormat(vao, i, state->attribute[i].size, GL_UNSIGNED_BYTE, GL_TRUE,
state->attribute[i].offset);
break;
case alias_memory_Format_Unorm16:
glVertexArrayAttribFormat(vao, i, state->attribute[i].size, GL_UNSIGNED_SHORT, GL_TRUE,
state->attribute[i].offset);
break;
case alias_memory_Format_Snorm8:
glVertexArrayAttribFormat(vao, i, state->attribute[i].size, GL_BYTE, GL_TRUE, state->attribute[i].offset);
break;
case alias_memory_Format_Snorm16:
glVertexArrayAttribFormat(vao, i, state->attribute[i].size, GL_SHORT, GL_TRUE, state->attribute[i].offset);
break;
case alias_memory_Format_Uscaled8:
glVertexArrayAttribFormat(vao, i, state->attribute[i].size, GL_UNSIGNED_BYTE, GL_FALSE,
state->attribute[i].offset);
break;
case alias_memory_Format_Uscaled16:
glVertexArrayAttribFormat(vao, i, state->attribute[i].size, GL_UNSIGNED_SHORT, GL_FALSE,
state->attribute[i].offset);
break;
case alias_memory_Format_Sscaled8:
glVertexArrayAttribFormat(vao, i, state->attribute[i].size, GL_BYTE, GL_FALSE, state->attribute[i].offset);
break;
case alias_memory_Format_Sscaled16:
glVertexArrayAttribFormat(vao, i, state->attribute[i].size, GL_SHORT, GL_FALSE, state->attribute[i].offset);
break;
case alias_memory_Format_Urgb8:
//
break;
case alias_memory_Format_Float16:
glVertexArrayAttribFormat(vao, i, state->attribute[i].size, GL_HALF_FLOAT, GL_FALSE,
state->attribute[i].offset);
break;
case alias_memory_Format_Float32:
glVertexArrayAttribFormat(vao, i, state->attribute[i].size, GL_FLOAT, GL_FALSE, state->attribute[i].offset);
break;
case alias_memory_Format_Float64:
glVertexArrayAttribLFormat(vao, i, state->attribute[i].size, GL_DOUBLE, state->attribute[i].offset);
break;
default:
// TODO error
break;
}
glVertexArrayAttribBinding(vao, i, state->attribute[i].binding);
}
*(GLuint *)(&state->vertex_array_object) = vao;
}
}
static GLbitfield apply_pipeline_state(const struct GL_PipelineState *state) {
static struct GL_PipelineState current_pipeline_state;
if(current_pipeline_state.program_object != state->program_object) {
glUseProgram(state->program_object);
current_pipeline_state.program_object = state->program_object;
}
return 0;
}
GLbitfield GL_apply_draw_state(const struct GL_DrawState *state) {
static struct GL_DrawState current_draw_state;
GLbitfield barriers = apply_pipeline_state((const struct GL_PipelineState *)state);
if(current_draw_state.vertex_array_object != state->vertex_array_object) {
glBindVertexArray(state->vertex_array_object);
current_draw_state.vertex_array_object = state->vertex_array_object;
}
if(current_draw_state.depth_test_enable != state->depth_test_enable) {
if(state->depth_test_enable) {
glEnable(GL_DEPTH_TEST);
current_draw_state.depth_test_enable = true;
} else {
glDisable(GL_DEPTH_TEST);
current_draw_state.depth_test_enable = false;
}
}
if(current_draw_state.depth_mask != state->depth_mask) {
if(state->depth_mask) {
glDepthMask(GL_TRUE);
current_draw_state.depth_mask = true;
} else {
glDepthMask(GL_FALSE);
current_draw_state.depth_mask = false;
}
}
if(current_draw_state.depth_range_min != state->depth_range_min ||
current_draw_state.depth_range_max != state->depth_range_max) {
glDepthRange(state->depth_range_min, state->depth_range_max);
current_draw_state.depth_range_min = state->depth_range_min;
current_draw_state.depth_range_max = state->depth_range_max;
}
if(state->blend_enable) {
if(!current_draw_state.blend_enable || current_draw_state.blend_src_factor != state->blend_src_factor ||
current_draw_state.blend_dst_factor != state->blend_dst_factor) {
glEnable(GL_BLEND);
glBlendFunc(state->blend_src_factor, state->blend_dst_factor);
current_draw_state.blend_enable = true;
current_draw_state.blend_src_factor = state->blend_src_factor;
current_draw_state.blend_dst_factor = state->blend_dst_factor;
}
} else if(current_draw_state.blend_enable) {
glDisable(GL_BLEND);
current_draw_state.blend_enable = false;
}
return barriers;
}
static inline void GL_apply_uniform(GLuint location, enum GL_Type type, GLsizei count,
const struct GL_UniformData *data) {
count = count || 1;
if(data->pointer) {
switch(type) {
case GL_Type_Unused:
break;
case GL_Type_Float:
glUniform1fv(location, count, data->pointer);
break;
case GL_Type_Float2:
glUniform2fv(location, count, data->pointer);
break;
case GL_Type_Float3:
glUniform3fv(location, count, data->pointer);
break;
case GL_Type_Float4:
glUniform4fv(location, count, data->pointer);
break;
case GL_Type_Int:
glUniform1iv(location, count, data->pointer);
break;
case GL_Type_Int2:
glUniform2iv(location, count, data->pointer);
break;
case GL_Type_Int3:
glUniform3iv(location, count, data->pointer);
break;
case GL_Type_Int4:
glUniform4iv(location, count, data->pointer);
break;
case GL_Type_Uint:
glUniform1uiv(location, count, data->pointer);
break;
case GL_Type_Uint2:
glUniform2uiv(location, count, data->pointer);
break;
case GL_Type_Uint3:
glUniform3uiv(location, count, data->pointer);
break;
case GL_Type_Uint4:
glUniform4uiv(location, count, data->pointer);
break;
case GL_Type_Float2x2:
glUniformMatrix2fv(location, count, data->transpose, data->pointer);
break;
case GL_Type_Float3x3:
glUniformMatrix3fv(location, count, data->transpose, data->pointer);
break;
case GL_Type_Float4x4:
glUniformMatrix4fv(location, count, data->transpose, data->pointer);
break;
case GL_Type_Float2x3:
glUniformMatrix2x3fv(location, count, data->transpose, data->pointer);
break;
case GL_Type_Float3x2:
glUniformMatrix3x2fv(location, count, data->transpose, data->pointer);
break;
case GL_Type_Float2x4:
glUniformMatrix2x4fv(location, count, data->transpose, data->pointer);
break;
case GL_Type_Float4x2:
glUniformMatrix4x2fv(location, count, data->transpose, data->pointer);
break;
case GL_Type_Float3x4:
glUniformMatrix3x4fv(location, count, data->transpose, data->pointer);
break;
case GL_Type_Float4x3:
glUniformMatrix4x3fv(location, count, data->transpose, data->pointer);
break;
default:
// TODO error
break;
}
} else {
switch(type) {
case GL_Type_Unused:
break;
case GL_Type_Float:
glUniform1f(location, data->_float);
break;
case GL_Type_Float2:
glUniform2f(location, data->vec[0], data->vec[1]);
break;
case GL_Type_Float3:
glUniform3f(location, data->vec[0], data->vec[1], data->vec[2]);
break;
case GL_Type_Float4:
glUniform4f(location, data->vec[0], data->vec[1], data->vec[2], data->vec[3]);
break;
case GL_Type_Int:
glUniform1i(location, data->_int);
break;
case GL_Type_Int2:
glUniform2i(location, data->ivec[0], data->ivec[1]);
break;
case GL_Type_Int3:
glUniform3i(location, data->ivec[0], data->ivec[1], data->ivec[2]);
break;
case GL_Type_Int4:
glUniform4i(location, data->ivec[0], data->ivec[1], data->ivec[2], data->ivec[3]);
break;
case GL_Type_Uint:
glUniform1ui(location, data->uint);
break;
case GL_Type_Uint2:
glUniform2ui(location, data->uvec[0], data->uvec[1]);
break;
case GL_Type_Uint3:
glUniform3ui(location, data->uvec[0], data->uvec[1], data->uvec[2]);
break;
case GL_Type_Uint4:
glUniform4ui(location, data->uvec[0], data->uvec[1], data->uvec[2], data->uvec[3]);
break;
case GL_Type_Float2x2:
glUniformMatrix2fv(location, count, data->transpose, data->mat);
break;
case GL_Type_Float3x3:
glUniformMatrix3fv(location, count, data->transpose, data->mat);
break;
case GL_Type_Float4x4:
glUniformMatrix4fv(location, count, data->transpose, data->mat);
break;
case GL_Type_Float2x3:
glUniformMatrix2x3fv(location, count, data->transpose, data->mat);
break;
case GL_Type_Float3x2:
glUniformMatrix3x2fv(location, count, data->transpose, data->mat);
break;
case GL_Type_Float2x4:
glUniformMatrix2x4fv(location, count, data->transpose, data->mat);
break;
case GL_Type_Float4x2:
glUniformMatrix4x2fv(location, count, data->transpose, data->mat);
break;
case GL_Type_Float3x4:
glUniformMatrix3x4fv(location, count, data->transpose, data->mat);
break;
case GL_Type_Float4x3:
glUniformMatrix4x3fv(location, count, data->transpose, data->mat);
break;
default:
// TODO error
break;
}
}
}
static inline GLbitfield apply_pipeline_assets(const struct GL_PipelineState *state,
const struct GL_PipelineAssets *assets, bool compute) {
static struct GL_PipelineAssets current_assets;
GLuint uniform_location = 0;
GLuint shader_storage_buffer_binding = 0;
GLuint location, binding;
GLbitfield barriers = 0;
for(uint32_t i = 0; i < THIN_GL_MAX_IMAGES; i++) {
if(assets != NULL && assets->image[i]) {
if(current_assets.image[i] != assets->image[i]) {
if(type_info[state->image[i].type].target == GL_SAMPLER) {
glBindSampler(i, assets->image[i]);
} else {
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(type_info[state->image[i].type].target, assets->image[i]);
}
} else {
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D, assets->image[i]);
}
current_assets.image[i] = assets->image[i];
}
}
for(uint32_t i = 0; i < THIN_GL_MAX_UNIFORMS; i++) {
if((!compute && !state->uniform[i].stage_bits) || state->uniform[i].type == GL_Type_Unused)
continue;
GLuint location = uniform_location++;
if(assets != NULL)
GL_apply_uniform(location, state->uniform[i].type, state->uniform[i].count, &assets->uniforms[i]);
}
for(uint32_t i = 0; i < THIN_GL_MAX_UNIFORMS; i++) {
if((!compute && !state->global[i].stage_bits) || state->global[i].resource == NULL)
continue;
uint32_t count = alias_max(state->global[i].resource->count, 1);
if(state->global[i].resource->type == GL_Type_ShaderStorageBuffer) {
binding = shader_storage_buffer_binding;
shader_storage_buffer_binding += count;
} else {
location = uniform_location++;
}
if(state->global[i].resource->type == GL_Type_ShaderStorageBuffer) {
if(count > 1) {
for(uint32_t j = 0; j < count; j++) {
barriers |= GL_flush_buffer(state->global[i].resource->block.buffers[j], GL_SHADER_STORAGE_BARRIER_BIT);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, binding + j, state->global[i].resource->block.buffers[j]->buffer);
}
} else {
barriers |= GL_flush_buffer(state->global[i].resource->block.buffer, GL_SHADER_STORAGE_BARRIER_BIT);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, binding, state->global[i].resource->block.buffer->buffer);
}
} else {
GL_ShaderResource_prepare(state->global[i].resource);
GL_apply_uniform(location, state->global[i].resource->type, state->global[i].resource->count,
&state->global[i].resource->uniform.data);
}
}
return barriers;
}
GLbitfield GL_apply_draw_assets(const struct GL_DrawState *state, const struct GL_DrawAssets *assets) {
// static struct GL_DrawAssets current_draw_assets;
GLbitfield barriers =
apply_pipeline_assets((const struct GL_PipelineState *)state, (const struct GL_PipelineAssets *)assets, false);
if(assets != NULL) {
if(assets->element_buffer != NULL) {
barriers |= GL_flush_buffer(assets->element_buffer, GL_ELEMENT_ARRAY_BARRIER_BIT);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, assets->element_buffer->buffer);
}
for(int i = 0; i < THIN_GL_MAX_BINDINGS; i++) {
if(assets->vertex_buffers[i] == NULL)
break;
barriers |= GL_flush_buffer(assets->vertex_buffers[i], GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
if(assets->vertex_buffers[i]->kind == GL_Buffer_Temporary) {
glBindVertexBuffer(i, assets->vertex_buffers[i]->buffer, assets->vertex_buffers[i]->offset,
state->binding[i].stride);
} else {
glBindVertexBuffer(i, assets->vertex_buffers[i]->buffer, 0, state->binding[i].stride);
}
}
}
return barriers;
}
static void apply_barriers(GLbitfield barriers) {
if(barriers)
glMemoryBarrier(barriers);
}
void GL_draw_arrays(const struct GL_DrawState *state, const struct GL_DrawAssets *assets, GLint first, GLsizei count,
GLsizei instancecount, GLuint baseinstance) {
GL_initialize_draw_state(state);
GLbitfield barriers = GL_apply_draw_state(state);
barriers |= GL_apply_draw_assets(state, assets);
apply_barriers(barriers);
glDrawArraysInstancedBaseInstance(state->primitive, first, count, instancecount, baseinstance);
_.draw_index++;
}
void GL_draw_elements(const struct GL_DrawState *state, const struct GL_DrawAssets *assets, GLsizei count,
GLsizei instancecount, GLint basevertex, GLuint baseinstance) {
GL_initialize_draw_state(state);
GLbitfield barriers = GL_apply_draw_state(state);
barriers |= GL_apply_draw_assets(state, assets);
apply_barriers(barriers);
glDrawElementsInstancedBaseVertexBaseInstance(
state->primitive, count, GL_UNSIGNED_INT,
(void *)(assets->element_buffer->kind == GL_Buffer_Temporary ? assets->element_buffer->offset : 0) +
sizeof(uint32_t) * assets->element_buffer_offset,
instancecount, basevertex, baseinstance);
_.draw_index++;
}
void GL_draw_elements_indirect(const struct GL_DrawState *state, const struct GL_DrawAssets *assets,
const struct GL_Buffer *indirect, GLsizei indirect_offset) {
GL_initialize_draw_state(state);
GLbitfield barriers = GL_apply_draw_state(state);
barriers |= GL_apply_draw_assets(state, assets);
barriers |= GL_flush_buffer(indirect, GL_COMMAND_BARRIER_BIT);
apply_barriers(barriers);
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, indirect->buffer);
glDrawElementsIndirect(state->primitive, GL_UNSIGNED_INT, (const void *)(uintptr_t)indirect_offset);
_.draw_index++;
}
struct GL_Buffer GL_allocate_static_buffer(GLenum type, GLsizei size, const void *data) {
struct GL_Buffer result;
result.kind = GL_Buffer_Static;
glCreateBuffers(1, &result.buffer);
glNamedBufferStorage(result.buffer, size, data, 0);
result.size = size;
return result;
}
struct GL_Buffer GL_allocate_temporary_buffer(GLenum type, GLsizei size) {
again:
for(uint32_t i = 0; i < _.num_temporary_buffers; i++) {
if(_.temporary_buffers[i].type == type && _.temporary_buffers[i].size - _.temporary_buffers[i].offset > size) {
struct GL_Buffer result;
result.kind = GL_Buffer_Temporary;
result.buffer = _.temporary_buffers[i].buffer;
result.size = size;
result.mapping = (void *)((GLbyte *)_.temporary_buffers[i].mapped_memory + _.temporary_buffers[i].offset);
result.offset = _.temporary_buffers[i].offset;
result.dirty = true;
_.temporary_buffers[i].offset += size;
return result;
}
}
// 16 << 20); // 16mb TODO make a cvar
GLsizei block_size = 4 << 20;
GLsizei allocation_size = ((size + block_size) / block_size) * block_size;
_.temporary_buffers = realloc(_.temporary_buffers, sizeof(*_.temporary_buffers) * (_.num_temporary_buffers + 1));
glCreateBuffers(1, &_.temporary_buffers[_.num_temporary_buffers].buffer);
glNamedBufferStorage(_.temporary_buffers[_.num_temporary_buffers].buffer, allocation_size, NULL,
GL_MAP_PERSISTENT_BIT | GL_MAP_WRITE_BIT);
_.temporary_buffers[_.num_temporary_buffers].type = type;
_.temporary_buffers[_.num_temporary_buffers].size = allocation_size;
_.temporary_buffers[_.num_temporary_buffers].offset = 0;
_.temporary_buffers[_.num_temporary_buffers].mapped_memory =
glMapNamedBufferRange(_.temporary_buffers[_.num_temporary_buffers].buffer, 0, allocation_size,
GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_FLUSH_EXPLICIT_BIT);
_.num_temporary_buffers++;
goto again;
}
struct GL_Buffer GL_allocate_temporary_buffer_from(GLenum type, GLsizei size, const void *ptr) {
struct GL_Buffer result = GL_allocate_temporary_buffer(type, size);
memcpy(result.mapping, ptr, size);
return result;
}
static void activate_buffer(const struct GL_Buffer *buffer) {
if(buffer->buffer != 0)
return;
switch(buffer->kind) {
case GL_Buffer_Static:
break;
case GL_Buffer_Temporary:
break;
case GL_Buffer_CPU:
glCreateBuffers(1, (GLuint *)&buffer->buffer);
glNamedBufferStorage(buffer->buffer, buffer->size, NULL, GL_MAP_PERSISTENT_BIT | GL_MAP_WRITE_BIT);
*(void **)&buffer->mapping = glMapNamedBufferRange(
buffer->buffer, 0, buffer->size, GL_MAP_PERSISTENT_BIT | GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT);
break;
case GL_Buffer_GPU:
glCreateBuffers(1, (GLuint *)&buffer->buffer);
glNamedBufferStorage(buffer->buffer, buffer->size, NULL, 0);
break;
}
}
void *GL_update_buffer_begin(const struct GL_Buffer *buffer, GLintptr offset, GLsizei size) {
(void)offset;
(void)size;
if(buffer->kind == GL_Buffer_CPU) {
activate_buffer(buffer);
return buffer->mapping;
}
return NULL;
}
void GL_update_buffer_end(const struct GL_Buffer *buffer, GLintptr offset, GLsizei size) {
if(buffer->kind == GL_Buffer_CPU) {
glFlushMappedNamedBufferRange(buffer->buffer, offset, size);
*(bool *)&buffer->dirty = true;
}
}
GLbitfield GL_flush_buffer(const struct GL_Buffer *buffer, GLbitfield read_barrier_bits) {
switch(buffer->kind) {
case GL_Buffer_Static:
break;
case GL_Buffer_Temporary:
if(buffer->dirty) {
glFlushMappedNamedBufferRange(buffer->buffer, buffer->offset, buffer->size);
*(bool *)&buffer->dirty = false;
return GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT;
}
break;
case GL_Buffer_CPU:
activate_buffer(buffer);
if(buffer->dirty) {
*(bool *)&buffer->dirty = false;
return GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT;
}
break;
case GL_Buffer_GPU:
activate_buffer(buffer);
if(buffer->dirty) {
*(bool *)&buffer->dirty = false;
return read_barrier_bits;
}
break;
}
return 0;
}
void GL_free_buffer(const struct GL_Buffer *buffer) {
switch(buffer->kind) {
case GL_Buffer_Static:
glDeleteBuffers(1, &buffer->buffer);
break;
case GL_Buffer_GPU:
case GL_Buffer_CPU:
break;
case GL_Buffer_Temporary:
break;
}
}
void GL_reset_temporary_buffers(void) {
for(uint32_t i = 0; i < _.num_temporary_buffers; i++) {
_.temporary_buffers[i].offset = 0;
}
}
void GL_temporary_buffer_stats(GLenum type, uint32_t *total_allocated, uint32_t *used) {
*total_allocated = 0;
*used = 0;
for(uint32_t i = 0; i < _.num_temporary_buffers; i++) {
if(_.temporary_buffers[i].type == type) {
*total_allocated += _.temporary_buffers[i].size;
*used += _.temporary_buffers[i].offset;
}
}
}
void GL_ShaderResource_prepare(const struct GL_ShaderResource *resource) {
if(resource->uniform.prepare_draw_index != _.draw_index) {
*(uint32_t *)&resource->uniform.prepare_draw_index = _.draw_index;
if(resource->uniform.prepare != NULL) {
resource->uniform.prepare();
}
}
}
#ifndef GL_SUBGROUP_SIZE
#define GL_SUBGROUP_SIZE 0x9532
#endif
void GL_initialize_compute_state(const struct GL_ComputeState *state) {
if(state->shader != NULL && state->shader_object == 0) {
script_builder_init();
script_builder_add_prelude((const struct GL_ShaderSnippet *)state->shader);
if(state->local_group_x == THIN_GL_LOCAL_GROUP_SIZE_SUBGROUP_SIZE) {
glGetIntegerv(GL_SUBGROUP_SIZE, (GLint *)&state->local_group_x);
}
if(state->local_group_y == THIN_GL_LOCAL_GROUP_SIZE_SUBGROUP_SIZE) {
glGetIntegerv(GL_SUBGROUP_SIZE, (GLint *)&state->local_group_y);
}
if(state->local_group_z == THIN_GL_LOCAL_GROUP_SIZE_SUBGROUP_SIZE) {
glGetIntegerv(GL_SUBGROUP_SIZE, (GLint *)&state->local_group_z);
}
script_builder_add("layout(local_size_x=%i, local_size_y=%i, local_size_z=%i) in;\n",
alias_max(state->local_group_x, 1), alias_max(state->local_group_y, 1),
alias_max(state->local_group_z, 1));
script_builder_add_uniform_format((const struct GL_PipelineState *)state, 0);
script_builder_add_images_format((const struct GL_PipelineState *)state, 0);
script_builder_add_shader_requisites((const struct GL_ShaderSnippet *)state->shader);
script_builder_add("%s", state->shader->code);
GLuint shader = glCreateShader(GL_COMPUTE_SHADER);
glShaderSource(shader, 1, (const char *const *)&_.script_builder_ptr, &_.script_builder_len);
gl_compileShader(shader);
*(GLuint *)(&state->shader_object) = shader;
}
if(state->shader_object != 0 && state->program_object == 0) {
GLuint program = glCreateProgram();
glAttachShader(program, state->shader_object);
gl_linkProgram(program);
*(GLuint *)(&state->program_object) = program;
}
}
GLbitfield GL_apply_compute_state(const struct GL_ComputeState *state) {
return apply_pipeline_state((const struct GL_PipelineState *)state);
}
GLbitfield GL_apply_compute_assets(const struct GL_ComputeState *state, const struct GL_ComputeAssets *assets) {
//static struct GL_ComputeAssets current_compute_assets;
GLbitfield barriers =
apply_pipeline_assets((const struct GL_PipelineState *)state, (const struct GL_PipelineAssets *)assets, true);
if(assets != NULL) {
}
return barriers;
}
void GL_compute(const struct GL_ComputeState *state, const struct GL_ComputeAssets *assets, GLuint num_groups_x,
GLuint num_groups_y, GLuint num_groups_z) {
GL_initialize_compute_state(state);
GLbitfield barriers = GL_apply_compute_state(state);
barriers |= GL_apply_compute_assets(state, assets);
apply_barriers(barriers);
glDispatchCompute(num_groups_x, num_groups_y, num_groups_z);
}
void GL_compute_indirect(const struct GL_ComputeState *state, const struct GL_ComputeAssets *assets,
const struct GL_Buffer *indirect, GLsizei indirect_offset) {
GL_initialize_compute_state(state);
GLbitfield barriers = GL_apply_compute_state(state);
barriers |= GL_apply_compute_assets(state, assets);
barriers |= GL_flush_buffer(indirect, GL_COMMAND_BARRIER_BIT);
apply_barriers(barriers);
glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, indirect->buffer);
glDispatchComputeIndirect(indirect_offset);
}
printf("%.*s\n", _.script_builder_len, _.script_builder_ptr);
script_builder_add("#define _Bool bool\n");
}
}
static uint32_t script_builder_collect_flags(const struct GL_ShaderSnippet *shader) {
uint32_t flags = shader->flags;
for(uint32_t i = 0; i < 8; i++) {
if(shader->requires[i] == NULL)
break;
flags |= script_builder_collect_flags(shader->requires[i]);
}
return flags;
}
static void script_builder_add_prelude(const struct GL_ShaderSnippet *shader) {
uint32_t flags = script_builder_collect_flags(shader);
script_builder_add("#version 460 core\n");
if(flags & THIN_GL_SHADER_FLAG_SUBGROUP_ARITHMETIC) {
script_builder_add("#extension GL_KHR_shader_subgroup_arithmetic : enable\n");
}
if(flags & THIN_GL_SHADER_FLAG_ARITHMETIC_INT64) {
script_builder_add("#extension GL_EXT_shader_explicit_arithmetic_types_int64 : enable\n");
.uniform[0] = {THIN_GL_FRAGMENT_BIT, GL_Type_Float, "alpha"},
.global[0] = {THIN_GL_VERTEX_BIT, &u_view_projection_matrix},
.image[0] = {THIN_GL_FRAGMENT_BIT, GL_Type_Sampler2D, "img"},
.uniform[0] = {ALIAS_GL_FRAGMENT_BIT, alias_gl_Type_float, "alpha"},
.global[0] = {ALIAS_GL_VERTEX_BIT, &u_view_projection_matrix},
.image[0] = {ALIAS_GL_FRAGMENT_BIT, alias_gl_Type_sampler2D, "img"},
struct GL_Buffer element_buffer =
GL_allocate_temporary_buffer_from(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32_t) * 6, indexes);
struct GL_Buffer vertex_buffer =
GL_allocate_temporary_buffer_from(GL_ARRAY_BUFFER, sizeof(struct DrawVertex) * 4, vertexes);
struct alias_gl_Buffer element_buffer =
alias_gl_allocateTemporaryBufferFrom(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32_t) * 6, indexes);
struct alias_gl_Buffer vertex_buffer =
alias_gl_allocateTemporaryBufferFrom(GL_ARRAY_BUFFER, sizeof(struct DrawVertex) * 4, vertexes);
.image[0] = {THIN_GL_FRAGMENT_BIT, GL_Type_Sampler2D, "sky_map"},
.global[0] = {THIN_GL_VERTEX_BIT, &u_model_view_projection_matrix},
.image[0] = {ALIAS_GL_FRAGMENT_BIT, alias_gl_Type_sampler2D, "sky_map"},
.global[0] = {ALIAS_GL_VERTEX_BIT, &u_model_view_projection_matrix},
GL_matrix_translation(r_origin[0], r_origin[1], r_origin[2], u_model_matrix.uniform.data.mat);
GL_rotate(u_model_matrix.uniform.data.mat, r_newrefdef.time * sky[cmodel_index].rotate, sky[cmodel_index].axis[0],
alias_matrix_translation(r_origin[0], r_origin[1], r_origin[2], u_model_matrix.uniform.data.mat);
alias_rotate(u_model_matrix.uniform.data.mat, r_newrefdef.time * sky[cmodel_index].rotate, sky[cmodel_index].axis[0],
index_buffer = GL_allocate_static_buffer(GL_ELEMENT_ARRAY_BUFFER, sizeof(index_data), index_data);
vertex_buffer = GL_allocate_static_buffer(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data);
index_buffer = alias_gl_allocateStaticBuffer(GL_ELEMENT_ARRAY_BUFFER, sizeof(index_data), index_data);
vertex_buffer = alias_gl_allocateStaticBuffer(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data);
.uniform[0] = {THIN_GL_FRAGMENT_BIT, GL_Type_Float3, "tangent"}, \
.uniform[1] = {THIN_GL_FRAGMENT_BIT, GL_Type_Float3, "bitangent"}, \
.uniform[2] = {THIN_GL_FRAGMENT_BIT, GL_Type_Float3, "normal"}, \
.uniform[3] = {THIN_GL_FRAGMENT_BIT, GL_Type_Float2, "alpha_time"}, \
.global[0] = {THIN_GL_VERTEX_BIT, &u_model_view_projection_matrix}
.uniform[0] = {ALIAS_GL_FRAGMENT_BIT, alias_gl_Type_float3, "tangent"}, \
.uniform[1] = {ALIAS_GL_FRAGMENT_BIT, alias_gl_Type_float3, "bitangent"}, \
.uniform[2] = {ALIAS_GL_FRAGMENT_BIT, alias_gl_Type_float3, "normal"}, \
.uniform[3] = {ALIAS_GL_FRAGMENT_BIT, alias_gl_Type_float2, "alpha_time"}, \
.global[0] = {ALIAS_GL_VERTEX_BIT, &u_model_view_projection_matrix}
.image[0] = {THIN_GL_FRAGMENT_BIT, GL_Type_Sampler2D, "albedo_map"}, \
.image[1] = {THIN_GL_FRAGMENT_BIT, GL_Type_Sampler2D, "normal_map"}, \
.image[3] = {THIN_GL_FRAGMENT_BIT, GL_Type_Sampler2D, "lightmap_rgb0"}, \
.image[4] = {THIN_GL_FRAGMENT_BIT, GL_Type_Sampler2D, "lightmap_r1"}, \
.image[5] = {THIN_GL_FRAGMENT_BIT, GL_Type_Sampler2D, "lightmap_g1"}, \
.image[6] = {THIN_GL_FRAGMENT_BIT, GL_Type_Sampler2D, "lightmap_b1"}
.image[0] = {ALIAS_GL_FRAGMENT_BIT, alias_gl_Type_sampler2D, "albedo_map"}, \
.image[1] = {ALIAS_GL_FRAGMENT_BIT, alias_gl_Type_sampler2D, "normal_map"}, \
.image[3] = {ALIAS_GL_FRAGMENT_BIT, alias_gl_Type_sampler2D, "lightmap_rgb0"}, \
.image[4] = {ALIAS_GL_FRAGMENT_BIT, alias_gl_Type_sampler2D, "lightmap_r1"}, \
.image[5] = {ALIAS_GL_FRAGMENT_BIT, alias_gl_Type_sampler2D, "lightmap_g1"}, \
.image[6] = {ALIAS_GL_FRAGMENT_BIT, alias_gl_Type_sampler2D, "lightmap_b1"}
GL_ShaderResource_prepare(&u_view_projection_matrix);
GL_matrix_multiply(u_view_projection_matrix.uniform.data.mat, u_model_matrix.uniform.data.mat,
alias_gl_ShaderResource_prepare(&u_view_projection_matrix);
alias_matrix_multiply(u_view_projection_matrix.uniform.data.mat, u_model_matrix.uniform.data.mat,
struct GL_ShaderResource u_time = {.type = GL_Type_Float, .name = "time"};
struct GL_ShaderResource u_model_matrix = {.type = GL_Type_Float4x4, .name = "model_matrix"};
struct GL_ShaderResource u_view_matrix = {.type = GL_Type_Float4x4, .name = "view_matrix"};
struct GL_ShaderResource u_model_view_matrix = {
.type = GL_Type_Float4x4, .name = "model_view_matrix", .uniform.prepare = prepare_model_view};
struct GL_ShaderResource u_projection_matrix = {.type = GL_Type_Float4x4, .name = "projection_matrix"};
struct GL_ShaderResource u_view_projection_matrix = {
.type = GL_Type_Float4x4, .name = "view_projection_matrix", .uniform.prepare = prepare_view_projection};
struct GL_ShaderResource u_model_view_projection_matrix = {
.type = GL_Type_Float4x4, .name = "model_view_projection_matrix", .uniform.prepare = prepare_model_view_projection};
struct alias_gl_ShaderResource u_time = {.type = alias_gl_Type_float, .name = "time"};
struct alias_gl_ShaderResource u_model_matrix = {.type = alias_gl_Type_float4x4, .name = "model_matrix"};
struct alias_gl_ShaderResource u_view_matrix = {.type = alias_gl_Type_float4x4, .name = "view_matrix"};
struct alias_gl_ShaderResource u_model_view_matrix = {
.type = alias_gl_Type_float4x4, .name = "model_view_matrix", .uniform.prepare = prepare_model_view};
struct alias_gl_ShaderResource u_projection_matrix = {.type = alias_gl_Type_float4x4, .name = "projection_matrix"};
struct alias_gl_ShaderResource u_view_projection_matrix = {
.type = alias_gl_Type_float4x4, .name = "view_projection_matrix", .uniform.prepare = prepare_view_projection};
struct alias_gl_ShaderResource u_model_view_projection_matrix = {
.type = alias_gl_Type_float4x4, .name = "model_view_projection_matrix", .uniform.prepare = prepare_model_view_projection};
struct GL_Buffer u_frame_buffer = {.kind = GL_Buffer_CPU, .size = sizeof(struct GL_Frame)};
struct GL_ShaderResource u_frame = {.type = GL_Type_ShaderStorageBuffer,
struct alias_gl_Buffer u_frame_buffer = {.kind = alias_gl_Buffer_cpu, .size = sizeof(struct alias_gl_Frame)};
struct alias_gl_ShaderResource u_frame = {.type = alias_gl_Type_shaderStorageBuffer,
GL_translate(u_model_matrix.uniform.data.mat, e->origin[0], e->origin[1], e->origin[2]);
GL_rotate_z(u_model_matrix.uniform.data.mat, e->angles[1]);
GL_rotate_y(u_model_matrix.uniform.data.mat, -e->angles[0]);
GL_rotate_x(u_model_matrix.uniform.data.mat, -e->angles[2]);
alias_translate(u_model_matrix.uniform.data.mat, e->origin[0], e->origin[1], e->origin[2]);
alias_rotate_z(u_model_matrix.uniform.data.mat, e->angles[1]);
alias_rotate_y(u_model_matrix.uniform.data.mat, -e->angles[0]);
alias_rotate_x(u_model_matrix.uniform.data.mat, -e->angles[2]);
GL_matrix_identity(u_view_matrix.uniform.data.mat);
GL_rotate_x(u_view_matrix.uniform.data.mat, -90);
GL_rotate_z(u_view_matrix.uniform.data.mat, 90);
GL_rotate_x(u_view_matrix.uniform.data.mat, -r_newrefdef.viewangles[2]);
GL_rotate_y(u_view_matrix.uniform.data.mat, -r_newrefdef.viewangles[0]);
GL_rotate_z(u_view_matrix.uniform.data.mat, -r_newrefdef.viewangles[1]);
GL_translate(u_view_matrix.uniform.data.mat, -r_newrefdef.vieworg[0], -r_newrefdef.vieworg[1],
alias_matrix_identity(u_view_matrix.uniform.data.mat);
alias_rotate_x(u_view_matrix.uniform.data.mat, -90);
alias_rotate_z(u_view_matrix.uniform.data.mat, 90);
alias_rotate_x(u_view_matrix.uniform.data.mat, -r_newrefdef.viewangles[2]);
alias_rotate_y(u_view_matrix.uniform.data.mat, -r_newrefdef.viewangles[0]);
alias_rotate_z(u_view_matrix.uniform.data.mat, -r_newrefdef.viewangles[1]);
alias_translate(u_view_matrix.uniform.data.mat, -r_newrefdef.vieworg[0], -r_newrefdef.vieworg[1],
GL_matrix_ortho(0, vid.width, vid.height, 0, -99999, 99999, u_projection_matrix.uniform.data.mat);
GL_matrix_identity(u_view_matrix.uniform.data.mat);
alias_matrix_ortho(0, vid.width, vid.height, 0, -99999, 99999, u_projection_matrix.uniform.data.mat);
alias_matrix_identity(u_view_matrix.uniform.data.mat);
GL_matrix_ortho(0, vid.width, vid.height, 0, -99999, 99999, u_projection_matrix.uniform.data.mat);
GL_matrix_identity(u_view_matrix.uniform.data.mat);
alias_matrix_ortho(0, vid.width, vid.height, 0, -99999, 99999, u_projection_matrix.uniform.data.mat);
alias_matrix_identity(u_view_matrix.uniform.data.mat);
THIN_GL_BLOCK(particle_data, require(particle_Data), unsized_array(struct(particle_DataPacked, item)))
static struct GL_Buffer data_buffer = {.kind = GL_Buffer_GPU, .size = sizeof(struct GL_particle_Data) * NUM_PARTICLES};
static struct GL_ShaderResource data_resource = {.type = GL_Type_ShaderStorageBuffer,
ALIAS_GL_BLOCK(particle_data, require(particle_Data), unsized_array(struct(particle_DataPacked, item)))
static struct alias_gl_Buffer data_buffer = {.kind = alias_gl_Buffer_gpu, .size = sizeof(struct alias_gl_particle_Data) * NUM_PARTICLES};
static struct alias_gl_ShaderResource data_resource = {.type = alias_gl_Type_shaderStorageBuffer,
THIN_GL_BLOCK(particle_distance, unsized_array(uint32(item)))
static struct GL_Buffer distance_buffer = {.kind = GL_Buffer_GPU, .size = sizeof(uint32_t) * NUM_PARTICLES};
static struct GL_ShaderResource distance_resource = {.type = GL_Type_ShaderStorageBuffer,
ALIAS_GL_BLOCK(particle_distance, unsized_array(uint32(item)))
static struct alias_gl_Buffer distance_buffer = {.kind = alias_gl_Buffer_gpu, .size = sizeof(uint32_t) * NUM_PARTICLES};
static struct alias_gl_ShaderResource distance_resource = {.type = alias_gl_Type_shaderStorageBuffer,
.block.snippet = &GL_particle_distance_snippet};
static struct GL_Buffer distance2_buffer = {.kind = GL_Buffer_GPU, .size = sizeof(uint32_t) * NUM_PARTICLES};
.block.snippet = &alias_gl_particle_distance_snippet};
static struct alias_gl_Buffer distance2_buffer = {.kind = alias_gl_Buffer_gpu, .size = sizeof(uint32_t) * NUM_PARTICLES};
THIN_GL_BLOCK(particle_dead, unsized_array(uint32(item)))
static struct GL_Buffer dead_buffer = {.kind = GL_Buffer_GPU, .size = sizeof(uint32_t) * NUM_PARTICLES};
static struct GL_ShaderResource dead_resource = {.type = GL_Type_ShaderStorageBuffer,
ALIAS_GL_BLOCK(particle_dead, unsized_array(uint32(item)))
static struct alias_gl_Buffer dead_buffer = {.kind = alias_gl_Buffer_gpu, .size = sizeof(uint32_t) * NUM_PARTICLES};
static struct alias_gl_ShaderResource dead_resource = {.type = alias_gl_Type_shaderStorageBuffer,
THIN_GL_BLOCK(particle_alive, unsized_array(uint32(item)))
static struct GL_Buffer alive_buffer = {.kind = GL_Buffer_GPU, .size = sizeof(uint32_t) * NUM_PARTICLES};
static struct GL_ShaderResource alive_resource = {.type = GL_Type_ShaderStorageBuffer,
ALIAS_GL_BLOCK(particle_alive, unsized_array(uint32(item)))
static struct alias_gl_Buffer alive_buffer = {.kind = alias_gl_Buffer_gpu, .size = sizeof(uint32_t) * NUM_PARTICLES};
static struct alias_gl_ShaderResource alive_resource = {.type = alias_gl_Type_shaderStorageBuffer,
THIN_GL_BLOCK(particle_emitted, unsized_array(uint32(item)))
static struct GL_Buffer emitted_buffer = {.kind = GL_Buffer_GPU, .size = sizeof(uint32_t) * NUM_PARTICLES};
static struct GL_ShaderResource emitted_resource = {.type = GL_Type_ShaderStorageBuffer,
ALIAS_GL_BLOCK(particle_emitted, unsized_array(uint32(item)))
static struct alias_gl_Buffer emitted_buffer = {.kind = alias_gl_Buffer_gpu, .size = sizeof(uint32_t) * NUM_PARTICLES};
static struct alias_gl_ShaderResource emitted_resource = {.type = alias_gl_Type_shaderStorageBuffer,
THIN_GL_BLOCK(particle_counter, uint32(alive), int32(dead), uint32(simulate))
static struct GL_Buffer counter_buffer = {.kind = GL_Buffer_GPU, .size = sizeof(struct GL_particle_counter)};
static struct GL_ShaderResource counter_resource = {.type = GL_Type_ShaderStorageBuffer,
ALIAS_GL_BLOCK(particle_counter, uint32(alive), int32(dead), uint32(simulate))
static struct alias_gl_Buffer counter_buffer = {.kind = alias_gl_Buffer_gpu, .size = sizeof(struct alias_gl_particle_counter)};
static struct alias_gl_ShaderResource counter_resource = {.type = alias_gl_Type_shaderStorageBuffer,
static struct GL_Buffer indirect_buffer = {.kind = GL_Buffer_GPU, .size = sizeof(struct GL_particle_indirect)};
static struct GL_ShaderResource indirect_resource = {.type = GL_Type_ShaderStorageBuffer,
static struct alias_gl_Buffer indirect_buffer = {.kind = alias_gl_Buffer_gpu, .size = sizeof(struct alias_gl_particle_indirect)};
static struct alias_gl_ShaderResource indirect_resource = {.type = alias_gl_Type_shaderStorageBuffer,
static struct GL_Buffer sort_parameters_buffer = {.kind = GL_Buffer_GPU, .size = sizeof(struct GL_sort_parameters)};
static struct GL_ShaderResource sort_parameters_resource = {.type = GL_Type_ShaderStorageBuffer,
static struct alias_gl_Buffer sort_parameters_buffer = {.kind = alias_gl_Buffer_gpu, .size = sizeof(struct alias_gl_sort_parameters)};
static struct alias_gl_ShaderResource sort_parameters_resource = {.type = alias_gl_Type_shaderStorageBuffer,
THIN_GL_BLOCK(particle_key, unsized_array(uint32(item)))
static struct GL_ShaderResource sort_key_resource = {.type = GL_Type_ShaderStorageBuffer,
ALIAS_GL_BLOCK(particle_key, unsized_array(uint32(item)))
static struct alias_gl_ShaderResource sort_key_resource = {.type = alias_gl_Type_shaderStorageBuffer,
THIN_GL_BLOCK(particle_value, unsized_array(uint32(item)))
static struct GL_ShaderResource sort_value_resource = {.type = GL_Type_ShaderStorageBuffer,
ALIAS_GL_BLOCK(particle_value, unsized_array(uint32(item)))
static struct alias_gl_ShaderResource sort_value_resource = {.type = alias_gl_Type_shaderStorageBuffer,
static struct GL_ComputeState initialize_compute_state = {.shader = &initialize_shader,
.uniform[0] = {0, GL_Type_Uint, "count"},
static struct alias_gl_ComputeState initialize_compute_state = {.shader = &initialize_shader,
.uniform[0] = {0, alias_gl_Type_uint, "count"},
struct GL_ComputeState emit_single_compute_state = {.shader = &emit_single_shader,
.uniform[0] = {0, GL_Type_Float3, "origin"},
.uniform[1] = {0, GL_Type_Float3, "velocity"},
.uniform[2] = {0, GL_Type_Float3, "acceleration"},
.uniform[3] = {0, GL_Type_Float, "alpha"},
.uniform[4] = {0, GL_Type_Float, "alphaVelocity"},
.uniform[5] = {0, GL_Type_Float4, "albedo"},
.uniform[6] = {0, GL_Type_Float4, "emit"},
.uniform[7] = {0, GL_Type_Float, "incandescence"},
.uniform[8] = {0, GL_Type_Float, "incandescenceVelocity"},
struct alias_gl_ComputeState emit_single_compute_state = {.shader = &emit_single_shader,
.uniform[0] = {0, alias_gl_Type_float3, "origin"},
.uniform[1] = {0, alias_gl_Type_float3, "velocity"},
.uniform[2] = {0, alias_gl_Type_float3, "acceleration"},
.uniform[3] = {0, alias_gl_Type_float, "alpha"},
.uniform[4] = {0, alias_gl_Type_float, "alphaVelocity"},
.uniform[5] = {0, alias_gl_Type_float4, "albedo"},
.uniform[6] = {0, alias_gl_Type_float4, "emit"},
.uniform[7] = {0, alias_gl_Type_float, "incandescence"},
.uniform[8] = {0, alias_gl_Type_float, "incandescenceVelocity"},
.attribute[0] = {0, alias_memory_Format_Float32, 3, "origin", offsetof(struct GL_particle_Data, origin_time)},
.attribute[1] = {0, alias_memory_Format_Float32, 1, "time", offsetof(struct GL_particle_Data, origin_time) + 12},
.attribute[2] = {0, alias_memory_Format_Snorm16, 3, "velocity", offsetof(struct GL_particle_Data, velocity_alpha)},
.attribute[3] = {0, alias_memory_Format_Snorm16, 1, "alpha", offsetof(struct GL_particle_Data, velocity_alpha) + 6},
.attribute[0] = {0, alias_memory_Format_Float32, 3, "origin", offsetof(struct alias_gl_particle_Data, origin_time)},
.attribute[1] = {0, alias_memory_Format_Float32, 1, "time", offsetof(struct alias_gl_particle_Data, origin_time) + 12},
.attribute[2] = {0, alias_memory_Format_Snorm16, 3, "velocity", offsetof(struct alias_gl_particle_Data, velocity_alpha)},
.attribute[3] = {0, alias_memory_Format_Snorm16, 1, "alpha", offsetof(struct alias_gl_particle_Data, velocity_alpha) + 6},
offsetof(struct GL_particle_Data, acceleration_alphaVelocity) + 6},
.attribute[6] = {0, alias_memory_Format_Unorm8, 3, "albedo", offsetof(struct GL_particle_Data, albedo)},
.attribute[7] = {0, alias_memory_Format_Unorm8, 3, "emit", offsetof(struct GL_particle_Data, emit)},
offsetof(struct alias_gl_particle_Data, acceleration_alphaVelocity) + 6},
.attribute[6] = {0, alias_memory_Format_Unorm8, 3, "albedo", offsetof(struct alias_gl_particle_Data, albedo)},
.attribute[7] = {0, alias_memory_Format_Unorm8, 3, "emit", offsetof(struct alias_gl_particle_Data, emit)},
offsetof(struct GL_particle_Data, incandescence_incandescenceVelocity) + 2},
.binding[0] = {sizeof(struct GL_particle_Data), 0},
.uniform[0] = {THIN_GL_VERTEX_BIT, GL_Type_Float3, "point_size_sizemin_sizemax"},
.uniform[1] = {THIN_GL_VERTEX_BIT, GL_Type_Float3, "point_a_b_c"},
.global[0] = {THIN_GL_VERTEX_BIT, &u_view_projection_matrix},
.global[1] = {THIN_GL_VERTEX_BIT, &u_view_matrix},
.global[2] = {THIN_GL_VERTEX_BIT, &u_time},
offsetof(struct alias_gl_particle_Data, incandescence_incandescenceVelocity) + 2},
.binding[0] = {sizeof(struct alias_gl_particle_Data), 0},
.uniform[0] = {ALIAS_GL_VERTEX_BIT, alias_gl_Type_float3, "point_size_sizemin_sizemax"},
.uniform[1] = {ALIAS_GL_VERTEX_BIT, alias_gl_Type_float3, "point_a_b_c"},
.global[0] = {ALIAS_GL_VERTEX_BIT, &u_view_projection_matrix},
.global[1] = {ALIAS_GL_VERTEX_BIT, &u_view_matrix},
.global[2] = {ALIAS_GL_VERTEX_BIT, &u_time},
GL_compute_indirect(&simulate_compute_state, NULL, &indirect_buffer, offsetof(struct GL_particle_indirect, simulate));
alias_gl_computeIndirect(&simulate_compute_state, NULL, &indirect_buffer, offsetof(struct alias_gl_particle_indirect, simulate));
GL_compute_indirect(&sort_particles_fill_pass_state, NULL, &sort_parameters_buffer,
offsetof(struct GL_sort_parameters, fill));
alias_gl_computeIndirect(&sort_particles_fill_pass_state, NULL, &sort_parameters_buffer,
offsetof(struct alias_gl_sort_parameters, fill));
GL_compute_indirect(&sort_particles_radix_pass_1_state, NULL, &sort_parameters_buffer,
offsetof(struct GL_sort_parameters, radix_1));
alias_gl_computeIndirect(&sort_particles_radix_pass_1_state, NULL, &sort_parameters_buffer,
offsetof(struct alias_gl_sort_parameters, radix_1));
GL_compute_indirect(&sort_particles_rotate_pass_state, NULL, &sort_parameters_buffer,
offsetof(struct GL_sort_parameters, rotate));
alias_gl_computeIndirect(&sort_particles_rotate_pass_state, NULL, &sort_parameters_buffer,
offsetof(struct alias_gl_sort_parameters, rotate));
GL_compute_indirect(&sort_particles_radix_pass_2_state, NULL, &sort_parameters_buffer,
offsetof(struct GL_sort_parameters, radix_2));
alias_gl_computeIndirect(&sort_particles_radix_pass_2_state, NULL, &sort_parameters_buffer,
offsetof(struct alias_gl_sort_parameters, radix_2));
GL_compute_indirect(&sort_particles_sortedmatrix_pass_state, NULL, &sort_parameters_buffer,
offsetof(struct GL_sort_parameters, sortedmatrix));
alias_gl_computeIndirect(&sort_particles_sortedmatrix_pass_state, NULL, &sort_parameters_buffer,
offsetof(struct alias_gl_sort_parameters, sortedmatrix));
GL_draw_elements_indirect(&particle_draw_state, &assets, &indirect_buffer,
offsetof(struct GL_particle_indirect, draw));
alias_gl_drawElementsIndirect(&particle_draw_state, &assets, &indirect_buffer,
offsetof(struct alias_gl_particle_indirect, draw));
.uniform[0] = {THIN_GL_FRAGMENT_BIT, GL_Type_Float3, "light_rgb0"}, \
.uniform[1] = {THIN_GL_FRAGMENT_BIT, GL_Type_Float3, "light_r1"}, \
.uniform[2] = {THIN_GL_FRAGMENT_BIT, GL_Type_Float3, "light_g1"}, \
.uniform[3] = {THIN_GL_FRAGMENT_BIT, GL_Type_Float3, "light_b1"}, \
.global[0] = {THIN_GL_VERTEX_BIT, &u_model_view_projection_matrix}
.uniform[0] = {ALIAS_GL_FRAGMENT_BIT, alias_gl_Type_float3, "light_rgb0"}, \
.uniform[1] = {ALIAS_GL_FRAGMENT_BIT, alias_gl_Type_float3, "light_r1"}, \
.uniform[2] = {ALIAS_GL_FRAGMENT_BIT, alias_gl_Type_float3, "light_g1"}, \
.uniform[3] = {ALIAS_GL_FRAGMENT_BIT, alias_gl_Type_float3, "light_b1"}, \
.global[0] = {ALIAS_GL_VERTEX_BIT, &u_model_view_projection_matrix}
element_buffer = GL_allocate_static_buffer(GL_ELEMENT_ARRAY_BUFFER, sizeof(element_data), element_data);
vertex_buffer = GL_allocate_static_buffer(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data);
element_buffer = alias_gl_allocateStaticBuffer(GL_ELEMENT_ARRAY_BUFFER, sizeof(element_data), element_data);
vertex_buffer = alias_gl_allocateStaticBuffer(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data);
(struct GL_UniformData){.vec[0] = shadelight.f[5], .vec[1] = shadelight.f[6], .vec[2] = shadelight.f[7]},
.uniforms[3] = (struct GL_UniformData){.vec[0] = shadelight.f[9],
(struct alias_gl_UniformData){.vec[0] = shadelight.f[5], .vec[1] = shadelight.f[6], .vec[2] = shadelight.f[7]},
.uniforms[3] = (struct alias_gl_UniformData){.vec[0] = shadelight.f[9],
struct GL_Buffer element_buffer; // triangles
struct GL_Buffer position_buffer; // position float[3]
struct GL_Buffer attribute_buffer; // st unorm16[2] / 2, lightmap_st unorm16[2], quat snorm16[4]
struct alias_gl_Buffer element_buffer; // triangles
struct alias_gl_Buffer position_buffer; // position float[3]
struct alias_gl_Buffer attribute_buffer; // st unorm16[2] / 2, lightmap_st unorm16[2], quat snorm16[4]
GL_allocate_static_buffer(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32_t) * num_elements, element_buffer_data);
alias_gl_allocateStaticBuffer(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32_t) * num_elements, element_buffer_data);
.uniform[0] = {THIN_GL_FRAGMENT_BIT, GL_Type_Float3, "light_rgb0"}, \
.uniform[1] = {THIN_GL_FRAGMENT_BIT, GL_Type_Float3, "light_r1"}, \
.uniform[2] = {THIN_GL_FRAGMENT_BIT, GL_Type_Float3, "light_g1"}, \
.uniform[3] = {THIN_GL_FRAGMENT_BIT, GL_Type_Float3, "light_b1"}, \
.global[0] = {THIN_GL_VERTEX_BIT, &u_model_matrix}, .global[1] = {THIN_GL_VERTEX_BIT, &u_view_matrix}, \
.global[2] = {THIN_GL_VERTEX_BIT, &u_projection_matrix}
.uniform[0] = {ALIAS_GL_FRAGMENT_BIT, alias_gl_Type_float3, "light_rgb0"}, \
.uniform[1] = {ALIAS_GL_FRAGMENT_BIT, alias_gl_Type_float3, "light_r1"}, \
.uniform[2] = {ALIAS_GL_FRAGMENT_BIT, alias_gl_Type_float3, "light_g1"}, \
.uniform[3] = {ALIAS_GL_FRAGMENT_BIT, alias_gl_Type_float3, "light_b1"}, \
.global[0] = {ALIAS_GL_VERTEX_BIT, &u_model_matrix}, .global[1] = {ALIAS_GL_VERTEX_BIT, &u_view_matrix}, \
.global[2] = {ALIAS_GL_VERTEX_BIT, &u_projection_matrix}
static struct GL_DrawState draw_state_opaque = {DRAW_STATE, NO_SHELL, OPAQUE, NO_DEPTH_HACK};
static struct GL_DrawState draw_state_opaque_depthhack = {DRAW_STATE, NO_SHELL, OPAQUE, DEPTH_HACK};
static struct GL_DrawState draw_state_transparent = {DRAW_STATE, NO_SHELL, TRANSPARENT, NO_DEPTH_HACK};
static struct GL_DrawState draw_state_transparent_depthhack = {DRAW_STATE, NO_SHELL, TRANSPARENT, DEPTH_HACK};
static struct alias_gl_DrawState draw_state_opaque = {DRAW_STATE, NO_SHELL, OPAQUE, NO_DEPTH_HACK};
static struct alias_gl_DrawState draw_state_opaque_depthhack = {DRAW_STATE, NO_SHELL, OPAQUE, DEPTH_HACK};
static struct alias_gl_DrawState draw_state_transparent = {DRAW_STATE, NO_SHELL, TRANSPARENT, NO_DEPTH_HACK};
static struct alias_gl_DrawState draw_state_transparent_depthhack = {DRAW_STATE, NO_SHELL, TRANSPARENT, DEPTH_HACK};
struct GL_Buffer element_vbo =
GL_allocate_temporary_buffer(GL_ELEMENT_ARRAY_BUFFER, render_mesh->num_indexes * sizeof(uint32_t));
struct GL_Buffer position_vbo =
GL_allocate_temporary_buffer(GL_ARRAY_BUFFER, render_mesh->num_vertexes * sizeof(struct VertexPosition));
struct GL_Buffer attribute_vbo =
GL_allocate_temporary_buffer(GL_ARRAY_BUFFER, render_mesh->num_vertexes * sizeof(struct VertexAttribute));
struct alias_gl_Buffer element_vbo =
alias_gl_allocateTemporaryBuffer(GL_ELEMENT_ARRAY_BUFFER, render_mesh->num_indexes * sizeof(uint32_t));
struct alias_gl_Buffer position_vbo =
alias_gl_allocateTemporaryBuffer(GL_ARRAY_BUFFER, render_mesh->num_vertexes * sizeof(struct VertexPosition));
struct alias_gl_Buffer attribute_vbo =
alias_gl_allocateTemporaryBuffer(GL_ARRAY_BUFFER, render_mesh->num_vertexes * sizeof(struct VertexAttribute));
extern struct GL_ShaderResource u_time;
extern struct GL_ShaderResource u_model_matrix;
extern struct GL_ShaderResource u_view_matrix;
extern struct GL_ShaderResource u_model_view_matrix;
extern struct GL_ShaderResource u_projection_matrix;
extern struct GL_ShaderResource u_view_projection_matrix;
extern struct GL_ShaderResource u_model_view_projection_matrix;
extern struct alias_gl_ShaderResource u_time;
extern struct alias_gl_ShaderResource u_model_matrix;
extern struct alias_gl_ShaderResource u_view_matrix;
extern struct alias_gl_ShaderResource u_model_view_matrix;
extern struct alias_gl_ShaderResource u_projection_matrix;
extern struct alias_gl_ShaderResource u_view_projection_matrix;
extern struct alias_gl_ShaderResource u_model_view_projection_matrix;
extern struct GL_ShaderResource u_frame;
extern struct GL_ShaderResource u_frame_metrics;
extern struct GL_ShaderResource u_view;
extern struct GL_ShaderResource u_draw;
extern struct alias_gl_ShaderResource u_frame;
extern struct alias_gl_ShaderResource u_frame_metrics;
extern struct alias_gl_ShaderResource u_view;
extern struct alias_gl_ShaderResource u_draw;
.global[0] = {THIN_GL_VERTEX_BIT, &u_view_projection_matrix},
.image[0] = {THIN_GL_FRAGMENT_BIT, GL_Type_Sampler2D, "img"},
.global[0] = {ALIAS_GL_VERTEX_BIT, &u_view_projection_matrix},
.image[0] = {ALIAS_GL_FRAGMENT_BIT, alias_gl_Type_sampler2D, "img"},
struct GL_Buffer element_buffer =
GL_allocate_temporary_buffer_from(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32_t) * num_indexes, indexes);
struct GL_Buffer vertex_buffer =
GL_allocate_temporary_buffer_from(GL_ARRAY_BUFFER, sizeof(struct DrawVertex) * num_vertexes, vertexes);
struct alias_gl_Buffer element_buffer =
alias_gl_allocateTemporaryBufferFrom(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32_t) * num_indexes, indexes);
struct alias_gl_Buffer vertex_buffer =
alias_gl_allocateTemporaryBufferFrom(GL_ARRAY_BUFFER, sizeof(struct DrawVertex) * num_vertexes, vertexes);
THIN_GL_DECLARE_SNIPPET(sort_key_float)
THIN_GL_DECLARE_SNIPPET(sort_key_uint)
THIN_GL_DECLARE_SNIPPET(sort_key)
THIN_GL_DECLARE_SNIPPET(sort_key_xy)
ALIAS_GL_DECLARE_SNIPPET(sort_key_float)
ALIAS_GL_DECLARE_SNIPPET(sort_key_uint)
ALIAS_GL_DECLARE_SNIPPET(sort_key)
ALIAS_GL_DECLARE_SNIPPET(sort_key_xy)
"#define RADIXSORT_BITS_PER_PASS " THIN_GL_TO_STRING(RADIXSORT_BITS_PER_PASS) "\n"
"#define RADIXSORT_WORKGROUP_SIZE " THIN_GL_TO_STRING(RADIXSORT_WORKGROUP_SIZE) "\n"
"#define RADIXSORT_BITS_PER_PASS " ALIAS_GL_TO_STRING(RADIXSORT_BITS_PER_PASS) "\n"
"#define RADIXSORT_WORKGROUP_SIZE " ALIAS_GL_TO_STRING(RADIXSORT_WORKGROUP_SIZE) "\n"
.uniform[0] = {THIN_GL_FRAGMENT_BIT, GL_Type_Float4, "color"},
.global[0] = {THIN_GL_VERTEX_BIT, &u_view_projection_matrix},
.uniform[0] = {ALIAS_GL_FRAGMENT_BIT, alias_gl_Type_float4, "color"},
.global[0] = {ALIAS_GL_VERTEX_BIT, &u_view_projection_matrix},
struct GL_Buffer vertex_buffer = GL_allocate_temporary_buffer(GL_ARRAY_BUFFER, sizeof(float) * 3 * 4 * NUM_BEAM_SEGS);
struct alias_gl_Buffer vertex_buffer = alias_gl_allocateTemporaryBuffer(GL_ARRAY_BUFFER, sizeof(float) * 3 * 4 * NUM_BEAM_SEGS);
void UI_Horizontal(void) { alias_ui_begin_horizontal(frame_ui); }
void UI_Vertical(void) { alias_ui_begin_vertical(frame_ui); }
void UI_End(void) { alias_ui_end(frame_ui); }
void UI_Horizontal(void) { alias_ui_begin_horizontal_stack(frame_ui); }
void UI_Vertical(void) { alias_ui_begin_vertical_stack(frame_ui); }
void UI_End(void) { alias_ui_end_stack(frame_ui); }
void UI_ForceWidth(float w) { alias_ui_override_width(frame_ui, w); }
void UI_ForceHeight(float h) { alias_ui_override_height(frame_ui, h); }
void UI_ForceWidth(float w) { alias_ui_width(frame_ui, w); }
void UI_ForceHeight(float h) { alias_ui_height(frame_ui, h); }
#include <alias/cpp.h>
struct alias_ui_dstack_child {
uint32_t hole;
float weight;
};
struct alias_ui_named_scope {
uint64_t hash;
uint32_t query_capacity;
float *query_rects;
uint32_t slot_capacity;
uint32_t *slot;
};
struct alias_ui_tree_scope {
uint32_t named_scope_index;
uint32_t font_index;
float font_size;
uint32_t font_color;
float weight;
#include <alias/ash.h>
#include <alias/data_structure/vector.h>
#include <alias/log.h>
#include <alias/ui.h>
bool handle_alignment;
float align_x;
float align_y;
union {
struct {
uint32_t hole;
uint32_t num_children;
} stack;
struct {
bool vertical;
uint32_t hole;
uint32_t child_pmark;
uint32_t child_mmark;
float total_weight;
uint32_t children_capacity;
uint32_t children_length;
struct alias_ui_dstack_child *children;
} dstack;
};
// for vsnprintf
#include <stdio.h>
void (*begin_child)(struct alias_ui *, struct alias_ui_tree_scope *);
void (*end_child)(struct alias_ui *, struct alias_ui_tree_scope *);
void (*end_scope)(struct alias_ui *, struct alias_ui_tree_scope *);
void *user_data;
};
// ====================================================================================================================
// structs
#define MAX_SCOPES 32
struct alias_ui {
alias_MemoryCB *mcb;
alias_ui_Input input;
alias_ui_Output *output;
void (*begin_child)(alias_ui *);
void (*end_child)(alias_ui *);
void (*end_scope)(alias_ui *);
void (*align)(alias_ui *, float x, float y);
};
uint32_t memory_capacity;
uint32_t memory_length;
uint32_t *memory;
// ====================================================================================================================
// private functions
static struct scope *_scope(alias_ui *ui) { return ui->scope_index_p1 > 0 ? &ui->scopes[ui->scope_index_p1 - 1] : NULL; }
enum {
P_TERMINATE,
P_EMPTY_FILL,
P_COLOR_FILL,
P_IMAGE,
P_TEXT,
P_BACKGROUND_COLOR,
P_BORDER,
P_STACK,
P_HORIZONTAL_STACK,
P_VERTICAL_STACK,
P_SIZE,
P_WIDTH,
P_HEIGHT,
P_ALIGN,
P_ALIGN_X,
P_ALIGN_Y,
P_PADDING,
P_QUERY,
};
static inline void _begin_child(alias_ui *ui) {
struct scope *s = _scope(ui);
if(s && s->begin_child) {
s->begin_child(ui);
// util ---------------------------------------------------------------------------------------------------------------
static inline bool alias_ui__grow(void **ptr, uint32_t element_size, uint32_t length, uint32_t *capacity) {
uint32_t old_capacity = *capacity;
if(length > old_capacity) {
*capacity = length + 1;
*capacity += *capacity >> 1;
void * new_ptr = alias_realloc(NULL, *ptr, element_size * old_capacity, element_size * *capacity, 4);
if(new_ptr == NULL) {
return false;
}
*ptr = new_ptr;
return true;
}
// tree ---------------------------------------------------------------------------------------------------------------
static inline void alias_ui__tree__space_for(struct alias_ui *ui, uint32_t count) {
alias_ui__grow((void **)&ui->tree_scope, sizeof(*ui->tree_scope), ui->tree_scope_length + count,
&ui->tree_scope_capacity);
static inline void _end_child(alias_ui *ui) {
struct scope *s = _scope(ui);
if(s->end_child) {
s->end_child(ui);
static inline struct alias_ui_tree_scope *alias_ui__tree__top_scope(struct alias_ui *ui) {
assert(ui->tree_scope_length > 0);
return &ui->tree_scope[ui->tree_scope_length - 1];
}
static inline void alias_ui__tree__begin_child(struct alias_ui *ui) {
if(ui->tree_scope_length > 0) {
struct alias_ui_tree_scope *scope = alias_ui__tree__top_scope(ui);
if(scope->begin_child) {
scope->begin_child(ui, scope);
}
static inline void _begin_scope(alias_ui *ui, void (*begin_child)(alias_ui *), void (*end_child)(alias_ui *), void (*end_scope)(alias_ui *)) {
struct scope *p = _scope(ui);
struct scope *s = &ui->scopes[ui->scope_index_p1++];
static inline void alias_ui__tree__end_child(struct alias_ui *ui) {
if(ui->tree_scope_length > 0) {
struct alias_ui_tree_scope *scope = alias_ui__tree__top_scope(ui);
if(scope->end_child) {
scope->end_child(ui, scope);
}
}
}
s->font_size = p ? p->font_size : 10;
s->font_color = p ? p->font_color : alias_Color_WHITE;
s->flex = alias_R_ZERO;
s->total_flex = alias_R_ZERO;
s->begin_child = begin_child;
s->end_child = end_child;
s->end_scope = end_scope;
s->alignment = 0.5f;
s->align = NULL;
static inline void alias_ui__tree__end_scope(struct alias_ui *ui) {
if(ui->tree_scope_length > 0) {
struct alias_ui_tree_scope *scope = alias_ui__tree__top_scope(ui);
ui->tree_scope_length -= 1;
if(scope->end_scope) {
scope->end_scope(ui, scope);
}
}
static inline void _end_scope(alias_ui *ui) {
struct scope *s = _scope(ui);
if(s) {
ui->scope_index_p1--;
if(s->end_scope) {
s->end_scope(ui);
static inline void alias_ui__tree__begin_scope(struct alias_ui *ui,
void (*begin_child)(struct alias_ui *, struct alias_ui_tree_scope *),
void (*end_child)(struct alias_ui *, struct alias_ui_tree_scope *),
void (*end_scope)(struct alias_ui *, struct alias_ui_tree_scope *)) {
alias_ui__tree__space_for(ui, 1);
struct alias_ui_tree_scope *parent_scope = ui->tree_scope_length > 0 ? alias_ui__tree__top_scope(ui) : NULL;
ui->tree_scope_length += 1;
struct alias_ui_tree_scope *scope = alias_ui__tree__top_scope(ui);
if(parent_scope != NULL) {
scope->named_scope_index = parent_scope->named_scope_index;
scope->font_index = parent_scope->font_index;
scope->font_size = parent_scope->font_size;
scope->font_color = parent_scope->font_color;
if(parent_scope->handle_alignment) {
scope->handle_alignment = true;
scope->align_x = parent_scope->align_x;
scope->align_y = parent_scope->align_y;
scope->begin_child = begin_child;
scope->end_child = end_child;
scope->end_scope = end_scope;
}
// program ------------------------------------------------------------------------------------------------------------
static inline void alias_ui__program__space_for(struct alias_ui *ui, uint32_t count) {
alias_ui__grow((void **)&ui->program, sizeof(*ui->program), ui->program_length + count, &ui->program_capacity);
static inline uint32_t _alloc(alias_ui *ui, uint32_t size) {
alias_Vector_space_for(&ui->memory, ui->mcb, size);
uint32_t result = ui->memory.length;
ui->memory.length += size;
static inline void alias_ui__program__initialize(struct alias_ui *ui) {
ui->program_length = 0;
}
static inline uint32_t alias_ui__program__mark(struct alias_ui *ui) {
return ui->program_length;
}
static inline uint32_t alias_ui__program__mark_size(struct alias_ui *ui, uint32_t mark) {
return ui->program_length - mark;
}
static inline void alias_ui__program__reserve(struct alias_ui *ui, uint32_t space) {
alias_ui__program__space_for(ui, space);
ui->program_length += space;
}
static inline uint32_t alias_ui__program__dig(struct alias_ui *ui, uint32_t space) {
uint32_t result = alias_ui__program__mark(ui);
alias_ui__program__reserve(ui, space);
static inline void *_mem(alias_ui *ui, uint32_t position) { return ui->memory.data + position; }
static inline void alias_ui__program__emit_u32(struct alias_ui *ui, uint32_t value) {
alias_ui__program__space_for(ui, 1);
ui->program[ui->program_length++] = value;
}
// ====================================================================================================================
// lifetime
static inline void alias_ui__program__emit_f32(struct alias_ui *ui, float value) {
union {
uint32_t u;
float f;
} flip = {.f = value};
alias_ui__program__emit_u32(ui, flip.u);
}
static void _layout_shape_set_x(alias_ash *ash) {
alias_ui *ui = (alias_ui *)ash->user_data;
uint32_t ptr = alias_ash_pop(ash);
SHAPE(ptr)->x = alias_ash_pop_R(ash);
// ALIAS_TRACE("shape(%i)->x = %g", ptr, SHAPE(ptr)->x);
static inline void alias_ui__program__fill_f32(struct alias_ui *ui, uint32_t hole, float value) {
union {
uint32_t u;
float f;
} flip = {.f = value};
alias_ui__program__fill_u32(ui, hole, flip.u);
static void _layout_shape_set_y(alias_ash *ash) {
alias_ui *ui = (alias_ui *)ash->user_data;
uint32_t ptr = alias_ash_pop(ash);
SHAPE(ptr)->y = alias_ash_pop_R(ash);
// ALIAS_TRACE("shape(%i)->y = %g", ptr, SHAPE(ptr)->y);
// ip -----------------------------------------------------------------------------------------------------------------
static inline void alias_ui__ip__initialize(struct alias_ui *ui) {
ui->ip = ui->program;
}
static inline void alias_ui__ip__advance(struct alias_ui *ui, uint32_t count) {
ui->ip += count;
}
static inline uint32_t alias_ui__ip__read_u32(struct alias_ui *ui) {
return *ui->ip++;
}
static inline float alias_ui__ip__read_f32(struct alias_ui *ui) {
union {
uint32_t u;
float f;
} flip = {.u = alias_ui__ip__read_u32(ui)};
return flip.f;
}
// memory -------------------------------------------------------------------------------------------------------------
static inline void alias_ui__memory__space_for(struct alias_ui *ui, uint32_t count) {
alias_ui__grow((void **)&ui->memory, sizeof(*ui->memory), ui->memory_length + count, &ui->memory_capacity);
}
static inline void alias_ui__memory__initialize(struct alias_ui *ui) {
ui->memory_length = 0;
}
static inline uint32_t alias_ui__memory__mark(struct alias_ui *ui) {
return ui->memory_length;
}
static inline uint32_t alias_ui__memory__mark_size(struct alias_ui *ui, uint32_t mark) {
return ui->memory_length - mark;
}
static inline void alias_ui__memory__reserve(struct alias_ui *ui, uint32_t space) {
alias_ui__memory__space_for(ui, space);
ui->memory_length += space;
static void _layout_shape_set_w(alias_ash *ash) {
alias_ui *ui = (alias_ui *)ash->user_data;
uint32_t ptr = alias_ash_pop(ash);
SHAPE(ptr)->w = alias_ash_pop_R(ash);
// ALIAS_TRACE("shape(%i)->w = %g", ptr, SHAPE(ptr)->w);
static inline uint32_t alias_ui__memory__dig(struct alias_ui *ui, uint32_t space) {
uint32_t result = alias_ui__memory__mark(ui);
alias_ui__memory__reserve(ui, space);
return result;
}
static inline void alias_ui__memory__fill_u32(struct alias_ui *ui, uint32_t hole, uint32_t value) {
assert(hole < ui->memory_length);
ui->memory[hole] = value;
}
static inline void alias_ui__memory__fill_f32(struct alias_ui *ui, uint32_t hole, float value) {
union {
uint32_t u;
float f;
} flip = {.f = value};
alias_ui__memory__fill_u32(ui, hole, flip.u);
}
// float --------------------------------------------------------------------------------------------------------------
static inline float alias_ui__float__min(float a, float b) {
return a < b ? a : b;
}
static inline float alias_ui__float__max(float a, float b) {
return a > b ? a : b;
}
static inline float alias_ui__float__clamp(float x, float min, float max) {
return alias_ui__float__min(alias_ui__float__max(x, min), max);
}
static inline uint8_t alias_ui__float__to_color_channel(float x) {
return (uint8_t)alias_ui__float__clamp(x * 255.0f, 0.0f, 255.0f);
}
static inline uint32_t alias_ui__color__pack(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
return ((uint32_t)r << 24) | ((uint32_t)g << 16) | ((uint32_t)b << 8) | a;
static void _layout_shape_set_h(alias_ash *ash) {
alias_ui *ui = (alias_ui *)ash->user_data;
uint32_t ptr = alias_ash_pop(ash);
SHAPE(ptr)->h = alias_ash_pop_R(ash);
// ALIAS_TRACE("shape(%i)->h = %g", ptr, SHAPE(ptr)->h);
static inline void alias_ui__color__unpack(uint32_t color, uint8_t *r, uint8_t *g, uint8_t *b, uint8_t *a) {
*r = (color >> 24) & 0xFF;
*g = (color >> 16) & 0xFF;
*b = (color >> 8) & 0xFF;
*a = (color >> 0) & 0xFF;
static void _render_shape_get_x(alias_ash *ash) {
alias_ui *ui = (alias_ui *)ash->user_data;
uint32_t ptr = alias_ash_pop(ash);
alias_ash_push_R(ash, SHAPE(ptr)->x);
// ALIAS_TRACE("shape(%i)->x == %g", ptr, SHAPE(ptr)->x);
// mp -----------------------------------------------------------------------------------------------------------------
static inline void alias_ui__mp__initialize(struct alias_ui *ui) {
ui->mp = ui->memory;
static void _render_shape_get_y(alias_ash *ash) {
alias_ui *ui = (alias_ui *)ash->user_data;
uint32_t ptr = alias_ash_pop(ash);
alias_ash_push_R(ash, SHAPE(ptr)->y);
// ALIAS_TRACE("shape(%i)->y == %g", ptr, SHAPE(ptr)->y);
static inline void alias_ui__mp__advance(struct alias_ui *ui, uint32_t count) {
ui->mp += count;
static void _render_shape_get_w(alias_ash *ash) {
alias_ui *ui = (alias_ui *)ash->user_data;
uint32_t ptr = alias_ash_pop(ash);
alias_ash_push_R(ash, SHAPE(ptr)->w);
// ALIAS_TRACE("shape(%i)->w == %g", ptr, SHAPE(ptr)->w);
static inline uint32_t alias_ui__mp__read_u32(struct alias_ui *ui) {
return *ui->mp++;
static void _render_shape_get_h(alias_ash *ash) {
alias_ui *ui = (alias_ui *)ash->user_data;
uint32_t ptr = alias_ash_pop(ash);
alias_ash_push_R(ash, SHAPE(ptr)->h);
// ALIAS_TRACE("shape(%i)->h == %g", ptr, SHAPE(ptr)->h);
static inline float alias_ui__mp__read_f32(struct alias_ui *ui) {
union {
uint32_t u;
float f;
} flip = {.u = alias_ui__mp__read_u32(ui)};
return flip.f;
static void _textv_layout(alias_ash *ash);
static void _textv_render(alias_ash *ash);
// vertex -------------------------------------------------------------------------------------------------------------
static inline void alias_ui__vertex__initialize(struct alias_ui *ui) {
ui->output->num_vertexes = 0;
}
static int _emit_point(alias_ui *ui, float x, float y, float r, float g, float b, float a, float s, float t) {
static inline uint32_t alias_ui__vertex__emit(struct alias_ui *ui, float x, float y, float s, float t, uint8_t r,
uint8_t g, uint8_t b, uint8_t a) {
alias_memory_SubBuffer_write(&ui->output->rgba_sub_buffer, ui->output->num_vertexes, 1, alias_memory_Format_Float32, 0, rgba);
alias_memory_SubBuffer_write(&ui->output->rgba_sub_buffer, ui->output->num_vertexes, 1, alias_memory_Format_Unorm8, 0, rgba);
static void _emit_triangle(alias_ui *ui, int p1, int p2, int p3) {
int p[] = {p1, p2, p3};
alias_memory_SubBuffer_write(&ui->output->index_sub_buffer, ui->output->num_indexes, 3, alias_memory_Format_Sint32, 0, p);
ui->output->num_indexes += 3;
// index --------------------------------------------------------------------------------------------------------------
static inline void alias_ui__index__initialize(struct alias_ui *ui) {
ui->output->num_indexes = 0;
}
static inline uint32_t alias_ui__index__emit(struct alias_ui *ui, uint32_t vertex_index) {
// requires caller to have called alias_ui__index__space_for(ui, N) before
alias_memory_SubBuffer_write(&ui->output->index_sub_buffer, ui->output->num_indexes, 1, alias_memory_Format_Sint32, 0, &vertex_index);
return ui->output->num_indexes++;
}
// group --------------------------------------------------------------------------------------------------------------
static inline void alias_ui__group__initialize(struct alias_ui *ui) {
ui->output->num_groups = 0;
}
static inline struct alias_ui_OutputGroup *alias_ui__group__top(struct alias_ui *ui) {
return &ui->output->groups[ui->groups_length - 1];
}
static inline void alias_ui__group__prepare(struct alias_ui *ui) {
struct alias_ui_OutputGroup *group = alias_ui__group__top(ui);
group->texture_id = ui->texture_id;
group->index = ui->output->num_indexes;
group->length = 0;
void alias_ui_SetTexture(alias_ui *ui, uint32_t texture_id) {
if(ui->output->groups[ui->output->num_groups - 1].texture_id != texture_id) {
if(ui->output->groups[ui->output->num_groups - 1].index != ui->output->num_indexes) {
ui->output->groups[ui->output->num_groups - 1].length = ui->output->num_indexes - ui->output->groups[ui->output->num_groups - 1].index;
ui->output->num_groups++;
}
ui->output->groups[ui->output->num_groups - 1].texture_id = texture_id;
ui->output->groups[ui->output->num_groups - 1].index = ui->output->num_indexes;
static inline void alias_ui__group__finalize(struct alias_ui *ui) {
struct alias_ui_OutputGroup *group = alias_ui__group__top(ui);
group->length = ui->output->num_indexes - group->index;
}
static inline void alias_ui__group__advance(struct alias_ui *ui) {
if(ui->groups_length > 0) {
alias_ui__group__finalize(ui);
static void _set_texture(alias_ash *ash) {
uint32_t texture_id = alias_ash_pop(ash);
alias_ui *ui = (alias_ui *)ash->user_data;
alias_ui_SetTexture(ui, texture_id);
// render -------------------------------------------------------------------------------------------------------------
void alias_ui_set_texture(struct alias_ui *ui, uint32_t texture_id) {
if(ui->texture_id != texture_id) {
ui->texture_id = texture_id;
alias_ui__group__advance(ui);
}
static void _rect_fill_c(alias_ash *ash) {
float a = alias_ash_pop_R(ash);
float b = alias_ash_pop_R(ash);
float g = alias_ash_pop_R(ash);
float r = alias_ash_pop_R(ash);
float h = alias_ash_pop_R(ash);
float w = alias_ash_pop_R(ash);
float y = alias_ash_pop_R(ash);
float x = alias_ash_pop_R(ash);
alias_ui *ui = (alias_ui *)ash->user_data;
int p1 = _emit_point(ui, x, y, r, g, b, a, 0, 0);
int p2 = _emit_point(ui, x + w, y, r, g, b, a, 1, 0);
int p3 = _emit_point(ui, x + w, y + h, r, g, b, a, 1, 1);
int p4 = _emit_point(ui, x, y + h, r, g, b, a, 0, 1);
_emit_triangle(ui, p2, p1, p3);
_emit_triangle(ui, p3, p1, p4);
void alias_ui_draw_rectangle(struct alias_ui *ui, float x, float y, float width, float height,
float s0, float t0, float s1, float t1, uint8_t r, uint8_t g,
uint8_t b, uint8_t a) {
float x0 = x;
float y0 = y;
float x1 = x + width;
float y1 = y + height;
uint32_t A = alias_ui__vertex__emit(ui, x0, y0, s0, t0, r, g, b, a);
uint32_t B = alias_ui__vertex__emit(ui, x0, y1, s0, t1, r, g, b, a);
uint32_t C = alias_ui__vertex__emit(ui, x1, y1, s1, t1, r, g, b, a);
uint32_t D = alias_ui__vertex__emit(ui, x1, y0, s1, t0, r, g, b, a);
alias_ui__index__emit(ui, A);
alias_ui__index__emit(ui, B);
alias_ui__index__emit(ui, C);
alias_ui__index__emit(ui, A);
alias_ui__index__emit(ui, C);
alias_ui__index__emit(ui, D);
static void _rect_fill_st(alias_ash *ash) {
float t1 = alias_ash_pop_R(ash);
float s1 = alias_ash_pop_R(ash);
float t0 = alias_ash_pop_R(ash);
float s0 = alias_ash_pop_R(ash);
float h = alias_ash_pop_R(ash);
float w = alias_ash_pop_R(ash);
float y = alias_ash_pop_R(ash);
float x = alias_ash_pop_R(ash);
alias_ui *ui = (alias_ui *)ash->user_data;
int p1 = _emit_point(ui, x, y, 1, 1, 1, 1, s0, t0);
int p2 = _emit_point(ui, x + w, y, 1, 1, 1, 1, s1, t0);
int p3 = _emit_point(ui, x + w, y + h, 1, 1, 1, 1, s1, t1);
int p4 = _emit_point(ui, x, y + h, 1, 1, 1, 1, s0, t1);
_emit_triangle(ui, p2, p1, p3);
_emit_triangle(ui, p3, p1, p4);
static inline void alias_ui__stats__initialize(alias_ui *ui) {
memset(&ui->stats, 0, sizeof(ui->stats));
ui->stats.texture_id = -1;
}
static inline void alias_ui__stats__set_texture(alias_ui *ui, uint32_t texture_id) {
if(ui->stats.texture_id != texture_id) {
ui->stats.texture_id = texture_id;
ui->stats.num_groups += 1;
}
}
static inline void alias_ui__stats__draw_rectangle(struct alias_ui *ui) {
ui->stats.num_vertexes += 4;
ui->stats.num_indexes += 6;
}
// ====================================================================================================================
static inline void alias_ui__layout(struct alias_ui *, float, float, float, float, float *, float *);
static inline void alias_ui__render(struct alias_ui *, float, float, float, float);
// ====================================================================================================================
// empty fill
// program: r:float, g:float, b:float, a:float
// memory: unused
static void alias_ui__empty_fill__layout(struct alias_ui *ui, float min_width, float max_width, float min_height,
float max_height, float *out_width, float *out_height) {
*out_width = max_width;
*out_height = max_height;
void alias_ui_EmitRect(alias_ui *ui, float x, float y, float w, float h, float s0, float t0, float s1, float t1, float r, float g, float b, float a) {
int p1 = _emit_point(ui, x, y, r, g, b, a, s0, t0);
int p2 = _emit_point(ui, x + w, y, r, g, b, a, s1, t0);
int p3 = _emit_point(ui, x + w, y + h, r, g, b, a, s1, t1);
int p4 = _emit_point(ui, x, y + h, r, g, b, a, s0, t1);
_emit_triangle(ui, p2, p1, p3);
_emit_triangle(ui, p3, p1, p4);
static void alias_ui__empty_fill__render(struct alias_ui *ui, float x, float y, float width, float height) {}
void alias_ui_empty_fill(struct alias_ui *ui) {
alias_ui__tree__begin_child(ui);
alias_ui__program__emit_u32(ui, P_EMPTY_FILL);
alias_ui__tree__end_child(ui);
}
// ====================================================================================================================
// color fill
// program: color:uint32_t
// memory: unused
static void alias_ui__color_fill__layout(struct alias_ui *ui, float min_width, float max_width, float min_height,
float max_height, float *out_width, float *out_height) {
alias_ui__ip__advance(ui, 4);
*out_width = max_width;
*out_height = max_height;
}
static void alias_ui__color_fill__render(struct alias_ui *ui, float x, float y, float width, float height) {
uint32_t color = alias_ui__ip__read_u32(ui);
uint8_t r, g, b, a;
alias_ui__color__unpack(color, &r, &g, &b, &a);
alias_ui_set_texture(ui, 0);
alias_ui_draw_rectangle(ui, x, y, width, height, 0, 0, 1, 1, r, g, b, a);
}
void alias_ui_color_fill(struct alias_ui *ui, float _r, float _g, float _b, float _a) {
alias_ui__tree__begin_child(ui);
alias_ui__program__emit_u32(ui, P_COLOR_FILL);
uint32_t r = alias_ui__float__to_color_channel(_r);
uint32_t g = alias_ui__float__to_color_channel(_g);
uint32_t b = alias_ui__float__to_color_channel(_b);
uint32_t a = alias_ui__float__to_color_channel(_a);
alias_ui__program__emit_u32(ui, alias_ui__color__pack(r, g, b, a));
alias_ui__tree__end_child(ui);
alias_ui__stats__set_texture(ui, 0);
alias_ui__stats__draw_rectangle(ui);
static void _standard_library(alias_ash_Program *program, alias_MemoryCB *mcb) {
ALIAS_ASH_EMIT(program, mcb,
fn(dip // [a] b f([a] -- ?) -- ? b
,
swap, r_push, call, r_pop)
// ====================================================================================================================
// image
// program: texture_id:uint32_t, width:float, height:float, s0:float, t0:float, s1:float, t1:float
static void alias_ui__image__layout(struct alias_ui *ui, float min_width, float max_width, float min_height,
float max_height, float *out_width, float *out_height) {
(void)alias_ui__ip__read_u32(ui);
float width = alias_ui__ip__read_f32(ui);
float height = alias_ui__ip__read_f32(ui);
(void)alias_ui__ip__read_f32(ui);
(void)alias_ui__ip__read_f32(ui);
(void)alias_ui__ip__read_f32(ui);
(void)alias_ui__ip__read_f32(ui);
*out_width = alias_ui__float__clamp(width, min_width, max_width);
*out_height = alias_ui__float__clamp(height, min_height, max_height);
}
,
fn(dip2 // [a] b c f([a] -- ?) -- ? b c
,
rot, r_push, r_push, call, r_pop, r_pop)
static void alias_ui__image__render(struct alias_ui *ui, float x, float y, float width, float height) {
uint32_t texture_id = alias_ui__ip__read_u32(ui);
(void)alias_ui__ip__read_f32(ui);
(void)alias_ui__ip__read_f32(ui);
float s0 = alias_ui__ip__read_f32(ui);
float t0 = alias_ui__ip__read_f32(ui);
float s1 = alias_ui__ip__read_f32(ui);
float t1 = alias_ui__ip__read_f32(ui);
alias_ui_set_texture(ui, texture_id);
alias_ui_draw_rectangle(ui, x, y, width, height, s0, t0, s1, t1, 255, 255, 255, 255);
}
,
fn(keep // [a] b f([a] b -- ?) -- ? b
,
swap, dup, r_push, call, r_pop)
void alias_ui_image(struct alias_ui *ui, float width, float height, float s0, float t0,
float s1, float t1, uint32_t texture_id) {
alias_ui__tree__begin_child(ui);
alias_ui__program__emit_u32(ui, P_IMAGE);
alias_ui__program__emit_u32(ui, texture_id);
alias_ui__program__emit_f32(ui, width);
alias_ui__program__emit_f32(ui, height);
alias_ui__program__emit_f32(ui, s0);
alias_ui__program__emit_f32(ui, t0);
alias_ui__program__emit_f32(ui, s1);
alias_ui__program__emit_f32(ui, t1);
alias_ui__tree__end_child(ui);
alias_ui__stats__set_texture(ui, texture_id);
alias_ui__stats__draw_rectangle(ui);
}
,
fn(f2_zip // a b c d f(x y -- z) -- f(a c) f(b d)
,
r_push // a b c d
,
rot, swap // a b c d -> a c b d
,
r_at, call // a c f(b d)
,
irot // f(b d) a c
,
r_pop, call // f(b d) f(a c)
,
swap)
// ====================================================================================================================
// font
void alias_ui_font_index(struct alias_ui *ui, uint32_t index) {
assert(index < ui->font_length);
assert(ui->tree_scope_length > 0);
alias_ui__tree__top_scope(ui)->font_index = index;
}
,
fn(f2_sub // a b c d -- (a + c) (b + d)
,
(f_sub), f2_zip)
void alias_ui_font_color(struct alias_ui *ui, alias_Color _color) {
assert(ui->tree_scope_length > 0);
uint8_t r = alias_ui__float__to_color_channel(_color.r);
uint8_t g = alias_ui__float__to_color_channel(_color.g);
uint8_t b = alias_ui__float__to_color_channel(_color.b);
uint8_t a = alias_ui__float__to_color_channel(_color.a);
uint32_t color = alias_ui__color__pack(r, g, b, a);
alias_ui__tree__top_scope(ui)->font_color = color;
}
,
fn(f2_min // a b c d -- min(a, c) min(b, d)
,
(f_min), f2_zip)
// ====================================================================================================================
// text
// program: font_index:uint32_t, size:float, color:uint32_t, len:uint32_t, content:[(len + 3) / 4]uint32_t
static void alias_ui__text__layout(struct alias_ui *ui, float min_width, float max_width, float min_height,
float max_height, float *out_width, float *out_height) {
uint32_t font_index = alias_ui__ip__read_u32(ui);
float font_size = alias_ui__ip__read_f32(ui);
(void)alias_ui__ip__read_u32(ui);
uint32_t len = alias_ui__ip__read_u32(ui);
const char *string = (const char *)ui->ip;
alias_ui__ip__advance(ui, (len + 3) >> 2);
struct alias_ui_Font *font = &ui->font[font_index];
uint32_t glyph = 0;
float x = 0;
float y = 0;
float width = 0;
float height = 0;
for(; *string; ) {
uint32_t string_advance;
struct alias_ui_Font_GlyphInfo glyph_info;
struct alias_ui_Font *glyph_font = font;
while(glyph_font != NULL && !glyph_font->decode(glyph_font, string, &glyph, &string_advance, &glyph_info)) {
glyph_font = glyph_font->fallback;
}
,
fn(f2_max // a b c d -- max(a, c) max(b,d)
,
(f_max), f2_zip)
string += string_advance;
float glyph_width = (glyph_info.x + glyph_info.width) * font_size;
float glyph_height = (glyph_info.y + glyph_info.height) * font_size;
width = alias_ui__float__max(width, x + glyph_width);
height = alias_ui__float__max(height, y + glyph_height);
x += glyph_info.advance_x * font_size;
if(glyph_info.newline) {
x = 0;
y += font_size;
}
}
*out_width = alias_ui__float__clamp(width, min_width, max_width);
*out_height = alias_ui__float__clamp(height, min_height, max_height);
,
fn(loose_constraint // w h -- 0 0 w h
,
f(0), dup, swap2));
static void alias_ui__text__render(struct alias_ui *ui, float x, float y, float width, float height) {
uint32_t font_index = alias_ui__ip__read_u32(ui);
float font_size = alias_ui__ip__read_f32(ui);
uint32_t font_color = alias_ui__ip__read_u32(ui);
uint32_t len = alias_ui__ip__read_u32(ui);
const char *string = (const char *)ui->ip;
alias_ui__ip__advance(ui, (len + 3) >> 2);
struct alias_ui_Font *font = &ui->font[font_index];
uint32_t glyph = 0;
float offset_x = 0;
float offset_y = 0;
uint8_t r = (font_color >> 24) & 0xFF;
uint8_t g = (font_color >> 16) & 0xFF;
uint8_t b = (font_color >> 8) & 0xFF;
uint8_t a = (font_color >> 0) & 0xFF;
for(; *string; ) {
uint32_t string_advance;
struct alias_ui_Font_GlyphInfo glyph_info;
struct alias_ui_Font *glyph_font = font;
while(glyph_font != NULL && !glyph_font->decode(glyph_font, string, &glyph, &string_advance, &glyph_info)) {
glyph_font = glyph_font->fallback;
}
string += string_advance;
alias_ui_set_texture(ui, glyph_font->texture_id);
alias_ui_draw_rectangle(ui, x + offset_x + glyph_info.x, y + offset_y + glyph_info.y, glyph_info.width * font_size,
glyph_info.height * font_size, glyph_info.s0, glyph_info.t0, glyph_info.s1, glyph_info.t1, r,
g, b, a);
offset_x += glyph_info.advance_x * font_size;
if(glyph_info.newline) {
offset_x = 0;
offset_y += font_size;
}
}
alias_ui_Result alias_ui_initialize(alias_MemoryCB *mcb, alias_ui **ui_ptr) {
alias_ui *ui = alias_malloc(mcb, sizeof(*ui), alignof(*ui));
if(ui == NULL) {
return alias_ui_ErrorOutOfMemory;
void alias_ui_textv(struct alias_ui *ui, const char *format, va_list ap) {
struct alias_ui_tree_scope *scope = alias_ui__tree__top_scope(ui);
scope->handle_alignment = true;
alias_ui__tree__begin_child(ui);
alias_ui__program__emit_u32(ui, P_TEXT);
alias_ui__program__emit_u32(ui, scope->font_index);
alias_ui__program__emit_f32(ui, scope->font_size);
alias_ui__program__emit_u32(ui, scope->font_color);
va_list ap1, ap2;
va_copy(ap1, ap);
va_copy(ap2, ap);
int size = vcprintf(format, ap1);
va_end(ap1);
alias_ui__program__emit_u32(ui, size);
alias_ui__program__space_for(ui, (size + 3) >> 2);
char *mut_string = (char *)(ui->program + ui->program_length);
vsprintf(mut_string, size + 1, format, ap2);
va_end(ap2);
ui->program_length += (size + 3) >> 2;
alias_ui__tree__end_child(ui);
// fix this?
uint32_t string_advance;
uint32_t font_index = scope->font_index;
const char * string = mut_string;
struct alias_ui_Font *font = &ui->font[font_index];
uint32_t glyph = 0;
for(; *string; ) {
struct alias_ui_Font_GlyphInfo glyph_info;
struct alias_ui_Font *glyph_font = font;
while(glyph_font != NULL && !glyph_font->decode(glyph_font, string, &glyph, &string_advance, &glyph_info)) {
glyph_font = glyph_font->fallback;
}
string += string_advance;
alias_ui__stats__set_texture(ui, glyph_font->texture_id);
alias_ui__stats__draw_rectangle(ui);
alias_ash_Program_initialize(&ui->layout_program);
alias_ash_Program_begin_library(&ui->layout_program, mcb);
alias_ash_Program_define_cfun(&ui->layout_program, mcb, "setx", _layout_shape_set_x);
alias_ash_Program_define_cfun(&ui->layout_program, mcb, "sety", _layout_shape_set_y);
alias_ash_Program_define_cfun(&ui->layout_program, mcb, "setw", _layout_shape_set_w);
alias_ash_Program_define_cfun(&ui->layout_program, mcb, "seth", _layout_shape_set_h);
alias_ash_Program_define_cfun(&ui->layout_program, mcb, "textv_layout", _textv_layout);
_standard_library(&ui->layout_program, mcb);
alias_ash_Program_end_library(&ui->layout_program);
// ====================================================================================================================
// background color
// program: color:uint32_t
static inline void alias_ui__background_color__begin_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
}
alias_ash_Program_initialize(&ui->render_program);
alias_ash_Program_begin_library(&ui->render_program, mcb);
alias_ash_Program_define_cfun(&ui->render_program, mcb, "getx", _render_shape_get_x);
alias_ash_Program_define_cfun(&ui->render_program, mcb, "gety", _render_shape_get_y);
alias_ash_Program_define_cfun(&ui->render_program, mcb, "getw", _render_shape_get_w);
alias_ash_Program_define_cfun(&ui->render_program, mcb, "geth", _render_shape_get_h);
alias_ash_Program_define_cfun(&ui->render_program, mcb, "textv_render", _textv_render);
alias_ash_Program_define_cfun(&ui->render_program, mcb, "set_texture", _set_texture);
alias_ash_Program_define_cfun(&ui->render_program, mcb, "rect_fill_c", _rect_fill_c);
alias_ash_Program_define_cfun(&ui->render_program, mcb, "rect_fill_st", _rect_fill_st);
_standard_library(&ui->render_program, mcb);
alias_ash_Program_end_library(&ui->render_program);
static inline void alias_ui__background_color__end_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
alias_ui__tree__end_scope(ui);
}
*ui_ptr = ui;
return alias_ui_Success;
static inline void alias_ui__background_color__layout(struct alias_ui *ui, float min_width, float max_width,
float min_height, float max_height, float *out_width,
float *out_height) {
(void)alias_ui__ip__read_u32(ui);
alias_ui__layout(ui, min_width, max_width, min_height, max_height, out_width, out_height);
alias_ui_Result alias_ui_free(alias_ui *ui, alias_MemoryCB *mcb) {
(void)ui;
(void)mcb;
static inline void alias_ui__background_color__render(struct alias_ui *ui, float x, float y, float width,
float height) {
uint32_t color = alias_ui__ip__read_u32(ui);
uint8_t r, g, b, a;
alias_ui__color__unpack(color, &r, &g, &b, &a);
alias_ui_set_texture(ui, 0);
alias_ui_draw_rectangle(ui, x, y, width, height, 0, 0, 0, 0, r, g, b, a);
alias_ui__render(ui, x, y, width, height);
}
return alias_ui_Success;
void alias_ui_background_color(struct alias_ui *ui, float r, float g, float b, float a) {
alias_ui__tree__begin_child(ui);
alias_ui__tree__begin_scope(ui, alias_ui__background_color__begin_child, alias_ui__background_color__end_child,
alias_ui__background_color__end_scope);
uint32_t color =
alias_ui__color__pack(alias_ui__float__to_color_channel(r), alias_ui__float__to_color_channel(g),
alias_ui__float__to_color_channel(b), alias_ui__float__to_color_channel(a));
alias_ui__program__emit_u32(ui, P_BACKGROUND_COLOR);
alias_ui__program__emit_u32(ui, color);
// frame (begin)
alias_ui_Result alias_ui_begin_frame(alias_ui *ui, alias_MemoryCB *mcb, const alias_ui_Input *input) {
ui->mcb = mcb;
// border
// program: color:uint32_t
static inline void alias_ui__border__begin_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {}
alias_ash_Program_begin_shader(&ui->layout_program, mcb);
alias_ash_Program_begin_shader(&ui->render_program, mcb);
alias_Vector_clear(&ui->memory);
static inline void alias_ui__border__end_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
alias_ui__tree__end_scope(ui);
}
// -- minw minh maxw maxh
alias_ash_Program *lp = &ui->layout_program;
ALIAS_ASH_EMIT(lp, ui->mcb, f(input->screen_size.width), f(input->screen_size.height), dup2);
static inline void alias_ui__border__end_scope(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
alias_ui__tree__end_child(ui);
}
// -- minw minh maxw maxh
ALIAS_ASH_EMIT(&ui->render_program, ui->mcb, f(0), dup, f(input->screen_size.width), f(input->screen_size.height));
static inline void alias_ui__border__layout(struct alias_ui *ui, float min_width, float max_width, float min_height,
float max_height, float *out_width, float *out_height) {
float size = alias_ui__ip__read_f32(ui);
(void)alias_ui__ip__read_u32(ui);
float child_width;
float child_height;
alias_ui__layout(ui, min_width, max_width, min_height, max_height, &child_width, &child_height);
child_width += size * 2;
child_height += size * 2;
*out_width = alias_ui__float__clamp(child_width, min_width, max_width);
*out_height = alias_ui__float__clamp(child_height, min_height, max_height);
}
ui->scope_index_p1 = 0;
_begin_scope(ui, NULL, NULL, NULL);
static inline void alias_ui__border__render(struct alias_ui *ui, float x, float y, float width, float height) {
uint32_t color = alias_ui__ip__read_u32(ui);
uint8_t r, g, b, a;
alias_ui__color__unpack(color, &r, &g, &b, &a);
alias_ui_set_texture(ui, 0);
alias_ui_draw_rectangle(ui, x, y, width, height, 0, 0, 0, 0, r, g, b, a);
alias_ui__render(ui, x, y, width, height);
}
ui->text_size = input->text_size;
ui->text_draw = input->text_draw;
ui->max_num_groups = 0;
ui->max_num_indexes = 0;
ui->max_num_vertexes = 0;
return alias_ui_Success;
void alias_ui_border(struct alias_ui *ui, float size, float r, float g, float b, float a) {
alias_ui__tree__begin_child(ui);
alias_ui__tree__begin_scope(ui, alias_ui__background_color__begin_child, alias_ui__background_color__end_child,
alias_ui__background_color__end_scope);
uint32_t color =
alias_ui__color__pack(alias_ui__float__to_color_channel(r), alias_ui__float__to_color_channel(g),
alias_ui__float__to_color_channel(b), alias_ui__float__to_color_channel(a));
alias_ui__program__emit_u32(ui, P_BORDER);
alias_ui__program__emit_f32(ui, size);
alias_ui__program__emit_u32(ui, color);
// align fractions (center)
static inline void _align_fractions_end_child(alias_ui *ui) {
struct scope *scope = _scope(ui);
uint32_t shape = scope->shape;
// stack
// program: len:uint32_t, [len]child
// memory: [len](width:float, height:float, child)
static inline void alias_ui__stack__begin_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
scope->stack.num_children += 1;
}
ALIAS_ASH_EMIT(&ui->layout_program,
ui->mcb
// end child: maxw maxh childw childh -- maxw maxh
,
over2 // a b c d a b
,
over2 // a b c d a b c d
//, ( f_sub, f(0.5), f_mul ), f2_zip // a b c d e f -- (max - child) * 0.5
,
rot, swap, f_sub, f(scope->args[1]), f_mul, irot, f_sub, f(scope->args[0]), f_mul, swap, i(shape), sety // a b c d e
,
i(shape), setx // a b c d
,
i(shape), seth // a b c
,
i(shape), setw // a b
static inline void alias_ui__stack__end_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {}
// end self: maxw maxh -- w h
/* nothing, our size is max size */
);
static inline void alias_ui__stack__end_scope(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
alias_ui__program__fill_u32(ui, scope->stack.hole, scope->stack.num_children);
alias_ui__tree__end_child(ui);
}
_end_scope(ui);
_end_child(ui);
static inline void alias_ui__stack__layout(struct alias_ui *ui, float min_width, float max_width, float min_height,
float max_height, float *out_width, float *out_height) {
float max_child_width = min_width;
float max_child_height = min_height;
uint32_t len = alias_ui__ip__read_u32(ui);
for(uint32_t i = 0; i < len; i++) {
uint32_t hole = alias_ui__memory__dig(ui, 2);
float child_width;
float child_height;
alias_ui__layout(ui, min_width, max_width, min_height, max_height, &child_width, &child_height);
alias_ui__memory__fill_f32(ui, hole + 0, child_width);
alias_ui__memory__fill_f32(ui, hole + 1, child_height);
max_child_width = alias_ui__float__max(max_child_width, child_width);
max_child_height = alias_ui__float__max(max_child_height, child_height);
}
*out_width = alias_ui__float__min(max_child_width, max_width);
*out_height = alias_ui__float__min(max_child_height, max_height);
void alias_ui_align_fractions(alias_ui *ui, float x, float y) {
if(_scope(ui)->align != NULL) {
_scope(ui)->align(ui, x, y);
return;
static inline void alias_ui__stack__render(struct alias_ui *ui, float x, float y, float width, float height) {
uint32_t len = alias_ui__ip__read_u32(ui);
for(uint32_t i = 0; i < len; i++) {
float child_width = alias_ui__mp__read_f32(ui);
float child_height = alias_ui__mp__read_f32(ui);
alias_ui__render(ui, x, y, child_width, child_height);
_begin_child(ui);
_begin_scope(ui, NULL, _align_fractions_end_child, NULL);
void alias_ui_begin_stack(struct alias_ui *ui) {
alias_ui__tree__begin_child(ui);
alias_ui__tree__begin_scope(ui, alias_ui__stack__begin_child, alias_ui__stack__end_child,
alias_ui__stack__end_scope);
alias_ui__program__emit_u32(ui, P_STACK);
struct alias_ui_tree_scope *scope = alias_ui__tree__top_scope(ui);
scope->stack.hole = alias_ui__program__dig(ui, 1);
}
struct scope *scope = _scope(ui);
// ====================================================================================================================
// directional stack
// program: len:uint32_t, [len](isize:uint32_t, msize:uint32_t, weight:float, align:float, child)
// memory: [len](width:float, height:float, child)
static inline void alias_ui__dstack__space_for(struct alias_ui *ui, uint32_t count) {
struct alias_ui_tree_scope *scope = alias_ui__tree__top_scope(ui);
alias_ui__grow((void **)&scope->dstack.children, sizeof(*scope->dstack.children),
scope->dstack.children_length + count, &scope->dstack.children_capacity);
}
uint32_t shape = _alloc(ui, sizeof(struct shape));
scope->shape = shape;
scope->args[0] = x;
scope->args[1] = y;
static inline void alias_ui__dstack__begin_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
scope->dstack.child_pmark = alias_ui__program__mark(ui);
scope->dstack.child_mmark = alias_ui__memory__mark(ui);
alias_ui__dstack__space_for(ui, 1);
scope->dstack.children_length += 1;
struct alias_ui_dstack_child *child = &scope->dstack.children[scope->dstack.children_length - 1];
child->hole = alias_ui__program__dig(ui, 3);
child->weight = alias_ui__float__max(scope->weight, 0);
scope->dstack.total_weight += child->weight;
alias_ui__program__emit_f32(ui, scope->dstack.vertical ? scope->align_x : scope->align_y);
alias_ui__memory__reserve(ui, 2);
scope->weight = 0;
scope->align_x = 0.5;
scope->align_y = 0.5;
}
ALIAS_ASH_EMIT(&ui->layout_program,
ui->mcb
// setup: minw minh maxw maxh -- maxw maxh
,
swap2,
drop2
static inline void alias_ui__dstack__end_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
uint32_t psize = alias_ui__program__mark_size(ui, scope->dstack.child_pmark);
uint32_t msize = alias_ui__memory__mark_size(ui, scope->dstack.child_mmark);
struct alias_ui_dstack_child *child = &scope->dstack.children[scope->dstack.children_length - 1];
alias_ui__program__fill_u32(ui, child->hole + 0, psize);
alias_ui__program__fill_u32(ui, child->hole + 1, msize);
}
// begin child: maxw maxh -- maxw maxh 0 0 maxw maxh
,
dup2, loose_constraint);
static inline void alias_ui__dstack__end_scope(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
alias_ui__program__fill_u32(ui, scope->dstack.hole, scope->dstack.children_length);
ALIAS_ASH_EMIT(&ui->render_program,
ui->mcb
// setup: x y w h -- cx cy cw ch
,
drop2 // a b c d -> a b
,
i(shape), getx // a b e
,
i(shape), gety // a b e f
,
f2_add // e f
,
i(shape), getw // e f g h
,
i(shape), geth // e f g h
);
for(uint32_t i = 0; i < scope->dstack.children_length; i++) {
struct alias_ui_dstack_child *child = &scope->dstack.children[i];
alias_ui__program__fill_f32(ui, child->hole + 2, child->weight / scope->dstack.total_weight);
}
alias_free(ui->mcb, scope->dstack.children, sizeof(*scope->dstack.children) * scope->dstack.children_capacity, 4);
alias_ui__tree__end_child(ui);
// ====================================================================================================================
// override size
// state: w h
static inline void _override_size_end_child(alias_ui *ui) {
// w h childw childh -- w h
ALIAS_ASH_EMIT(&ui->layout_program, ui->mcb, drop2);
static inline void alias_ui__dstack__create(struct alias_ui *ui, bool vertical) {
alias_ui__tree__begin_child(ui);
alias_ui__tree__begin_scope(ui, alias_ui__dstack__begin_child, alias_ui__dstack__end_child,
alias_ui__dstack__end_scope);
alias_ui__program__emit_u32(ui, vertical ? P_VERTICAL_STACK : P_HORIZONTAL_STACK);
struct alias_ui_tree_scope *scope = alias_ui__tree__top_scope(ui);
scope->handle_alignment = true;
scope->align_x = 0.5;
scope->align_y = 0.5;
scope->dstack.vertical = vertical;
scope->dstack.hole = alias_ui__program__dig(ui, 1);
scope->dstack.total_weight = 0;
scope->dstack.children_capacity = 0;
scope->dstack.children_length = 0;
scope->dstack.children = NULL;
}
_end_scope(ui);
_end_child(ui);
static inline void alias_ui__dstack__layout(struct alias_ui *ui, bool vertical, float min_width, float max_width,
float min_height, float max_height, float *out_width, float *out_height) {
uint32_t len = alias_ui__ip__read_u32(ui);
uint32_t *prepass_ip = ui->ip;
float max_child_width = min_width;
float max_child_height = min_height;
for(uint32_t pass = 0; pass < 2; pass++) {
ui->ip = prepass_ip;
for(uint32_t i = 0; i < len; i++) {
uint32_t psize = alias_ui__ip__read_u32(ui);
uint32_t msize = alias_ui__ip__read_u32(ui);
float weight = alias_ui__ip__read_f32(ui);
if(pass != (weight > 0 ? 1 : 0)) {
alias_ui__ip__advance(ui, psize - 3);
alias_ui__mp__advance(ui, msize);
continue;
}
(void)alias_ui__ip__read_f32(ui);
float child_width;
float child_height;
uint32_t mhole = alias_ui__memory__dig(ui, 2);
alias_ui__layout(ui, min_width, max_width, min_height, max_height, &child_width, &child_height);
if(pass == 1) {
if(!vertical) {
child_width = weight * max_width;
} else {
child_height = weight * max_height;
}
}
alias_ui__memory__fill_f32(ui, mhole + 0, child_width);
alias_ui__memory__fill_f32(ui, mhole + 1, child_height);
max_child_width = alias_ui__float__max(max_child_width, child_width);
max_child_height = alias_ui__float__max(max_child_height, child_height);
if(pass == 0) {
if(vertical) {
min_height = alias_ui__float__max(min_height - child_height, 0);
max_height = alias_ui__float__max(max_height - child_height, 0);
} else {
min_width = alias_ui__float__max(min_width - child_width, 0);
max_width = alias_ui__float__max(max_width - child_width, 0);
}
}
}
}
*out_width = alias_ui__float__min(max_width, max_child_width);
*out_height = alias_ui__float__min(max_height, max_child_height);
void alias_ui_override_size(alias_ui *ui, alias_R width, alias_R height) {
_begin_child(ui);
_begin_scope(ui, NULL, _override_size_end_child, NULL);
static inline void alias_ui__dstack__render(struct alias_ui *ui, bool vertical, float x, float y, float width,
float height) {
uint32_t len = alias_ui__ip__read_u32(ui);
for(uint32_t i = 0; i < len; i++) {
(void)alias_ui__ip__read_u32(ui);
(void)alias_ui__ip__read_u32(ui);
(void)alias_ui__ip__read_f32(ui);
float align = alias_ui__ip__read_f32(ui);
float child_width = alias_ui__mp__read_f32(ui);
float child_height = alias_ui__mp__read_f32(ui);
alias_ui__render(ui, vertical ? x + alias_ui__float__max(width - child_width, 0) * align : x,
vertical ? y : y + alias_ui__float__max(height - child_height, 0) * align, child_width,
child_height);
if(!vertical) {
x += child_width;
} else {
y += child_height;
}
}
}
// override width
// state: w
static inline void _override_width_end_child(alias_ui *ui) {
// w childw childh -- w childh
ALIAS_ASH_EMIT(&ui->layout_program, ui->mcb, nip);
void alias_ui_stack_weight(struct alias_ui *ui, float weight) {
alias_ui__tree__top_scope(ui)->weight = weight;
}
void alias_ui_override_width(alias_ui *ui, alias_R width) {
_begin_child(ui);
_begin_scope(ui, NULL, _override_width_end_child, NULL);
// ====================================================================================================================
// named scope
// program: child
// memory: child
static inline void alias_ui__named_scope__begin_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {}
ALIAS_ASH_EMIT(&ui->layout_program, ui->mcb,
// setup: minw minh maxw maxh -- minh maxh w
// begin child: minh maxh w -- w 0 minh w maxh
// setup and begin child: minw minh maxw maxh -- w 0 minh w maxh
(nip, f(0), swap, f(width), irot), dip2, nip, f(width), swap);
static inline void alias_ui__named_scope__end_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
alias_ui__tree__end_scope(ui);
}
static inline void alias_ui__named_scope__end_scope(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
alias_ui__tree__end_child(ui);
}
void alias_ui_named_scope(struct alias_ui *ui, const char *format, ...) {
alias_ui__tree__begin_child(ui);
alias_ui__tree__begin_scope(ui, alias_ui__named_scope__begin_child, alias_ui__named_scope__end_child,
alias_ui__named_scope__end_scope);
struct alias_ui_tree_scope *scope = alias_ui__tree__top_scope(ui);
va_list ap;
va_start(ap, format);
int size = vcprintf(format, ap);
va_end(ap);
char *buffer = alloca(size + 1);
va_start(ap, format);
vsprintf(buffer, size + 1, format, ap);
va_end(ap);
uint64_t hash =
0xCBF29CE484222325ul ^
(scope->named_scope_index < ui->named_scope_length ? ui->named_scope[scope->named_scope_index].hash : 0);
while(*buffer) {
hash ^= *buffer++;
hash *= 0x00000100000001B3ul;
}
for(uint32_t i = 0; i < ui->named_scope_length; i++) {
if(ui->named_scope[i].hash == hash) {
scope->named_scope_index = i;
return;
}
}
alias_ui__grow((void **)&ui->named_scope, sizeof(*ui->named_scope), ui->named_scope_length + 1,
&ui->named_scope_capacity);
ui->named_scope[ui->named_scope_length].hash = hash;
ui->named_scope[ui->named_scope_length].query_capacity = 0;
ui->named_scope[ui->named_scope_length].query_rects = NULL;
ui->named_scope[ui->named_scope_length].slot_capacity = 0;
ui->named_scope[ui->named_scope_length].slot = NULL;
scope->named_scope_index = ui->named_scope_length++;
// override height
// state: h
static inline void _override_height_end_child(alias_ui *ui) {
// h childw childh -- childw h
ALIAS_ASH_EMIT(&ui->layout_program, ui->mcb, drop, swap);
void alias_ui_set_uint32(struct alias_ui *ui, uint32_t slot_index, uint32_t value) {
struct alias_ui_tree_scope *scope = alias_ui__tree__top_scope(ui);
struct alias_ui_named_scope *named_scope = &ui->named_scope[scope->named_scope_index];
alias_ui__grow((void **)&named_scope->slot, sizeof(*named_scope->slot), slot_index, &named_scope->slot_capacity);
named_scope->slot[slot_index] = value;
}
void alias_ui_override_height(alias_ui *ui, alias_R height) {
_begin_child(ui);
_begin_scope(ui, NULL, _override_height_end_child, NULL);
uint32_t alias_ui_get_uint32(struct alias_ui *ui, uint32_t slot_index) {
struct alias_ui_tree_scope *scope = alias_ui__tree__top_scope(ui);
struct alias_ui_named_scope *named_scope = &ui->named_scope[scope->named_scope_index];
if(slot_index < named_scope->slot_capacity) {
return named_scope->slot[slot_index];
} else {
return 0;
}
}
ALIAS_ASH_EMIT(&ui->layout_program, ui->mcb,
// setup: minw minh maxw maxh -- minw maxw h
// begin child: minw maxw h -- h minw 0 maxw h
// setup and begin child: minw minh maxw maxh -- h minw 0 maxw h
drop, (drop, f(height), swap, f(0)), dip, f(height));
float alias_ui_get_float(struct alias_ui *ui, uint32_t slot_index) {
union {
uint32_t u;
float f;
} flip = {.u = alias_ui_get_uint32(ui, slot_index)};
return flip.f;
// vertical layout
static inline void _vertical_begin_child(alias_ui *ui) {
int shape = _alloc(ui, sizeof(struct shape));
_scope(ui)->shape = shape;
// size
// program: width:float, height:float, child
// memory: child
static inline void alias_ui__size__begin_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {}
ALIAS_ASH_EMIT(&ui->layout_program, ui->mcb,
// minw minh maxw maxh w h -- minw minh maxw maxh w h minw minh maxw maxh-h
i(5), pick, i(5), pick, i(5), pick, i(5), pick, i(4), pick, f_sub);
static inline void alias_ui__size__end_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
alias_ui__tree__end_scope(ui);
}
ALIAS_ASH_EMIT(&ui->render_program, ui->mcb,
// x y w h -- x y w h (x+(w-cw)/2) (y+cy) cw ch
i(3), pick, // x y w h x
f(_scope(ui)->alignment), // x y w h x 0.5
i(3), pick, // x y w h x 0.5 w
i(shape), getw, // x y w h x 0.5 w cw
f_sub, f_mul, f_add, // x y w h cx
i(3), pick, // x y w h cx y
i(shape), gety, // x y w h cx y cy
f_add, i(shape), getw, i(shape), geth);
static inline void alias_ui__size__end_scope(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
alias_ui__tree__end_child(ui);
}
_scope(ui)->alignment = 0.5f;
static inline void alias_ui__size__layout(struct alias_ui *ui, float min_width, float max_width, float min_height,
float max_height, float *out_width, float *out_height) {
float width = alias_ui__ip__read_f32(ui);
float height = alias_ui__ip__read_f32(ui);
float unused_width;
float unused_height;
alias_ui__layout(ui, width, width, height, height, &unused_width, &unused_height);
*out_width = alias_ui__float__clamp(width, min_width, max_width);
*out_height = alias_ui__float__clamp(height, min_height, max_height);
}
static inline void alias_ui__size__render(struct alias_ui *ui, float x, float y, float width, float height) {
(void)alias_ui__ip__read_f32(ui);
(void)alias_ui__ip__read_f32(ui);
alias_ui__render(ui, x, y, width, height);
}
void alias_ui_size(struct alias_ui *ui, float width, float height) {
alias_ui__tree__begin_child(ui);
alias_ui__tree__begin_scope(ui, alias_ui__size__begin_child, alias_ui__size__end_child,
alias_ui__size__end_scope);
alias_ui__program__emit_u32(ui, P_SIZE);
alias_ui__program__emit_f32(ui, width);
alias_ui__program__emit_f32(ui, height);
static inline void _vertical_end_child(alias_ui *ui) {
int shape = _scope(ui)->shape;
// ====================================================================================================================
// width
// program: width:float, child
// memory: child
static inline void alias_ui__width__begin_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {}
static inline void alias_ui__width__end_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
alias_ui__tree__end_scope(ui);
}
static inline void alias_ui__width__end_scope(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
alias_ui__tree__end_child(ui);
}
static inline void alias_ui__width__layout(struct alias_ui *ui, float min_width, float max_width, float min_height,
float max_height, float *out_width, float *out_height) {
float width = alias_ui__ip__read_f32(ui);
float unused_width;
float height;
alias_ui__layout(ui, width, width, min_height, max_height, &unused_width, &height);
*out_width = alias_ui__float__clamp(width, min_width, max_width);
*out_height = alias_ui__float__clamp(height, min_height, max_height);
}
ALIAS_ASH_EMIT(&ui->layout_program, ui->mcb,
// minw minh maxw maxh w h childw childh -- minw minh maxw maxh max(w childw) (h + childh)
dup, i(shape), seth, // a b maxw maxh w h childw childh
swap, dup, i(shape), setw, // a b maxw maxh w h childh childw
r_push, // a b maxw maxh w h childh
over, i(shape), sety, // a b maxw maxh w h childh (copy current h to y)
f_add, // a b maxw maxh w (h + childh)
swap, r_pop, // a b maxw maxh (h + childh) w childw
f_max, swap // a b maxw maxh max(w childw) (h + childh)
);
static inline void alias_ui__width__render(struct alias_ui *ui, float x, float y, float width, float height) {
(void)alias_ui__ip__read_f32(ui);
alias_ui__render(ui, x, y, width, height);
static inline void _vertical_end_scope(alias_ui *ui) {
ALIAS_ASH_EMIT(&ui->layout_program, ui->mcb,
// minw minh maxw maxh max(childw) sum(childh) -- w h
fit);
void alias_ui_width(struct alias_ui *ui, float width) {
alias_ui__tree__begin_child(ui);
alias_ui__tree__begin_scope(ui, alias_ui__width__begin_child, alias_ui__width__end_child,
alias_ui__width__end_scope);
alias_ui__program__emit_u32(ui, P_WIDTH);
alias_ui__program__emit_f32(ui, width);
}
ALIAS_ASH_EMIT(&ui->render_program, ui->mcb,
// x y w h --
drop2, drop2);
// ====================================================================================================================
// height
// program: height:float, child
// memory: child
static inline void alias_ui__height__begin_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {}
static inline void _vertical_align(alias_ui *ui, float x, float y) {
(void)y;
_scope(ui)->alignment = x;
static inline void alias_ui__height__end_scope(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
alias_ui__tree__end_child(ui);
void alias_ui_begin_vertical(alias_ui *ui) {
_begin_child(ui);
_begin_scope(ui, _vertical_begin_child, _vertical_end_child, _vertical_end_scope);
static inline void alias_ui__height__layout(struct alias_ui *ui, float min_width, float max_width, float min_height,
float max_height, float *out_width, float *out_height) {
float height = alias_ui__ip__read_f32(ui);
float width;
float unused_height;
alias_ui__layout(ui, min_width, max_width, height, height, &width, &unused_height);
*out_width = alias_ui__float__clamp(width, min_width, max_width);
*out_height = alias_ui__float__clamp(height, min_height, max_height);
}
_scope(ui)->align = _vertical_align;
_scope(ui)->alignment = 0.5f;
static inline void alias_ui__height__render(struct alias_ui *ui, float x, float y, float width, float height) {
(void)alias_ui__ip__read_f32(ui);
alias_ui__render(ui, x, y, width, height);
}
ALIAS_ASH_EMIT(&ui->layout_program, ui->mcb,
// setup: minw minh maxw maxh -- minw minh maxw maxh 0 0 (current width, height)
i(0), dup);
void alias_ui_height(struct alias_ui *ui, float height) {
alias_ui__tree__begin_child(ui);
alias_ui__tree__begin_scope(ui, alias_ui__height__begin_child, alias_ui__height__end_child,
alias_ui__height__end_scope);
alias_ui__program__emit_u32(ui, P_HEIGHT);
alias_ui__program__emit_f32(ui, height);
// horizontal layout
static inline void _horizontal_begin_child(alias_ui *ui) {
int shape = _alloc(ui, sizeof(struct shape));
_scope(ui)->shape = shape;
// align
// program: x:float, y:float, child
// memory: width:float, height:float, child
static inline void alias_ui__align__begin_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
alias_ui__memory__reserve(ui, 2);
}
ALIAS_ASH_EMIT(&ui->layout_program,
ui->mcb
// minw minh maxw maxh w h -- minw minh maxw maxh w h minw minh maxw-w maxh
,
i(5), pick, i(5), pick, i(5), pick, i(4), pick, f_sub, i(5), pick);
static inline void alias_ui__align__end_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
alias_ui__tree__end_scope(ui);
}
ALIAS_ASH_EMIT(&ui->render_program,
ui->mcb
// x y w h -- x y w h (x+cx) (y+(h-ch)/2) cw ch
,
i(3), pick // x y w h x
,
i(shape), getx // x y w h x cx
,
f_add // x y w h cx
,
i(3), pick // x y w h cx y
,
f(_scope(ui)->alignment) // x y w h cx y 0.5
,
i(3), pick // x y w h cx y 0.5 h
,
i(shape), geth // x y w h cx y 0.5 h ch
,
f_sub, f_mul, f_add // x y w h cx cy
,
i(shape), getw, i(shape), geth);
static inline void alias_ui__align__end_scope(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
alias_ui__tree__end_child(ui);
}
_scope(ui)->alignment = 0.5f;
static inline void alias_ui__align__layout(struct alias_ui *ui, float min_width, float max_width, float min_height,
float max_height, float *out_width, float *out_height) {
(void)alias_ui__ip__read_f32(ui);
(void)alias_ui__ip__read_f32(ui);
float width;
float height;
uint32_t mhole = alias_ui__memory__dig(ui, 2);
alias_ui__layout(ui, min_width, max_width, min_height, max_height, &width, &height);
alias_ui__memory__fill_f32(ui, mhole + 0, width);
alias_ui__memory__fill_f32(ui, mhole + 1, height);
*out_width = max_width;
*out_height = max_height;
static inline void _horizontal_end_child(alias_ui *ui) {
int shape = _scope(ui)->shape;
static inline void alias_ui__align__render(struct alias_ui *ui, float x, float y, float width, float height) {
float align_x = alias_ui__ip__read_f32(ui);
float align_y = alias_ui__ip__read_f32(ui);
float child_width = alias_ui__mp__read_f32(ui);
float child_height = alias_ui__mp__read_f32(ui);
alias_ui__render(ui, x + (width - child_width) * align_x, y + (height - child_height) * align_y, child_width,
child_height);
}
ALIAS_ASH_EMIT(&ui->layout_program,
ui->mcb
// minw minh maxw maxh w h childw childh -- minw minh maxw maxh max(w childw) (h + childh)
,
dup, i(shape), seth // a b maxw maxh w h childw childh
,
swap, dup, i(shape), setw // a b maxw maxh w h childh childw
,
r_push // a b maxw maxh w h childh
,
i(2), pick, i(shape), setx // a b maxw maxh w h childh (copy current w to x)
,
f_max // a b maxw maxh w max(h childh)
,
swap, r_pop // a b maxw maxh max(h childh) w childw
,
f_add, swap // a b maxw maxh (w + childw) max(h childh)
);
void alias_ui_align(struct alias_ui *ui, float x, float y) {
alias_ui__tree__begin_child(ui);
alias_ui__tree__begin_scope(ui, alias_ui__align__begin_child, alias_ui__align__end_child,
alias_ui__align__end_scope);
alias_ui__program__emit_u32(ui, P_ALIGN);
alias_ui__program__emit_f32(ui, x);
alias_ui__program__emit_f32(ui, y);
}
// ====================================================================================================================
// alignx
// program: x:float, child
// memory: width:float, child
static inline void alias_ui__alignx__begin_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
alias_ui__memory__reserve(ui, 1);
}
static inline void alias_ui__alignx__end_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
alias_ui__tree__end_scope(ui);
}
static inline void alias_ui__alignx__end_scope(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
alias_ui__tree__end_child(ui);
}
static inline void alias_ui__alignx__layout(struct alias_ui *ui, float min_width, float max_width, float min_height,
float max_height, float *out_width, float *out_height) {
(void)alias_ui__ip__read_f32(ui);
float width;
float height;
uint32_t mhole = alias_ui__memory__dig(ui, 1);
alias_ui__layout(ui, min_width, max_width, min_height, max_height, &width, &height);
alias_ui__memory__fill_f32(ui, mhole, width);
*out_width = max_width;
*out_height = alias_ui__float__clamp(height, min_height, min_height);
}
static inline void alias_ui__alignx__render(struct alias_ui *ui, float x, float y, float width, float height) {
float align_x = alias_ui__ip__read_f32(ui);
float child_width = alias_ui__mp__read_f32(ui);
alias_ui__render(ui, x + (width - child_width) * align_x, y, child_width, height);
static inline void _horizontal_end_scope(alias_ui *ui) {
ALIAS_ASH_EMIT(&ui->layout_program,
ui->mcb
// minw minh maxw maxh sum(childw) max(childh) -- w h
,
fit);
void alias_ui_align_x(struct alias_ui *ui, float x) {
alias_ui__tree__begin_child(ui);
alias_ui__tree__begin_scope(ui, alias_ui__alignx__begin_child, alias_ui__alignx__end_child,
alias_ui__alignx__end_scope);
alias_ui__program__emit_u32(ui, P_ALIGN_X);
alias_ui__program__emit_f32(ui, x);
}
ALIAS_ASH_EMIT(&ui->render_program,
ui->mcb
// x y w h --
,
drop2, drop2);
// ====================================================================================================================
// aligny
// program: y:float, child
// memory: height:float, child
static inline void alias_ui__aligny__begin_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
alias_ui__memory__reserve(ui, 1);
}
static inline void _horizontal_align(alias_ui *ui, float x, float y) {
(void)x;
_scope(ui)->alignment = y;
static inline void alias_ui__aligny__end_scope(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
alias_ui__tree__end_child(ui);
void alias_ui_begin_horizontal(alias_ui *ui) {
_begin_child(ui);
_begin_scope(ui, _horizontal_begin_child, _horizontal_end_child, _horizontal_end_scope);
static inline void alias_ui__aligny__layout(struct alias_ui *ui, float min_width, float max_width, float min_height,
float max_height, float *out_width, float *out_height) {
(void)alias_ui__ip__read_f32(ui);
float width;
float height;
uint32_t mhole = alias_ui__memory__dig(ui, 1);
alias_ui__layout(ui, min_width, max_width, min_height, max_height, &width, &height);
alias_ui__memory__fill_f32(ui, mhole, height);
*out_width = alias_ui__float__clamp(width, min_width, min_width);
*out_height = max_height;
}
_scope(ui)->align = _horizontal_align;
_scope(ui)->alignment = 0.5f;
static inline void alias_ui__aligny__render(struct alias_ui *ui, float x, float y, float width, float height) {
float align_y = alias_ui__ip__read_f32(ui);
float child_height = alias_ui__mp__read_f32(ui);
alias_ui__render(ui, x, y + (height - child_height) * align_y, width, child_height);
}
ALIAS_ASH_EMIT(&ui->layout_program,
ui->mcb
// setup: minw minh maxw maxh -- minw minh maxw maxh 0 0 (current width, height)
,
i(0), dup);
void alias_ui_align_y(struct alias_ui *ui, float y) {
alias_ui__tree__begin_child(ui);
alias_ui__tree__begin_scope(ui, alias_ui__aligny__begin_child, alias_ui__aligny__end_child,
alias_ui__aligny__end_scope);
alias_ui__program__emit_u32(ui, P_ALIGN_Y);
alias_ui__program__emit_f32(ui, y);
// stack layout
static inline void _stack_begin_child(alias_ui *ui) {
int shape = _alloc(ui, sizeof(struct shape));
_scope(ui)->shape = shape;
// padding
// program: left:float, top:float, right:float, bottom:float, child
// memory: child
static inline void alias_ui__padding__begin_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
}
ALIAS_ASH_EMIT(&ui->layout_program,
ui->mcb
// minw minh maxw maxh w h -- minw minh maxw maxh w h 0 0 maxw maxh
,
f(0), dup, i(5), pick, i(5), pick);
static inline void alias_ui__padding__end_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
alias_ui__tree__end_scope(ui);
}
ALIAS_ASH_EMIT(&ui->render_program,
ui->mcb
// x y w h -- x y w h (x+cx) (y+cy) cw ch
,
over2, i(shape), getw, i(shape), geth);
static inline void alias_ui__padding__end_scope(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
alias_ui__tree__end_child(ui);
static inline void _stack_end_child(alias_ui *ui) {
int shape = _scope(ui)->shape;
static inline void alias_ui__padding__layout(struct alias_ui *ui, float min_width, float max_width, float min_height,
float max_height, float *out_width, float *out_height) {
float left = alias_ui__ip__read_f32(ui);
float top = alias_ui__ip__read_f32(ui);
float right = alias_ui__ip__read_f32(ui);
float bottom = alias_ui__ip__read_f32(ui);
float padding_width = left + right;
float padding_height = top + bottom;
float child_width;
float child_height;
float child_min_width = alias_ui__float__max(min_width - padding_width, 0);
float child_max_width = alias_ui__float__max(max_width - padding_width, 0);
float child_min_height = alias_ui__float__max(min_height - padding_height, 0);
float child_max_height = alias_ui__float__max(max_height - padding_height, 0);
alias_ui__layout(ui, child_min_width, child_max_width, child_min_height, child_max_height, &child_width, &child_height);
*out_width = alias_ui__float__clamp(child_width + padding_width, min_width, max_width);
*out_height = alias_ui__float__clamp(child_height + padding_height, min_height, max_height);
}
ALIAS_ASH_EMIT(&ui->layout_program,
ui->mcb
// minw minh maxw maxh w h childw childh -- minw minh maxw maxh max(w childw) max(h childh)
,
dup, i(shape), seth, swap, dup, i(shape), setw, swap, f2_max);
static inline void alias_ui__padding__render(struct alias_ui *ui, float x, float y, float width, float height) {
float left = alias_ui__ip__read_f32(ui);
float top = alias_ui__ip__read_f32(ui);
float right = alias_ui__ip__read_f32(ui);
float bottom = alias_ui__ip__read_f32(ui);
float padding_width = left + right;
float padding_height = top + bottom;
alias_ui__render(ui, x + left, y + top, width - padding_width, height - padding_height);
static inline void _stack_end_scope(alias_ui *ui) {
ALIAS_ASH_EMIT(&ui->layout_program,
ui->mcb
// minw minh maxw maxh max(childw) max(childh) -- w h
,
fit);
void alias_ui_padding(struct alias_ui *ui, float left, float top, float right, float bottom) {
alias_ui__tree__begin_child(ui);
alias_ui__tree__begin_scope(ui, alias_ui__padding__begin_child, alias_ui__padding__end_child,
alias_ui__padding__end_scope);
alias_ui__program__emit_u32(ui, P_PADDING);
alias_ui__program__emit_f32(ui, left);
alias_ui__program__emit_f32(ui, top);
alias_ui__program__emit_f32(ui, right);
alias_ui__program__emit_f32(ui, bottom);
}
ALIAS_ASH_EMIT(&ui->render_program,
ui->mcb
// x y w h --
,
drop2, drop2);
// ====================================================================================================================
// query
// program: named_scope:uint32_t, query_index:uint32_t, child
// memory: child
static inline void alias_ui__query__begin_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {}
void alias_ui_begin_stack(alias_ui *ui) {
_begin_child(ui);
_begin_scope(ui, _stack_begin_child, _stack_end_child, _stack_end_scope);
static inline void alias_ui__query__end_scope(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
alias_ui__tree__end_child(ui);
}
ALIAS_ASH_EMIT(&ui->layout_program,
ui->mcb
// setup: minw minh maxw maxh -- minw minh maxw maxh 0 0 (current width, height)
,
i(0), dup);
static inline void alias_ui__query__layout(struct alias_ui *ui, float min_width, float max_width, float min_height,
float max_height, float *out_width, float *out_height) {
(void)alias_ui__ip__read_u32(ui);
(void)alias_ui__ip__read_u32(ui);
alias_ui__layout(ui, min_width, max_width, min_height, max_height, out_width, out_height);
void alias_ui_end(alias_ui *ui) { _end_scope(ui); }
static inline void alias_ui__query__render(struct alias_ui *ui, float x, float y, float width, float height) {
uint32_t named_scope_index = alias_ui__ip__read_u32(ui);
uint32_t query_index = alias_ui__ip__read_u32(ui);
struct alias_ui_named_scope *named_scope = &ui->named_scope[named_scope_index];
named_scope->query_rects[query_index * 4 + 0] = x;
named_scope->query_rects[query_index * 4 + 1] = y;
named_scope->query_rects[query_index * 4 + 2] = width;
named_scope->query_rects[query_index * 4 + 3] = height;
alias_ui__render(ui, x, y, width, height);
}
void alias_ui_stats(alias_ui *ui, uint32_t *num_vertexes, uint32_t *num_indexes, uint32_t *num_groups) {
*num_vertexes = ui->max_num_vertexes;
*num_indexes = ui->max_num_indexes;
*num_groups = ui->max_num_groups;
void alias_ui_query(struct alias_ui *ui, uint32_t query_index, float *out_rect) {
alias_ui__tree__begin_child(ui);
alias_ui__tree__begin_scope(ui, alias_ui__query__begin_child, alias_ui__query__end_child,
alias_ui__query__end_scope);
struct alias_ui_tree_scope *scope = alias_ui__tree__top_scope(ui);
alias_ui__program__emit_u32(ui, P_QUERY);
alias_ui__program__emit_u32(ui, scope->named_scope_index);
alias_ui__program__emit_u32(ui, query_index);
struct alias_ui_named_scope *named_scope = &ui->named_scope[scope->named_scope_index];
alias_ui__grow((void **)&named_scope->query_rects, sizeof(*named_scope->query_rects) * 4, query_index + 1,
&named_scope->query_capacity);
out_rect[0] = named_scope->query_rects[query_index * 4 + 0];
out_rect[1] = named_scope->query_rects[query_index * 4 + 1];
out_rect[2] = named_scope->query_rects[query_index * 4 + 2];
out_rect[3] = named_scope->query_rects[query_index * 4 + 3];
// font
void alias_ui_font_size(alias_ui *ui, alias_R size) { _scope(ui)->font_size = size; }
static inline void alias_ui__layout__initialize(struct alias_ui *ui) {
alias_ui__ip__initialize(ui);
alias_ui__memory__initialize(ui);
}
void alias_ui_font_color(alias_ui *ui, alias_Color color) { _scope(ui)->font_color = color; }
static inline void alias_ui__layout(struct alias_ui *ui, float aw, float bw, float ah, float bh, float *oh,
float *ow) {
uint32_t code = alias_ui__ip__read_u32(ui);
switch(code) {
case P_TERMINATE:
break;
case P_EMPTY_FILL:
alias_ui__empty_fill__layout(ui, aw, bw, ah, bh, oh, ow);
break;
case P_COLOR_FILL:
alias_ui__color_fill__layout(ui, aw, bw, ah, bh, oh, ow);
break;
case P_TEXT:
alias_ui__text__layout(ui, aw, bw, ah, bh, oh, ow);
break;
case P_IMAGE:
alias_ui__image__layout(ui, aw, bw, ah, bh, oh, ow);
break;
case P_BACKGROUND_COLOR:
alias_ui__background_color__layout(ui, aw, bw, ah, bh, oh, ow);
break;
case P_BORDER:
alias_ui__border__layout(ui, aw, bw, ah, bh, oh, ow);
break;
case P_STACK:
alias_ui__stack__layout(ui, aw, bw, ah, bh, oh, ow);
break;
case P_HORIZONTAL_STACK:
alias_ui__dstack__layout(ui, false, aw, bw, ah, bh, oh, ow);
break;
case P_VERTICAL_STACK:
alias_ui__dstack__layout(ui, true, aw, bw, ah, bh, oh, ow);
break;
case P_SIZE:
alias_ui__size__layout(ui, aw, bw, ah, bh, oh, ow);
break;
case P_WIDTH:
alias_ui__width__layout(ui, aw, bw, ah, bh, oh, ow);
break;
case P_HEIGHT:
alias_ui__height__layout(ui, aw, bw, ah, bh, oh, ow);
break;
case P_ALIGN:
alias_ui__align__layout(ui, aw, bw, ah, bh, oh, ow);
break;
case P_ALIGN_X:
alias_ui__alignx__layout(ui, aw, bw, ah, bh, oh, ow);
break;
case P_ALIGN_Y:
alias_ui__aligny__layout(ui, aw, bw, ah, bh, oh, ow);
break;
case P_PADDING:
alias_ui__padding__layout(ui, aw, bw, ah, bh, oh, ow);
break;
case P_QUERY:
alias_ui__query__layout(ui, aw, bw, ah, bh, oh, ow);
break;
}
}
static inline void alias_ui__render__initialize(struct alias_ui *ui) {
alias_ui__ip__initialize(ui);
alias_ui__mp__initialize(ui);
alias_ui__vertex__initialize(ui);
alias_ui__index__initialize(ui);
alias_ui__group__initialize(ui);
ui->texture_id = 0;
alias_ui__group__advance(ui);
}
static inline void alias_ui__render(struct alias_ui *ui, float x, float y, float w, float h) {
uint32_t code = alias_ui__ip__read_u32(ui);
switch(code) {
case P_TERMINATE:
break;
case P_EMPTY_FILL:
alias_ui__empty_fill__render(ui, x, y, w, h);
break;
case P_COLOR_FILL:
alias_ui__color_fill__render(ui, x, y, w, h);
break;
case P_TEXT:
alias_ui__text__render(ui, x, y, w, h);
break;
case P_IMAGE:
alias_ui__image__render(ui, x, y, w, h);
break;
case P_BACKGROUND_COLOR:
alias_ui__background_color__render(ui, x, y, w, h);
break;
case P_BORDER:
alias_ui__border__render(ui, x, y, w, h);
break;
case P_STACK:
alias_ui__stack__render(ui, x, y, w, h);
break;
case P_HORIZONTAL_STACK:
alias_ui__dstack__render(ui, false, x, y, w, h);
break;
case P_VERTICAL_STACK:
alias_ui__dstack__render(ui, true, x, y, w, h);
break;
case P_SIZE:
alias_ui__size__render(ui, x, y, w, h);
break;
case P_WIDTH:
alias_ui__width__render(ui, x, y, w, h);
break;
case P_HEIGHT:
alias_ui__height__render(ui, x, y, w, h);
break;
case P_ALIGN:
alias_ui__align__render(ui, x, y, w, h);
break;
case P_ALIGN_X:
alias_ui__alignx__render(ui, x, y, w, h);
break;
case P_ALIGN_Y:
alias_ui__aligny__render(ui, x, y, w, h);
break;
case P_PADDING:
alias_ui__padding__render(ui, x, y, w, h);
break;
case P_QUERY:
alias_ui__query__render(ui, x, y, w, h);
break;
}
}
// text
static void _textv_layout(alias_ash *ash) {
float size = alias_ash_pop_R(ash);
uint32_t text = alias_ash_pop(ash);
float maxh = alias_ash_pop_R(ash);
float maxw = alias_ash_pop_R(ash);
float minh = alias_ash_pop_R(ash);
float minw = alias_ash_pop_R(ash);
float w, h;
alias_ui *ui = (alias_ui *)ash->user_data;
ui->text_size(ui, _mem(ui, text), size, maxw, &w, &h);
alias_ash_push_R(ash, alias_max(minw, alias_min(maxw, w)));
alias_ash_push_R(ash, alias_max(minh, alias_min(maxh, h)));
static inline bool alias_ui__dev_font__decode(struct alias_ui_Font *font, const char *string, uint32_t *inout_glyph,
uint32_t *out_num_bytes, struct alias_ui_Font_GlyphInfo *out_info) {
uint32_t glyph = *string;
*inout_glyph = glyph;
*out_num_bytes = 1;
uint32_t row = glyph >> 4;
uint32_t col = glyph & 15;
out_info->newline = glyph == '\n';
out_info->advance_x = 0.5f;
out_info->x = 0.0f;
out_info->y = 0.0f;
out_info->width = 1.33f;
out_info->height = 1.33f;
if(row < 2 || glyph == ' ') {
out_info->width = 0;
out_info->height = 0;
} else {
row -= 2;
}
out_info->s0 = (float)(col + 0) / 16.0f;
out_info->t0 = (float)(row + 0) / 16.0f;
out_info->s1 = (float)(col + 1) / 16.0f;
out_info->t1 = (float)(row + 1) / 16.0f;
return true;
}
static struct alias_ui_Font alias_ui__dev_font = {
.texture_id = 0,
.decode = alias_ui__dev_font__decode,
};
// --------------------------------------------------------------------------------------------------------------------
#ifdef UNICAT_UI_ENABLE_FREETYPE
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_OUTLINE_H
#define MULTILINE_STRING(...) #__VA_ARGS__
// ALIAS_TRACE("textv_layout '%s' %g %g -> %g %g", _mem(ui, text), size, maxw, w, h);
const char * alias_ui_freetype_opengl_fragment_shader(uint32_t major, uint32_t minor) {
return
MULTILINE_STRING(
vec2 alias_ui_freetype_snorm16_decode2(uvec2 x) {
return vec2(x) / 65535.0 - 0.5;
static void _textv_render(alias_ash *ash) {
float a = alias_ash_pop_R(ash);
float b = alias_ash_pop_R(ash);
float g = alias_ash_pop_R(ash);
float r = alias_ash_pop_R(ash);
float size = alias_ash_pop_R(ash);
uint32_t text = alias_ash_pop(ash);
float h = alias_ash_pop_R(ash);
float w = alias_ash_pop_R(ash);
float y = alias_ash_pop_R(ash);
float x = alias_ash_pop_R(ash);
(void)h;
alias_ui *ui = (alias_ui *)ash->user_data;
ui->text_draw(ui, _mem(ui, text), x, y, w, size, (alias_Color){r, g, b, a});
float alias_ui_freetype_draw_curve(vec2 p0, vec2 p1, vec2 p2, float inverse_pixel_width) {
vec2 a = p0 - 2.0*p1 + p2;
vec2 b = p0 - p1;
vec2 c = p0;
vec2 t;
float si = b.y*b.y - a.y*c.y;
float s = sqrt(max(si, 0.0));
t = vec2(b.y - s, b.y + s) / a.y;
vec2 x = (a.x*t - 2.0*b.x)*t + c.x;
vec2 weight = clamp(x * inverse_pixel_width + 0.5, 0.0, 1.0) * step(0.0, t) * step(-1.0, -t);
return dot(weight, vec2(1, -1)) * step(0.0, si);
}
// ALIAS_TRACE("textv_draw '%s' %g %g %g", _mem(ui, text), minx, miny, size);
float alias_ui_freetype_draw_layer(vec2 uv, vec2 inverse_pixel_width, uint curve_start, uint curve_length, bool super_sampling) {
float alpha = 0.0;
uint row = curve_start;
uint end = row + curve_length;
while(row < end) {
uvec4 contour = alias_ui_freetype_user_font(row++);
uint count = contour.x;
vec2 a = alias_ui_freetype_snorm16_decode2(contour.zw) * scale - uv;
for(uint i = 0u; i < count; i++) {
uvec4 curve = alias_ui_freetype_user_font(row++);
vec2 b = alias_ui_freetype_snorm16_decode2(curve.xy) * scale - uv;
vec2 c = alias_ui_freetype_snorm16_decode2(curve.zw) * scale - uv;
vec3 x = vec3(a.x, b.x, c.x);
vec3 y = vec3(a.y, b.y, c.y);
if(!all(lessThan(y, vec3(0))) && !all(greaterThan(y, vec3(0)))) {
alpha += alias_ui_freetype_draw_curve(a, b, c, inverse_pixel_width.x);
}
if(super_sampling && !all(lessThan(x, vec3(0))) && !all(greaterThan(x, vec3(0)))) {
alpha += alias_ui_freetype_draw_curve(vec2(a.y, -a.x), vec2(b.y, -b.x), vec2(c.y, -c.x), inverse_pixel_width.y);
}
a = c;
}
}
return alpha * (float(!super_sampling)*0.5+0.5);
void alias_ui_textv(alias_ui *ui, const char *format, va_list ap) {
uint32_t text;
size_t length;
{
va_list ap2;
va_copy(ap2, ap);
length = vsnprintf(NULL, 0, 0, format, ap2);
va_end(ap2);
text = _alloc(ui, length + 1);
vsnprintf(_mem(ui, text), length + 1, length + 1, format, ap);
vec4 alias_ui_freetype_draw_glyph(vec4 default_color, vec2 uv, uint glyph_index, bool super_sampling) {
vec2 inverse_pixel_width = 1.0 / fwidth(uv);
uvec4 glyph = alias_ui_freetype_user_font(glyph_index);
if(glyph.y == 1u) {
float alpha = alias_ui_freetype_draw_layer(uv, inverse_pixel_width, glyph.z, glyph.w, super_sampling);
return vec4(default_color.rgb, default_color.a * alpha);
} else {
vec4 color = vec4(0);
for(uint i = 0u; i < glyph.y; i++) {
uvec4 layer = alias_ui_freetype_user_font(glyph.x + i);
float alpha = alias_ui_freetype_draw_layer(uv, inverse_pixel_width, glyph.z, glyph.w, super_sampling);
}
return color;
ui->max_num_vertexes += 4 * length;
ui->max_num_indexes += 6 * length;
ui->max_num_groups++;
void alias_ui_freetype_texture_callback(struct alias_ui *ui, uint32_t (*f)(uint32_t length, void ** ptr)) {
ui->freetype_texture_callback = f;
}
ALIAS_ASH_EMIT(&ui->render_program,
ui->mcb
// self: minx miny w h --
,
i(text), f(_scope(ui)->font_size), f(_scope(ui)->font_color.r), f(_scope(ui)->font_color.g), f(_scope(ui)->font_color.b),
f(_scope(ui)->font_color.a), textv_render);
static int alias_ui_freetype__counter_move(const FT_Vector * to, void * user) {
struct alias_ui_freetype__Counter *c = (struct alias_ui_freetype__Counter *)user;
c->num_points += 1;
c->num_contours += 1;
return 0;
}
// ====================================================================================================================
void alias_ui_fill(alias_ui *ui, alias_Color color) {
_begin_child(ui);
static int alias_ui_freetype__counter_conic(const FT_Vector * control, const FT_Vector * to, void * user) {
struct alias_ui_freetype__Counter *c = (struct alias_ui_freetype__Counter *)user;
c->num_points += 2;
return 0;
}
ui->max_num_vertexes += 4;
ui->max_num_indexes += 6;
ui->max_num_groups++;
static int alias_ui_freetype__counter_cubic(const FT_Vector * control1, const FT_Vector * control2, const FT_Vector * to, void * user) {
struct alias_ui_freetype__Counter *c = (struct alias_ui_freetype__Counter *)user;
c->num_points += 4;
return 0;
}
struct alias_ui_freetype__Emitter {
float scale;
uint16_t * data;
uint32_t contour_data_index_start;
uint32_t data_index;
float ax;
float ay;
};
ALIAS_ASH_EMIT(&ui->layout_program,
ui->mcb
// self: minw minh maxw mwxh -- w h
,
swap2, drop2);
static void alias_ui_freetype__Emitter_flush(struct alias_ui_freetype__Emitter *e) {
if(e->contour_data_index_start > 0) {
e->data[e->contour_data_index_start * 4 + 0] = e->data_index - e->data[e->contour_data_index_start * 4 + 0];
}
e->contour_data_index_start = 0;
}
static void alias_ui_freetype__Emitter_contour(struct alias_ui_freetype__Emitter *e, float ax, float ay) {
alias_ui_freetype__Emitter_flush(e);
e->contour_data_index_start = e->data_index;
e->data[e->data_index * 4 + 0] = 0;
e->data[e->data_index * 4 + 1] = 0;
e->data[e->data_index * 4 + 2] = (uint16_t)((int32_t)e->ax + 32768);
e->data[e->data_index * 4 + 3] = (uint16_t)((int32_t)e->ay + 32768);
e->data_index++;
e->ax = ax;
e->ay = ay;
}
static void alias_ui_freetype__Emitter_curve(struct alias_ui_freetype__Emitter *e, float bx, float by, float cx, float cy) {
float x = e->ax - 2.0f*bx + cx;
float y = e->ay - 2.0f*by + cy;
if(fabs(x) < 0.00001f || fabs(y) < 0.00001f) {
bx += (e->ax - cx) * 0.1f;
by += (e->ay - cy) * 0.1f;
}
e->data[e->data_index * 4 + 0] = (uint16_t)((int32_t)bx + 32768);
e->data[e->data_index * 4 + 1] = (uint16_t)((int32_t)by + 32768);
e->data[e->data_index * 4 + 2] = (uint16_t)((int32_t)cx + 32768);
e->data[e->data_index * 4 + 3] = (uint16_t)((int32_t)cy + 32768);
e->data_index++;
e->ax = cx;
e->ay = cy;
}
static int alias_ui_freetype__emitter_move(const FT_Vector * to, void * user) {
struct alias_ui_freetype__Emitter *e = (struct alias_ui_freetype__Emitter *)user;
alias_ui_freetype__Emitter_contour(e, (float)to->x * e->scale, (float)to->y * e->scale);
return 0;
}
ALIAS_ASH_EMIT(&ui->render_program,
ui->mcb
// self: x y w h --
,
i(0), set_texture, f(color.r), f(color.g), f(color.b), f(color.a), rect_fill_c);
static int alias_ui_freetype__emitter_line(const FT_Vector * to, void * user) {
struct alias_ui_freetype__Emitter *e = (struct alias_ui_freetype__Emitter *)user;
float cx = (float)to->x * e->scale;
float cy = (float)to->y * e->scale;
float bx = (e->ax + cx) * 0.5f;
float by = (e->ay + cy) * 0.5f;
alias_ui_freetype__Emitter_curve(e, bx, by, cx, cy);
return 0;
}
static int alias_ui_freetype__emitter_conic(const FT_Vector * control, const FT_Vector * to, void * user) {
struct alias_ui_freetype__Emitter *e = (struct alias_ui_freetype__Emitter *)user;
float bx = (float)control->x * e->scale;
float by = (float)control->y * e->scale;
float cx = (float)to->x * e->scale;
float cy = (float)to->y * e->scale;
alias_ui_freetype__Emitter_curve(e, bx, by, cx, cy);
return 0;
}
_end_child(ui);
static int alias_ui_freetype__emitter_cubic(const FT_Vector * control1, const FT_Vector * control2, const FT_Vector * to, void * user) {
struct alias_ui_freetype__Emitter *e = (struct alias_ui_freetype__Emitter *)user;
// a b c d e
// start c1 mid c2 end
float control1x = (float)control1->x * e->scale;
float control1y = (float)control1->y * e->scale;
float control2x = (float)control2->x * e->scale;
float control2y = (float)control2->y * e->scale;
float ex = (float)to->x * e->scale;
float ey = (float)to->y * e->scale;
float bx = e->ax + (control1x - e->ax) * 0.75;
float by = e->ax + (control1y - e->ay) * 0.75;
float dx = ex + (control2x - ex) * 0.75;
float dy = ey + (control2y - ey) * 0.75;
float cx = (bx + dx) * 0.5;
float cy = (by + dy) * 0.5;
alias_ui_freetype__Emitter_curve(e, bx, by, cx, cy);
alias_ui_freetype__Emitter_curve(e, dx, dy, ex, ey);
return 0;
// ====================================================================================================================
void alias_ui_image(alias_ui *ui, alias_R width, alias_R height, alias_R s0, alias_R t0, alias_R s1, alias_R t1, uint32_t texture_id) {
_begin_child(ui);
struct alias_ui_freetype_font_character {
uint32_t charcode;
uint32_t have_bold : 1;
uint32_t have_italic : 1;
uint32_t have_bold_italic : 1;
uint32_t glyph_index : 29;
};
ALIAS_ASH_EMIT(&ui->layout_program,
ui->mcb
// self: minw minh maxw mwxh -- w h
,
f(width), f(height), fit);
struct alias_ui_freetype_font {
struct alias_ui_font root;
struct alias_ui_freetype_font_character * character_map;
uint32_t num_characters;
_end_child(ui);
static int alias_ui_freetype_character_map_compare(const void * a, const void * b) {
uint32_t charcode = *(const uint32_t *)a;
const struct alias_ui_freetype_font_character * character = (const struct alias_ui_freetype_font_character *)b;
return (int)((int64_t)character->charcode - (int64_t)a);
// ====================================================================================================================
// frame (end)
alias_ui_Result alias_ui_end_frame(alias_ui *ui, alias_MemoryCB *mcb, alias_ui_Output *output) {
_end_scope(ui);
ui->output = output;
static bool alias_ui_freetype_font_decode(struct alias_ui_font *_font, const char *string, uint32_t *inout_glyph, uint32_t *out_num_bytes, struct alias_ui_font_glyph_info *out_info) {
struct alias_ui_freetype_font * font = (struct alias_ui_freetype_font *)_font->user_data;
uint32_t charcode = *string;
struct alias_ui_freetype_font_character * character = bsearch(&charcode, font->character_map, font->num_characters, sizeof(*font->character_map), alias_ui_freetype_character_map_compare);
*out_num_bytes = 1;
if(character != NULL) {
*inout_glyph = character - font->character_map;
} else {
return false;
}
alias_ash_Program_end_shader(&ui->layout_program, mcb);
alias_ash_Program_end_shader(&ui->render_program, mcb);
out_info->newline == *string == '\n';
out_info->advance_x = font->glyph_map[*inout_glyph].advance_x;
out_info->x = font->glyph_map[*inout_glyph].x;
out_info->y = font->glyph_map[*inout_glyph].y;
out_info->width = font->glyph_map[*inout_glyph].width;
out_info->height = font->glyph_map[*inout_glyph].height;
out_info->s0 = 0.0f + *inout_glyph;
out_info->t0 = 0.0f;
out_info->s1 = 1.0f + *inout_glyph;
out_info->t1 = 1.0f;
return true;
}
alias_ash_initialize(&ash, &ui->layout_program);
while(alias_ash_step(&ash))
;
struct alias_ui_freetype_font * font = malloc(sizeof(*font));
uint32_t num_faces = num_filenames;
FT_Face * faces = malloc(sizeof(FT_Face) * num_faces);
if(output->num_groups > 0) {
output->groups[output->num_groups - 1].length = output->num_indexes - output->groups[output->num_groups - 1].index;
for(uint32_t i = 0; i < num_filenames; i++) {
FT_New_Face(library, filenames[i], 0, &faces[i]);
output->groups[output->num_groups].index = output->num_indexes;
output->groups[output->num_groups].length = 0;
output->groups[output->num_groups].texture_id = 0;
output->num_groups++;
struct {
struct {
uint32_t face;
uint32_t glyph;
} style[4];
} *building_character_map = NULL;
alias_ash_initialize(&ash, &ui->render_program);
while(alias_ash_step(&ash))
;
font->num_glyphs = 0;
for(uint32_t charcode = ' '; charcode < 0x1FFFFF; charcode++) {
uint32_t face_index = 0;
FT_UInt glyph_index = 0;
struct {
uint32_t face;
uint32_t glyph;
} style[4] = {{-1,-1},{-1,-1},{-1,-1},{-1,-1}};
for(; face_index < num_faces; face_index++) {
glyph_index = FT_Get_Char_Index(faces[face_index], charcode);
if(glyph_index != 0) {
if(style[faces[face_index]->style_flags].face == -1) {
style[faces[face_index]->style_flags].face = face_index;
style[faces[face_index]->style_flags].glyph = glyph_index;
}
}
}
if(style[0].face == -1) {
continue;
}
font->character_map = realloc(font->character_map, sizeof(*font->character_map) * (font->num_characters + 1));
building_character_map = realloc(building_character_map, sizeof(*building_character_map) * (font->num_characters + 1));
output->groups[output->num_groups - 1].length = output->num_indexes - output->groups[output->num_groups - 1].index;
font->character_map[font->num_characters].charcode = charcode;
font->character_map[font->num_characters].glyph_index = font->num_glyphs;
font->character_map[font->num_characters].have_bold = style[1].face != -1;
font->character_map[font->num_characters].have_italic = style[2].face != -1;
font->character_map[font->num_characters].have_bold_italic = style[3].face != -1;
building_character_map[font->num_characters].style[0].face = style[0].face;
building_character_map[font->num_characters].style[0].glyph = style[0].glyph;
building_character_map[font->num_characters].style[1].face = style[1].face;
building_character_map[font->num_characters].style[1].glyph = style[1].glyph;
building_character_map[font->num_characters].style[2].face = style[2].face;
building_character_map[font->num_characters].style[2].glyph = style[2].glyph;
building_character_map[font->num_characters].style[3].face = style[3].face;
building_character_map[font->num_characters].style[3].glyph = style[3].glyph;
font->num_glyphs += 1 +
font->character_map[font->num_characters].have_bold +
font->character_map[font->num_characters].have_italic +
font->character_map[font->num_characters].have_bold_italic;
font->num_characters++;
}
if(output->groups[output->num_groups - 1].length == 0) {
output->num_groups--;
struct alias_ui_freetype__Counter counter;
memset(&counter, 0, sizeof(counter));
FT_Outline_Funcs counter_funcs;
memset(&counter_funcs, 0, sizeof(counter_funcs));
counter_funcs.move_to = alias_ui_freetype__counter_move;
counter_funcs.line_to = alias_ui_freetype__counter_line;
counter_funcs.conic_to = alias_ui_freetype__counter_conic;
counter_funcs.cubic_to = alias_ui_freetype__counter_cubic;
for(uint32_t character_index = 0; character_index < font->num_characters; character_index++) {
for(uint32_t style_index = 0; style_index < 4; style_index) {
if(building_character_map[character_index].style[style_index].face != -1) {
FT_Face face = faces[building_character_map[character_index].style[style_index].face];
FT_Load_Glyph(
face,
building_character_map[character_index].style[style_index].glyph,
FT_LOAD_NO_HINTING | FT_LOAD_NO_SCALE | FT_LOAD_LINEAR_DESIGN
);
FT_Outline_Decompose(&face->glyph->outline, &counter_funcs, &counter);
}
}
}
FT_Outline_Funcs emitter_funcs;
memset(&emitter_funcs, 0, sizeof(emitter_funcs));
emitter_funcs.move_to = alias_ui_freetype__emitter_move;
emitter_funcs.line_to = alias_ui_freetype__emitter_line;
emitter_funcs.conic_to = alias_ui_freetype__emitter_conic;
emitter_funcs.cubic_to = alias_ui_freetype__emitter_cubic;
uint32_t length = font->num_glyphs + counter.num_contours + (counter.num_points - counter.num_contours) * 2;
struct alias_ui_freetype__Emitter emitter;
memset(&emitter, 0, sizeof(emitter));
ui->freetype_texture_callback(length, (void **)&emitter.data);
emitter.data_index = font->num_characters;
font->glyph_map = malloc(sizeof(*font->glyph_map) * font->num_glyphs);
uint32_t glyph_index = 0;
for(uint32_t character_index = 0; character_index < font->num_characters; character_index++) {
for(uint32_t style_index = 0; style_index < 4; style_index) {
if(building_character_map[character_index].style[style_index].face != -1) {
FT_Face face = faces[building_character_map[character_index].style[style_index].face];
FT_Load_Glyph(
face,
building_character_map[character_index].style[style_index].glyph,
FT_LOAD_NO_HINTING | FT_LOAD_NO_SCALE
);
emitter.scale = 65535.0f / (float)face->units_per_EM;
FT_Outline_Decompose(&face->glyph->outline, &emitter_funcs, &emitter);
alias_ui_freetype__Emitter_flush(&emitter);
font->glyph_map[glyph_index].advance_x = (float)face->glyph->metrics.horiAdvance * emitter.scale;
font->glyph_map[glyph_index].x = (float)face->glyph->metrics.horiBearingX * emitter.scale;
font->glyph_map[glyph_index].y = (float)face->glyph->metrics.horiBearingY * emitter.scale;
font->glyph_map[glyph_index].width = (float)face->glyph->metrics.width * emitter.scale;
font->glyph_map[glyph_index].height = (float)face->glyph->metrics.height * emitter.scale;
}
}
}
for(uint32_t i = 0; i < num_faces; i++) {
FT_Done_Face(faces[i]);
}
free(faces);
free(building_character_map);
font->root.texture_id = ui->freetype_texture_callback(length, (void **)&emitter.data);
font->root.decode = alias_ui_freetype_font_decode;
font->root.user_data = font;
return &font->root;
}
void alias_ui_freetype_free_font(struct alias_ui_font * font) {
}
#endif
// ====================================================================================================================
alias_ui_Result alias_ui_initialize(alias_MemoryCB *mcb, alias_ui **ui_ptr) {
struct alias_ui * ui = alias_malloc(mcb, sizeof(struct alias_ui), alignof(struct alias_ui));
*ui_ptr = ui;
if(ui == NULL) {
return alias_ui_ErrorOutOfMemory;
}
memset(ui, 0, sizeof(*ui));
ui->mcb = mcb;
return alias_ui_add_font(ui, &alias_ui__dev_font, NULL);
}
void alias_ui_free(alias_ui *ui, alias_MemoryCB *mcb) {
}
alias_ui_Result alias_ui_add_font(alias_ui *ui, struct alias_ui_Font *font, uint32_t *out_result) {
if(!alias_ui__grow((void **)&ui->font, sizeof(*ui->font), ui->font_length + 1, &ui->font_capacity)) {
return alias_ui_ErrorOutOfMemory;
}
uint32_t index = ui->font_length;
ui->font[index] = *font;
ui->font_length += 1;
if(out_result != NULL) {
*out_result = index;
void alias_ui_stats(alias_ui *ui, uint32_t *num_vertexes, uint32_t *num_indexes, uint32_t *num_groups) {
*num_vertexes = ui->stats.num_vertexes;
*num_indexes = ui->stats.num_indexes;
*num_groups = ui->stats.num_groups;
}
alias_ui_Result alias_ui_end_frame(alias_ui *ui, alias_MemoryCB *mcb, alias_ui_Output *output) {
ui->output = output;
float width = ui->input.screen_size.width;
float height = ui->input.screen_size.height;
alias_ui__layout__initialize(ui);
alias_ui__layout(ui, 0, width, 0, height, &width, &height);
alias_ui__render__initialize(ui);
alias_ui__render(ui, 0, 0, width, height);
alias_ui__group__finalize(ui);
return alias_ui_Success;
}
struct alias_ui_Font_GlyphInfo {
bool newline;
float advance_x;
float x;
float y;
float width;
float height;
float s0;
float t0;
float s1;
float t1;
};
struct alias_ui_Font {
struct alias_ui_Font *fallback;
uint32_t texture_id;
bool (*decode)(struct alias_ui_Font *font, const char *string, uint32_t *inout_glyph, uint32_t *out_num_bytes,
struct alias_ui_Font_GlyphInfo *out_info);
void *user_data;
};
void alias_ui_SetTexture(alias_ui *ui, uint32_t texture_id);
void alias_ui_EmitRect(alias_ui *ui, float x, float y, float w, float h, float s0, float t0, float s1, float t1, float r, float g, float b, float a);
void alias_ui_set_texture(struct alias_ui *ui, uint32_t texture_id);
void alias_ui_draw_rectangle(struct alias_ui *ui, float x, float y, float width, float height,
float s0, float t0, float s1, float t1, uint8_t r, uint8_t g,
uint8_t b, uint8_t a);
typedef void (*alias_ui_TextSizeFn)(alias_ui *ui, const char *buffer, alias_R size, alias_R max_width, alias_R *out_width, alias_R *out_height);
typedef void (*alias_ui_TextDrawFn)(alias_ui *ui, const char *buffer, alias_R x, alias_R y, alias_R width, alias_R size, alias_Color color);
typedef void (*alias_ui_TextSizeFn)(alias_ui *ui, const char *buffer, float size, float max_width, float *out_width, float *out_height);
typedef void (*alias_ui_TextDrawFn)(alias_ui *ui, const char *buffer, float x, float y, float width, float size, alias_Color color);
void alias_ui_override_size(alias_ui *ui, alias_R width, alias_R height);
void alias_ui_override_width(alias_ui *ui, alias_R width);
void alias_ui_override_height(alias_ui *ui, alias_R height);
void alias_ui_size(alias_ui *ui, float width, float height);
void alias_ui_width(alias_ui *ui, float width);
void alias_ui_height(alias_ui *ui, float height);
void alias_ui_margin(alias_ui *ui, alias_R left, alias_R right, alias_R top, alias_R bottom);
void alias_ui_padding(alias_ui *ui, alias_R left, alias_R right, alias_R top, alias_R bottom);
void alias_ui_margin(alias_ui *ui, float left, float right, float top, float bottom);
void alias_ui_padding(alias_ui *ui, float left, float right, float top, float bottom);
void alias_ui_fill(alias_ui *ui, alias_Color color);
void alias_ui_image(alias_ui *ui, alias_R width, alias_R height, alias_R s0, alias_R t0, alias_R s1, alias_R t1, uint32_t texture_id);
void alias_ui_color_fill(alias_ui *ui, float r, float g, float b, float a);
void alias_ui_image(alias_ui *ui, float width, float height, float s0, float t0, float s1, float t1, uint32_t texture_id);
#define ALIAS_GL_IMPL_SNIPPET(NAME, ...) \
struct alias_gl_ShaderSnippet alias_gl_##NAME##_snippet = { \
.requires = {ALIAS_CPP_EVAL(ALIAS_CPP_MAP(ALIAS_GL_SNIPPET_REQUIRE_, __VA_ARGS__))}, \
#define ALIAS_GL_IMPL_SNIPPET(NAME, ...) \
struct alias_gl_ShaderSnippet alias_gl_##NAME##_snippet = { \
.requires = {ALIAS_CPP_EVAL(ALIAS_CPP_MAP(ALIAS_GL_SNIPPET_REQUIRE_, __VA_ARGS__))}, \
.flags = 0 ALIAS_CPP_EVAL(ALIAS_CPP_MAP(ALIAS_GL_SNIPPET_FLAG_, __VA_ARGS__)), \