Compare commits

...

9 Commits

56 changed files with 6028477 additions and 759 deletions

View File

@ -17,11 +17,9 @@ execute_process(
OUTPUT_STRIP_TRAILING_WHITESPACE
)
#add_compile_options("-I/nix/store/2hm4rjvywd00p417y43i9rzx8v793qi0-pipewire-1.4.5-dev/include/pipewire-0.3 -I/nix/store/2hm4rjvywd00p417y43i9rzx8v793qi0-pipewire-1.4.5-dev/include/spa-0.2")
message(INFO ${LIBPIPEWIRE_CFLAGS})
#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} \
# -I /nix/store/2hm4rjvywd00p417y43i9rzx8v793qi0-pipewire-1.4.5-dev/include/pipewire-0.3 \
# -I /nix/store/2hm4rjvywd00p417y43i9rzx8v793qi0-pipewire-1.4.5-dev/include/spa-0.2 ")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${LIBPIPEWIRE_CFLAGS}")
add_compile_definitions(_POSIX_C_SOURCE=200112L)
add_compile_definitions(_GNU_SOURCE)
@ -43,8 +41,12 @@ add_executable(codegen_l1_5 src/l1_5/anne/codegen.c)
#add_executable(1_render_test src/l2/tests/r1/r1.c gen/l_wl_protocols/xdg-shell-private.c)
#target_link_libraries(1_render_test -lwayland-client -lrt -lm -lxkbcommon)
#
#add_executable(2a_render_test src/l2/tests/r2/r2a.c gen/l_wl_protocols/xdg-shell-private.c)
#target_link_libraries(2a_render_test ${LIBPIPEWIRE_LIBS} -lwayland-client -lrt -lm -lxkbcommon)
add_executable(r2a src/l2/tests/r2/r2a.c gen/l_wl_protocols/xdg-shell-private.c)
target_link_libraries(r2a ${LIBPIPEWIRE_LIBS} -lwayland-client -lrt -lm -lxkbcommon)
add_executable(r2c src/l2/tests/r2/r2c.c)
target_link_libraries(r2c -lm)
#
#add_executable(3_render_test src/l2/tests/r3/r3.c gen/l_wl_protocols/xdg-shell-private.c)
#target_link_libraries(3_render_test -lwayland-client -lm -lvulkan -lxkbcommon)

4
README.txt Normal file
View File

@ -0,0 +1,4 @@
Fonts used:
DM Serif Text made by Colophon Foundry
Roboto made by Christian Robertson, Paratype, Font Bureau
Great Vibes made by Robert Leuschke

View File

@ -20,6 +20,10 @@ void generate_code_for_alice_on_l1(){
generate_eve_span_company_for_primitive(l, ns, cstr("RefListNodeAliceGenericMeshHand"), true, false);
generate_eve_span_company_for_primitive(l, ns, cstr("RefListNodeAliceShinyMeshHand"), true, false);
generate_Option_templ_inst_eve_header(l, ns, (option_template_instantiation_op){
.T = cstr("GenericMeshTopology")
});
}
#endif

View File

@ -7,14 +7,13 @@
void generate_l1_lucy_headers(){
SpanU8 l = cstr("l1"), ns = cstr("lucy");
mkdir_nofail("l1/eve/lucy");
generate_List_templ_inst_eve_header(l, ns, (list_instantiation_op){
.T = cstr("LucyImage"), .t_primitive = true}, true);
generate_Option_templ_inst_eve_header(l, ns, (option_template_instantiation_op){
.T = cstr("LucyImage"), .t_primitive = true});
generate_eve_span_company_for_primitive(l, ns, cstr("OptionLucyImage"), true, false);
generate_eve_span_company_for_primitive(l, ns, cstr("KVPU32ToLucyStoredGlyph"), true, false);
generate_eve_span_company_for_primitive(l, ns, cstr("KVPU32ToLucyFaceFixedSize"), true, false);
generate_eve_span_company_for_non_primitive_non_clonable(l, ns, cstr("LucyGlyphCachingRequest"), true, true);
/* Vector of iterators */
generate_eve_span_company_for_primitive(l, ns, cstr("RefListNodeLucyImage"), true, false);
generate_util_templ_inst_eve_header(l, ns, (util_templates_instantiation_options){
.T = cstr("LucyPositionedStagingGlyph"), .vec = true, .sort = true,

View File

@ -46,72 +46,9 @@ NODISCARD VecU8 generate_texture_data_struct_and_necc_methods(SpanU8 tex, SpanU8
"size_t %s_get_size_in_bytes(const %s* self) {\n"
SPACE "return self->pixels.len * sizeof(%s);\n"
"}\n\n", tex, tex, memb));
/* Method _to_bitmap_text()
* We use the assumption that bytes in type member are tightly packed
* Actually, our current method of texture read/write is super inefficient
*/
VecU8_append_vec(&res, VecU8_fmt(
"VecU8 %s_to_bitmap_text(const %s* self) {\n"
SPACE "assert(SIZE_MAX / self->pixels.len >= 100);\n"
SPACE "size_t len = self->pixels.len * sizeof(%s);\n"
SPACE "VecU8 res = VecU8_new_zeroinit(8 + len);\n"
SPACE "size_t width = self->width;\n"
SPACE "size_t height = self->pixels.len / self->width;\n"
SPACE "assert(UINT32_MAX / width >= 10 && UINT32_MAX / height >= 10);\n"
SPACE "for (int i = 0; i < 4; i++)\n"
SPACE SPACE "*VecU8_mat(&res, 0 + i) = (width >> (8 * i)) & 0xff;\n"
SPACE "for (int i = 0; i < 4; i++)\n"
SPACE SPACE "*VecU8_mat(&res, 4 + i) = (height >> (8 * i)) & 0xff;\n"
SPACE "memcpy(res.buf + 8, self->pixels.buf, len);\n"
SPACE "return res;\n"
"}\n\n", tex, tex, memb));
/* Method _write_to_file
* Aborts on failure */
VecU8_append_vec(&res, VecU8_fmt(
"void %s_write_to_file(const %s* self, const char* path) {\n"
SPACE "VecU8 data = %s_to_bitmap_text(self);\n"
SPACE "write_whole_file_or_abort(path, VecU8_to_span(&data));\n"
SPACE "VecU8_drop(data);\n"
"}\n\n", tex, tex, tex));
/* Result<tex, SpanU8> structure */
VecU8 g_resoftex = get_ResultType_inst_name(tex, cstr("SpanU8"));
SpanU8 resoftex = VecU8_to_span(&g_resoftex);
VecU8_append_vec(&res, generate_result_template_inst(tex, cstr("SpanU8"), false, true));
/* I also add this, because why not?? Maye I will use it in the future... */
/* Result<tex, VecU8> structure */
VecU8_append_vec(&res, generate_result_template_inst(tex, cstr("VecU8"), false, false));
/* Method _from_bitmap_text()
* We assume that bytes are tightly packed in member type */
VecU8_append_vec(&res, VecU8_fmt(
"%s %s_from_bitmap_text(SpanU8 text) {\n"
SPACE "if (text.len < 8)\n"
SPACE SPACE "return (%s){.variant = Result_Err, .err = cstr(\"No header *crying emoji*\")};\n"
SPACE "size_t width = 0, height = 0;\n"
SPACE "for (int i = 0; i < 4; i++)\n"
SPACE SPACE "width |= (((size_t)*SpanU8_at(text, 0 + i)) << (8 * i));\n"
SPACE "for (int i = 0; i < 4; i++)\n"
SPACE SPACE "height |= (((size_t)*SpanU8_at(text, 4 + i)) << (8 * i));\n"
SPACE "if (SIZE_MAX / width / height < 100 || UINT32_MAX / width < 10 || UINT32_MAX / height < 10)\n"
SPACE SPACE "return (%s){.variant = Result_Err, .err = cstr(\"Image is too big\")};\n"
SPACE "size_t len = width * height * sizeof(%s);\n"
SPACE "if (text.len < 8 + len)\n"
SPACE SPACE "return (%s){.variant = Result_Err, .err = cstr(\"Texture size and file size mismatch\")};\n"
SPACE "%s res = %s_new(width, height);\n"
SPACE "memcpy(res.pixels.buf, text.data + 8, len);\n"
SPACE "return (%s){.variant = Result_Ok, .ok = res};\n"
"}\n\n", resoftex, tex, resoftex, resoftex, memb, resoftex, tex, tex, resoftex));
/* Method _read_from_file */
VecU8_append_vec(&res, VecU8_fmt(
"%s %s_read_from_file(SpanU8 path) {\n"
SPACE "VecU8 data = read_whole_file_or_abort(path);\n"
SPACE "%s res = %s_from_bitmap_text(VecU8_to_span(&data));\n"
SPACE "if (res.variant != Result_Ok) {\n"
SPACE SPACE "fprintf(stderr, \"Tried loading bitmap texture from file, but encountered decoding error: \");\n"
SPACE SPACE "SpanU8_fprint(res.err, stderr);\n"
SPACE SPACE "abortf(\"\\n\");\n"
SPACE "}\n"
SPACE "VecU8_drop(data);\n"
SPACE "return res.ok;\n"
"}\n\n", tex, tex, resoftex, tex));
/* Method _is_inside() */
VecU8_append_vec(&res, VecU8_fmt(
"bool %s_is_inside(const %s* self, S32 x, S32 y) {\n"
@ -146,7 +83,6 @@ NODISCARD VecU8 generate_texture_data_struct_and_necc_methods(SpanU8 tex, SpanU8
SPACE "}\n"
"}\n\n", tex, tex, memb, tex, luminosity_formula));
VecU8_drop(g_resoftex);
VecU8_drop(g_pixvec);
return res;
}

View File

@ -8,7 +8,7 @@
typedef struct {
VecU8 result;
VecU8 nt_filename;
VecU8 filename;
} GeneratedHeader;
NODISCARD GeneratedHeader begin_header(SpanU8 filename) {
@ -26,14 +26,13 @@ NODISCARD GeneratedHeader begin_header(SpanU8 filename) {
VecU8_append_span(&res, cstr("\n#define "));
VecU8_append_vec(&res, guard);
VecU8_append_span(&res, cstr("\n/* Automatically generated file. Do not edit it. */\n\n"));
return (GeneratedHeader){.result = res, .nt_filename = VecU8_fmt("%s%c", filename, 0) };
return (GeneratedHeader){.result = res, .filename = VecU8_from_span(filename) };
}
/* Codegen script's working directory should be `gen` */
void finish_header(GeneratedHeader header) {
VecU8_append_span(&header.result, cstr("#endif\n"));
write_whole_file_or_abort((const char*)header.nt_filename.buf, VecU8_to_span(&header.result));
VecU8_drop(header.nt_filename);
write_file_by_path(header.filename, VecU8_to_span(&header.result));
VecU8_drop(header.result);
}
@ -43,9 +42,7 @@ void finish_header(GeneratedHeader header) {
#define SPACE16 " "
void finish_layer(SpanU8 layer_name) {
VecU8 nt_name = VecU8_fmt("%s/dorothy.txt%c", layer_name, 0);
write_whole_file_or_abort((const char*)nt_name.buf, cstr(""));
VecU8_drop(nt_name);
write_file_by_path(VecU8_fmt("%s/dorothy.txt", layer_name), cstr(""));
}
int get_number_of_parts_in_header_namespace(SpanU8 ns) {
@ -88,9 +85,7 @@ NODISCARD VecU8 prepend_spaces_to_SpanU8_lines(SpanU8 lines, int tabulation){
void generate_SOME_templ_inst_eve_header(SpanU8 layer, SpanU8 bonus_ns, VecU8 body, VecU8 name){
VecU8 text = VecU8_fmt("/* Automatically generated file. Don't edit it.\n"
"* Don't include it in more than one place */\n\n%v", body);
VecU8 nt_path = VecU8_fmt("%s/eve/%s/%v.h%c", layer, bonus_ns, name, 0);
write_whole_file_or_abort((const char*)nt_path.buf, VecU8_to_span(&text));
VecU8_drop(nt_path);
write_file_by_path(VecU8_fmt("%s/eve/%s/%v.h", layer, bonus_ns, name), VecU8_to_span(&text));
VecU8_drop(text);
}
@ -116,4 +111,9 @@ NODISCARD VecU8 codegen_include_relative_to_root(SpanU8 bonus_ns, SpanU8 abs_pat
return res;
}
/* returns back `type` string, but if it is "", returns "void" instead */
SpanU8 c_type_empty_means_void(SpanU8 type){
return type.len > 0 ? type : cstr("void");
}
#endif

View File

@ -209,7 +209,7 @@ NODISCARD VecU8 VecU8_fmt(const char* fmt, ...) {
}
// todo: generate a special span method to check equality of contents
bool strings_in_spans_equal(SpanU8 a, SpanU8 b) {
bool SpanU8_cont_equal(SpanU8 a, SpanU8 b) {
if (a.len != b.len)
return false;
for (size_t i = 0; i < a.len; i++) {
@ -235,7 +235,7 @@ U32 SpanU8_decode_as_utf8(SpanU8* rem){
if (rem->len < (size_t)sz)
return 0;
U32 res = first & (b - 1);
for (int i = 1; i < sz; i++) {
for (int i = 1; i <= sz; i++) {
U8 th = rem->data[0];
if ((th & 0b11000000) != 0b10000000)
return 0;
@ -252,4 +252,12 @@ U32 SpanU8_decode_as_utf8(SpanU8* rem){
return 0;
}
bool SpanU8_is_prefix(SpanU8 a, SpanU8 str){
return str.len >= a.len && SpanU8_cont_equal(a, SpanU8_span(str, 0, a.len));
}
bool SpanU8_is_postfix(SpanU8 a, SpanU8 str){
return str.len >= a.len && SpanU8_cont_equal(a, SpanU8_span(str, str.len - a.len, a.len));
}
#endif

View File

@ -13,12 +13,4 @@ typedef struct{
U32 len;
} U32Segment;
U64 U64Segment_get_length_resp_alignment(U64Segment self, U8 alignment_exp) {
if (self.start & ((1ull << alignment_exp) - 1)) {
U64 pad_left = (1ull << alignment_exp) - (self.start & ((1ull << alignment_exp) - 1));
return self.len >= pad_left ? self.len - pad_left : 0;
}
return self.len;
}
#endif

View File

@ -16,24 +16,18 @@ typedef struct {
};
} Result_VecU8_or_int;
void Result_VecU8_or_int_drop(Result_VecU8_or_int obj) {
if (obj.variant == Result_Ok)
VecU8_drop(obj.Ok);
}
typedef struct {
Result_variant variant;
int Err;
} Result_ok_or_int;
void Result_ok_or_int_drop(Result_ok_or_int obj) {}
NODISCARD VecU8 read_whole_file_or_abort(SpanU8 path) {
VecU8 filename = VecU8_fmt("%s%c", path, 0);
FILE* fp = fopen((const char*)filename.buf, "rb");
/* path is VecU8. Aborts on error */
NODISCARD VecU8 read_file_by_path(VecU8 path){
VecU8_append(&path, 0);
FILE* fp = fopen((const char*)path.buf, "rb");
if (!fp)
abortf("Can't open file %s: %s\n", (const char*)filename.buf, strerror(errno));
VecU8_drop(filename);
abortf("Can't open file %s: %s\n", (const char*)path.buf, strerror(errno));
VecU8_drop(path);
if (fseek(fp, 0, SEEK_END) != 0) {
abortf("fseek: %s\n", strerror(errno));
}
@ -46,23 +40,18 @@ NODISCARD VecU8 read_whole_file_or_abort(SpanU8 path) {
}
VecU8 result = (VecU8){.buf = safe_malloc(file_size), .len = file_size, .capacity = file_size};
size_t nread = fread(result.buf, 1, (size_t)file_size, fp);
if (nread < file_size) {
if ((long)nread < file_size) {
abortf("fread\n");
}
fclose(fp);
return result;
}
NODISCARD VecU8 read_file_by_path(VecU8 path){
VecU8 content = read_whole_file_or_abort(VecU8_to_span(&path));
VecU8_drop(path);
return content;
}
void write_whole_file_or_abort(const char* filename, SpanU8 content) {
FILE* fd = fopen(filename, "wb");
void write_file_by_path(VecU8 path, SpanU8 content){
VecU8_append(&path, 0);
FILE* fd = fopen((const char*)path.buf, "wb");
if (!fd) {
abortf("Can't open file %s: %s\n", filename, strerror(errno));
abortf("Can't open file %s: %s\n", (const char*)path.buf, strerror(errno));
}
if (fwrite(content.data, 1, content.len, fd) < content.len) {
abortf("fwrite\n");

View File

@ -3,38 +3,38 @@
int main(){
{
VecU8 res = VecU8_fmt("%i", 0);
check(strings_in_spans_equal(VecU8_to_span(&res), cstr("0")));
check(SpanU8_cont_equal(VecU8_to_span(&res), cstr("0")));
VecU8_drop(res);
}
{
VecU8 res = VecU8_fmt("%i%i%i%i", -1LL, 0LL, 44LL, -231LL);
check(strings_in_spans_equal(VecU8_to_span(&res), cstr("-1044-231")));
check(SpanU8_cont_equal(VecU8_to_span(&res), cstr("-1044-231")));
VecU8_drop(res);
}
{
VecU8 res = VecU8_fmt("%i", 44LL);
check(strings_in_spans_equal(VecU8_to_span(&res), cstr("44")));
check(SpanU8_cont_equal(VecU8_to_span(&res), cstr("44")));
VecU8_drop(res);
}
{
VecU8 res = VecU8_fmt("%u", 44ULL);
check(strings_in_spans_equal(VecU8_to_span(&res), cstr("44")));
check(SpanU8_cont_equal(VecU8_to_span(&res), cstr("44")));
VecU8_drop(res);
}
{
VecU8 res = VecU8_fmt("%u %i", 18446744073709551615ULL, -1LL);
check(strings_in_spans_equal(VecU8_to_span(&res), cstr("18446744073709551615 -1")));
check(SpanU8_cont_equal(VecU8_to_span(&res), cstr("18446744073709551615 -1")));
VecU8_drop(res);
}
{
VecU8 res = VecU8_fmt("%i %i", 9223372036854775807LL, -9223372036854775807LL-1);
check(strings_in_spans_equal(VecU8_to_span(&res), cstr("9223372036854775807 -9223372036854775808")));
check(SpanU8_cont_equal(VecU8_to_span(&res), cstr("9223372036854775807 -9223372036854775808")));
VecU8_drop(res);
}
{
VecU8 vec2 = vcstr("vec2");
VecU8 res = VecU8_fmt("%i %v %i", -1230LL, vec2, 1340LL);
check(strings_in_spans_equal(VecU8_to_span(&res), cstr("-1230 vec2 1340")));
check(SpanU8_cont_equal(VecU8_to_span(&res), cstr("-1230 vec2 1340")));
VecU8_drop(res);
}
return 0;

View File

@ -4,13 +4,16 @@
#include "l1_5_templ_very_base.h"
#include "margaret.h"
#include "lucy.h"
#include "gui.h"
int main() {
mkdir_nofail("l1_5");
mkdir_nofail("l1_5/eve");
generate_l1_5_liza_headers();
generate_l1_5_template_instantiation_for_base_types();
generate_l1_5_template_instantiations_for_margaret();
generate_l1_5_lucy_headers();
generate_l1_5_gui_headers();
finish_layer(cstr("l1_5"));
return 0;
}

47
src/l1_5/anne/gui.h Normal file
View File

@ -0,0 +1,47 @@
#ifndef prototype1_src_l1_5_anne_gui_h
#define prototype1_src_l1_5_anne_gui_h
#include "../codegen/trait_wrap_boil.h"
void generate_l1_5_gui_headers(){
mkdir_nofail("l1_5/eve/gui");
SpanU8 l = cstr("l1_5"), ns = cstr("gui");
generate_trait_wrapper_templ_inst_eve_header(l, ns, (trait_wrapper_boil_options){
.trait = {
.name = cstr("Widget"),
.methods = (SpanNamedMethodSignatureRecordRef){
.data = (NamedMethodSignatureRecordRef[]){
{
.takes_self = true,
.takes_mut_self = true,
.params = (SpanNamedVariableRecordRef){
.data = (NamedVariableRecordRef[]){
{ .type = cstr("uvec2"), .name = cstr("max_limits") }
}, .len = 1
},
.return_type = cstr("uvec2"),
.name = cstr("DRAW_PREPARE"),
},
{
.takes_self = true,
.takes_mut_self = true,
.params = (SpanNamedVariableRecordRef){
.data = (NamedVariableRecordRef[]){
{ .type = cstr("ivec2"), .name = cstr("drawing_offset") },
{ .type = cstr("uvec2"), .name = cstr("surface_sz") },
{ .type = cstr("BorderS32"), .name = cstr("border") },
}, .len = 3
},
.return_type = cstr(""),
.name = cstr("DRAW"),
}
}, .len = 2
},
.drop_primitive = false,
.base_struct_name = cstr("Widget"),
},
.box = true, .mut_ref = true
});
}
#endif

View File

@ -4,8 +4,32 @@
#include "../codegen/trait_wrap_boil.h"
void generate_l1_5_liza_headers() {
mkdir_nofail("l1_5/liza");
// todo: use#include "../codegen/trait_wrap_boil.h"
mkdir_nofail("l1_5/eve/liza");
SpanU8 l = cstr("l1_5"), ns = cstr("liza");
generate_trait_wrapper_templ_inst_eve_header(l, ns, (trait_wrapper_boil_options){
.trait = {
.name = cstr("LizaInstrument"),
.methods = (SpanNamedMethodSignatureRecordRef){
// todo: request options for instrument
.data = (NamedMethodSignatureRecordRef[]){
{
.takes_self = true,
.params = (SpanNamedVariableRecordRef){
.data = (NamedVariableRecordRef[]){
{.type = cstr("double"), .name = cstr("frequency") },
{ .type = cstr("double"), .name = cstr("time") },
}, .len = 2
},
.return_type = cstr("BoxLizaSound"),
.name = cstr("ding"),
}
}, .len = 1
},
.drop_primitive = false,
.base_struct_name = cstr(""),
},
.box = true, .ref = true, .mut_ref = true
});
}
#endif

View File

@ -414,7 +414,8 @@ NODISCARD VecU8 generate_rbtree_Map_template_instantiation(map_instantiation_op
return res;
}
void generate_rbtree_Map_templ_inst_eve_header(SpanU8 layer, SpanU8 bonus_ns, map_instantiation_op op, bool generate_node_struct) {
void generate_rbtree_Map_templ_inst_eve_header(SpanU8 layer, SpanU8 bonus_ns, map_instantiation_op op,
bool generate_node_struct) {
generate_SOME_templ_inst_eve_header(layer, bonus_ns,
generate_rbtree_Map_template_instantiation(op, generate_node_struct), get_name_of_rbtree_map_structure(op));
}

View File

@ -11,6 +11,8 @@ typedef struct {
#include "../../../gen/l1/eve/embassy_l1_5/SpanNamedVariableRecordRef.h"
typedef struct {
bool takes_self;
bool takes_mut_self;
SpanNamedVariableRecordRef params;
SpanU8 return_type;
SpanU8 name;
@ -20,24 +22,36 @@ typedef struct {
typedef struct {
SpanNamedMethodSignatureRecordRef methods;
bool drop_primitive;
SpanU8 name;
/* It is usually either name or "void" */
SpanU8 base_struct_name;
} NamedTraitDefRecordRef;
NODISCARD VecU8 generate_trait_table_structure(NamedTraitDefRecordRef trait){
VecU8 res = VecU8_from_cstr("typedef struct {");
// todo: add iteration macro
VecU8 res = VecU8_from_cstr("typedef struct {\n");
for (size_t i = 0; i < trait.methods.len; i++) {
NamedMethodSignatureRecordRef method = *SpanNamedMethodSignatureRecordRef_at(trait.methods, i);
VecU8_append_vec(&res, VecU8_fmt(SPACE "%s (*%s)(", method.return_type, method.name));
VecU8_append_vec(&res, VecU8_fmt(SPACE "%s (*%s)(", c_type_empty_means_void(method.return_type), method.name));
if (method.takes_self) {
VecU8_append_vec(&res, VecU8_fmt(
method.takes_mut_self ? "%s*" : "const %s*",
c_type_empty_means_void(trait.base_struct_name)));
}
for (size_t p = 0; p < method.params.len; p++) {
NamedVariableRecordRef param = *SpanNamedVariableRecordRef_at(method.params, p);
if (p)
if (p || method.takes_self)
VecU8_append_span(&res, cstr(", "));
VecU8_append_span(&res, param.type);
}
VecU8_append_span(&res, cstr(");\n"));
}
VecU8_append_vec(&res, VecU8_fmt("} %s;\n\n", trait.name));
if (!trait.drop_primitive) {
VecU8_append_vec(&res, VecU8_fmt(
SPACE "void (*drop)(%s*);\n",
c_type_empty_means_void(trait.base_struct_name)));
}
VecU8_append_vec(&res, VecU8_fmt("} %s_Table;\n\n", trait.name));
return res;
}
@ -48,10 +62,113 @@ typedef struct {
bool mut_ref;
} trait_wrapper_boil_options;
/* (refkind, mut) in {(Ref, false), (MutRef, true), (Box, true)} */
void codegen_append_trait_wrapper_structure_some_refkind(VecU8* res, NamedTraitDefRecordRef trait,
SpanU8 refkind, bool mut){
VecU8_append_vec(res, VecU8_fmt(
"typedef struct {\n"
SPACE "%s%s* r;\n" /* epsilon / const, op.trait.base_struct_name */
SPACE "const %s_Table* t;\n" /* op.trait.name */
"} %s%s;\n\n", /* refkind, op.trait.name */
mut ? cstr("") : cstr("const "),
c_type_empty_means_void(trait.base_struct_name),
trait.name, refkind, trait.name));
}
/* (refkind, self_as_ptr) in {(Ref, false), (MutRef, false), (Box, true)} */
void codegen_append_trait_wrapper_some_method_some_refkind(VecU8* res, SpanU8 trait_name,
NamedMethodSignatureRecordRef method, SpanU8 refkind, bool self_as_ptr){
VecU8_append_vec(res, VecU8_fmt(
"%s %s%s_%s(%s%s%s self",
/* return_type, refkind, trait.name, method.name, refkind, trait.name */
c_type_empty_means_void(method.return_type),
refkind, trait_name, method.name, refkind, trait_name, self_as_ptr ? cstr("*") : cstr("")));
for (size_t p = 0; p < method.params.len; p++) {
NamedVariableRecordRef param = method.params.data[p];
VecU8_append_vec(res, VecU8_fmt(", %s %s", param.type, param.name));
}
VecU8_append_span(res, cstr("){\n" SPACE));
if (method.return_type.len > 0)
VecU8_append_span(res, cstr("return "));
VecU8_append_vec(res, VecU8_fmt("self%s""t->%s(",
self_as_ptr ? cstr("->") : cstr("."),
method.name));
if (method.takes_self) {
VecU8_append_vec(res, VecU8_fmt("self%s""r", self_as_ptr ? cstr("->") : cstr(".")));
}
for (size_t p = 0; p < method.params.len; p++) {
NamedVariableRecordRef param = method.params.data[p];
if (p > 0 || method.takes_self)
VecU8_append_span(res, cstr(", "));
VecU8_append_span(res, param.name);
}
VecU8_append_span(res, cstr(");\n}\n\n"));
}
NODISCARD VecU8 generate_trait_wrapper_boilerplate(trait_wrapper_boil_options op) {
/* Checking */
for (size_t i = 0; i < op.trait.methods.len; i++) {
NamedMethodSignatureRecordRef method = op.trait.methods.data[i];
assert(!method.takes_mut_self || method.takes_self);
}
VecU8 res = VecU8_new();
// todo: write it
VecU8_append_vec(&res, generate_trait_table_structure(op.trait));
if (op.ref) {
codegen_append_trait_wrapper_structure_some_refkind(&res, op.trait, cstr("Ref"), false);
for (size_t i = 0; i < op.trait.methods.len; i++) {
NamedMethodSignatureRecordRef method = op.trait.methods.data[i];
if (method.takes_mut_self)
continue;
codegen_append_trait_wrapper_some_method_some_refkind(&res, op.trait.name, method, cstr("Ref"), false);
}
}
if (op.mut_ref) {
codegen_append_trait_wrapper_structure_some_refkind(&res, op.trait, cstr("MutRef"), true);
for (size_t i = 0; i < op.trait.methods.len; i++) {
NamedMethodSignatureRecordRef method = op.trait.methods.data[i];
codegen_append_trait_wrapper_some_method_some_refkind(&res, op.trait.name, method, cstr("MutRef"), false);
}
}
if (op.box) {
codegen_append_trait_wrapper_structure_some_refkind(&res, op.trait, cstr("Box"), true);
for (size_t i = 0; i < op.trait.methods.len; i++) {
NamedMethodSignatureRecordRef method = op.trait.methods.data[i];
codegen_append_trait_wrapper_some_method_some_refkind(&res, op.trait.name, method, cstr("Box"), true);
}
VecU8_append_vec(&res, VecU8_fmt(
"void Box%s_drop(Box%s self){\n" /* trait.name, trait.name */
"%s" /* epsilon / calling self.t->drop() */
SPACE "free(self.r);\n"
"}\n\n",
op.trait.name, op.trait.name,
op.trait.drop_primitive ? cstr("") : cstr(SPACE "self.t->drop(self.r);\n")));
if (op.ref) {
VecU8_append_vec(&res, VecU8_fmt(
"Ref%s Box%s_ref(Box%s *self) {\n"
SPACE "return (Ref%s){.r = self->r, .t = self->t};\n"
"}\n\n", op.trait.name, op.trait.name, op.trait.name, op.trait.name));
}
if (op.mut_ref) {
VecU8_append_vec(&res, VecU8_fmt(
"MutRef%s Box%s_mut_ref(Box%s *self) {\n"
SPACE "return (MutRef%s){.r = self->r, .t = self->t};\n"
"}\n\n", op.trait.name, op.trait.name, op.trait.name, op.trait.name));
}
}
return res;
}
void generate_trait_wrapper_templ_inst_eve_header(SpanU8 layer, SpanU8 bonus_ns, trait_wrapper_boil_options op){
generate_SOME_templ_inst_eve_header(layer, bonus_ns, generate_trait_wrapper_boilerplate(op),
VecU8_from_span(op.trait.name));
}
void generate_trait_wrapper_templ_inst_guarded_header(SpanU8 layer, SpanU8 bonus_ns, SpanU8 dependencies,
trait_wrapper_boil_options op){
generate_SOME_templ_inst_guarded_header(layer, bonus_ns,
VecU8_fmt("#include <stdlib.h>\n%s", dependencies),
generate_trait_wrapper_boilerplate(op), VecU8_from_span(op.trait.name));
}
#endif

View File

@ -20,7 +20,7 @@ void stdin_skip_whitespaces(){
}
}
// Aborts on error
// Aborts on error, skips whitespaces
OptionU64 stdin_read_U64(){
stdin_skip_whitespaces();
U64 x = 0;

View File

@ -0,0 +1,230 @@
#ifndef prototype1_src_l1_5_core_parsing_string_h
#define prototype1_src_l1_5_core_parsing_string_h
#include "../../l1/core/VecU8_as_str.h"
#include <math.h>
void SpanU8_parsing_expect_char(SpanU8* rem, char ch){
if (rem->len == 0) {
abortf("Unexpected EOF. Syntax error\n");
}
if (*rem->data != (U8)ch) {
abortf("Expected %d, got %d. Syntax error\n", (int)(*rem->data), (int)ch);
}
rem->data++;
rem->len--;
}
/* if `expected` is prefix of `rem`, `rem` will be advanced by |`expected`| and true will be returned.
* Otherwise false is returned and `rem` is untouched */
bool SpanU8_parsing_try_read_prefix(SpanU8* rem, SpanU8 expected){
if (rem->len < expected.len) {
return false;
}
if (SpanU8_cont_equal(SpanU8_span(*rem, 0, expected.len), expected)) {
rem->data += expected.len;
rem->len -= expected.len;
return true;
}
return false;
}
bool SpanU8_parsing_try_read_char(SpanU8* rem, char ch){
if (rem->len == 0) {
return false;
}
if (rem->data[0] == (U8)ch) {
rem->data++;
rem->len--;
return true;
}
return false;
}
void SpanU8_parsing_skip_entire_line(SpanU8* rem){
while (rem->len > 0) {
U8 ch = *(rem->data++);
rem->len--;
if (ch == '\n')
break;
}
}
void SpanU8_parsing_skip_char(SpanU8* rem){
assert(rem->len > 0);
rem->data++;
rem->len--;
}
bool SpanU8_parsing_is_char_ahead(SpanU8* rem, char ch){
return rem->len > 0 ? rem->data[0] == (U8)ch : false;
}
/* Time to learn how to read integers */
/* returns positive on error, returns 0 on success */
int SpanU8_read_U64(SpanU8* rem_ret, U64* res_ret){
SpanU8 rem = *rem_ret;
U64 x = 0;
while (rem.len > 0) {
U8 ch = *rem.data;
if (!('0' <= ch && ch <= '9')) {
break;
}
U64 d = (U64)(ch - '0');
if (x == 0 && rem_ret->data != rem.data) {
return 1;
}
if (x > UINT64_MAX / 10) {
return 2;
}
x *= 10;
if (x > UINT64_MAX - d) {
return 2;
}
x += d;
rem.data++;
rem.len--;
}
if (rem_ret->data == rem.data) {
return 1;
}
*res_ret = x;
*rem_ret = rem;
return 0;
}
U64 SpanU64_expect_read_U64(SpanU8* rem){
U64 x;
int code = SpanU8_read_U64(rem, &x);
if (code)
abortf("Failed to read U64. Syntax error\n");
return x;
}
int SpanU8_read_S64(SpanU8* rem_ret, S64* ret){
SpanU8 rem = *rem_ret;
U64 x = 0;
bool saw_minus = false;
bool saw_digit = false;
while (rem.len > 0) {
U8 ch = *rem.data;
if ('0' <= ch && ch <= '9') {
U64 d = (U64)(ch - '0');
if (x == 0 && rem_ret->len - rem.len > (U64)saw_minus) {
return 1;
}
if (x > 9223372036854775808UL / 10) {
return 2;
}
x *= 10;
if (x > 9223372036854775808UL - d) {
return 2;
}
x += d;
saw_digit = true;
} else if (ch == '-') {
if (rem_ret->data != rem.data) {
break;
}
saw_minus = true;
} else {
break;
}
rem.data++;
rem.len--;
}
if (!saw_digit) {
return 1;
}
assert(x <= 9223372036854775808UL);
if (x == 9223372036854775808UL) {
if (saw_minus) {
*ret = -9223372036854775807L-1;
} else {
return 2;
}
} else {
if (saw_minus) {
*ret = -(S64)x;
} else {
*ret = (S64)x;
}
}
*rem_ret = rem;
return 0;
}
/* returns positive int on error, 0 on success */
int SpanU8_read_float(SpanU8* rem_ret, float* res_ret){
SpanU8 rem = *rem_ret;
float res = 0;
bool saw_minus = false;
bool saw_digit = false;
bool saw_dot = false;
float mul = 1;
while (rem.len > 0) {
U8 ch = *rem.data;
if (ch == '.') {
if (saw_dot) {
return 1;
}
saw_dot = true;
} else if (ch == '-') {
if (rem_ret->data != rem.data) {
break;
}
saw_minus = true;
} else if ('0' <= ch && ch <= '9') {
float d = (float)(ch - '0');
if (saw_dot) {
mul /= 10.f;
res = (res + d * mul);
} else {
res = (res * 10 + d);
}
saw_digit = true;
} else if (ch == 'e') {
SpanU8_parsing_skip_char(&rem);
S64 exp;
int ret = SpanU8_read_S64(&rem, &exp);
if (ret)
return ret;
if (exp > 1000 || exp < -999) {
return 2;
}
/* If compiler won't perform pow optimization here, I will throw my chair out of the window */
res = res * powf(10.f, (float)exp);
break;
} else {
break;
}
rem.data++;
rem.len--;
}
if (!saw_digit) {
return 1;
}
if (saw_dot && mul == 1.f) {
return 1;
}
if (saw_minus) {
res = -(res);
}
*res_ret = res;
*rem_ret = rem;
return 0;
}
float SpanU8_expect_read_float(SpanU8* rem){
float x;
int code = SpanU8_read_float(rem, &x);
if (code)
abortf("Failed to read float. Syntax error\n");
return x;
}
#endif

View File

@ -29,7 +29,7 @@ bool string_contains_string_ignorecase(SpanU8 str1, SpanU8 str2) {
bool is_string_in_string_vec(SpanU8 a, const VecVecU8* B) {
for (size_t i = 0; i < B->len; i++) {
if (strings_in_spans_equal(a, VecU8_to_span(VecVecU8_at(B, i))))
if (SpanU8_cont_equal(a, VecU8_to_span(VecVecU8_at(B, i))))
return true;
}
return false;

View File

@ -59,6 +59,7 @@ typedef struct {
typedef struct {
vec3 pos;
vec3 color;
} ShinyMeshVertexInc;
typedef struct {
@ -85,7 +86,6 @@ ShinyMeshTopology ShinyMeshTopology_clone(const ShinyMeshTopology* self) {
typedef struct{
mat4 model_t;
vec3 color_off;
vec3 color_on;
} ShinyMeshInstanceInc;

View File

@ -1,6 +1,9 @@
#ifndef prototype1_src_l2_alice_model_file_h
#define prototype1_src_l2_alice_model_file_h
#include "../../../gen/l1/VecAndSpan_vec2.h"
#include "../../../gen/l1/VecAndSpan_vec3.h"
#include "../../l1_5/core/parsing_string.h"
#include "../../l1/system/fileio.h"
#include "assets.h"
#include "stdalign.h"
@ -8,7 +11,7 @@
static_assert(sizeof(float) == 4, "...");
static_assert(sizeof(GenericMeshVertexInc) == 4 * (3 + 2), "...");
static_assert(alignof(GenericMeshVertexInc) == 4, "...");
static_assert(sizeof(ShinyMeshVertexInc) == 4 * (3), "...");
static_assert(sizeof(ShinyMeshVertexInc) == 4 * (3 + 3), "...");
static_assert(alignof(ShinyMeshVertexInc) == 4, "...");
/* Yes, at this point I really started thinking that maybe I should have written Alice as a template */
@ -26,10 +29,8 @@ void alice_write_generic_mesh_to_file(GenericMeshTopology model, VecU8 file_path
memcpy(buf, model.vertices.buf, model.vertices.len * sizeof(GenericMeshVertexInc));
buf += model.vertices.len * sizeof(GenericMeshVertexInc);
memcpy(buf, model.indexes.buf, model.indexes.len * sizeof(U32));
VecU8_append(&file_path, 0);
write_whole_file_or_abort((const char*)file_path.buf, VecU8_to_span(&res));
write_file_by_path(file_path, VecU8_to_span(&res));
GenericMeshTopology_drop(model);
VecU8_drop(file_path);
VecU8_drop(res);
}
@ -71,10 +72,8 @@ void alice_write_shiny_mesh_to_file(ShinyMeshTopology model, VecU8 file_path){
memcpy(buf, model.vertices.buf, model.vertices.len * sizeof(ShinyMeshVertexInc));
buf += model.vertices.len * sizeof(ShinyMeshVertexInc);
memcpy(buf, model.indexes.buf, model.indexes.len * sizeof(U32));
VecU8_append(&file_path, 0);
write_whole_file_or_abort((const char*)file_path.buf, VecU8_to_span(&res));
write_file_by_path(file_path, VecU8_to_span(&res));
ShinyMeshTopology_drop(model);
VecU8_drop(file_path);
VecU8_drop(res);
}
@ -103,6 +102,143 @@ ShinyMeshTopology alice_expect_read_shiny_mesh_from_file(VecU8 file_path){
return (ShinyMeshTopology){.vertices = vertices, .indexes = indexes};
}
/* Just read code, okay? Just read source code, I can't explain THAT */
int alice_obj_file_parser_try_read_vert_index(SpanU8* rem, U64 limit, S32* ret_ind){
SpanU8_parsing_try_read_char(rem, '/');
U64 x;
if (SpanU8_read_U64(rem, &x)) {
*ret_ind = -1;
} else {
if (x == 0)
return 1;
x--;
if (x >= limit)
return 3;
*ret_ind = (S32)x;
}
return 0;
}
/* In wavefront .obj file each face consists of 3 vertices and each vertex in a face
* can be specified in the following forms: v, v/vt, v//vn, v/vt/vn. vn is of course ignored,
* because only sussies store normal vectors in a file.
* Returns positive on error. 0 on success. Don't read source code
*/
int alice_obj_file_parser_try_read_vertex_data(SpanU8* rem, U64 vertices_pos_limit, U64 vertices_tex_limit,
S32* ret_pos_ind, S32* ret_tex_ind){
int ret;
ret = alice_obj_file_parser_try_read_vert_index(rem, vertices_pos_limit, ret_pos_ind);
if (ret) {
return 3;
}
if (*ret_pos_ind < 0) {
return 1;
}
ret = alice_obj_file_parser_try_read_vert_index(rem, vertices_tex_limit, ret_tex_ind);
if (ret > 0) {
return 3;
}
S32 who_cares;
alice_obj_file_parser_try_read_vert_index(rem, UINT64_MAX, &who_cares);
return 0;
}
GenericMeshVertexInc alice_obj_file_parser_retrieve_data_from_vertex_arrays(
const Vecvec3* vertex_pos, const Vecvec2* vertex_tex, S32 pos_ind, S32 tex_ind){
return (GenericMeshVertexInc){
.pos = *Vecvec3_at(vertex_pos, (U64)pos_ind),
.tex = tex_ind >= 0 ? *Vecvec2_at(vertex_tex, (U64)tex_ind) : (vec2){0, 0}
};
}
#include "../../../gen/l1/eve/alice/OptionGenericMeshTopology.h"
/* My life f****** sucks so much */
OptionGenericMeshTopology alice_read_generic_mesh_from_obj_file(VecU8 file_path){
Vecvec3 vertex_pos = Vecvec3_new();
Vecvec2 vertex_tex = Vecvec2_new();
VecU8 text_buffer = read_file_by_path(file_path);
VecGenericMeshVertexInc mesh_vertices = VecGenericMeshVertexInc_new();
VecU32 mesh_indexes = VecU32_new();
SpanU8 text = VecU8_to_span(&text_buffer);
while (text.len > 0) {
if (SpanU8_parsing_try_read_prefix(&text, cstr("v "))) {
float x, y, z;
if (SpanU8_read_float(&text, &x))
goto failure;
if (!SpanU8_parsing_try_read_char(&text, ' '))
goto failure;
if (SpanU8_read_float(&text, &y))
goto failure;
if (!SpanU8_parsing_try_read_char(&text, ' '))
goto failure;
if (SpanU8_read_float(&text, &z))
goto failure;
if (!SpanU8_parsing_try_read_char(&text, '\n'))
goto failure;
Vecvec3_append(&vertex_pos, (vec3){x, y, z});
} else if (SpanU8_parsing_try_read_prefix(&text, cstr("vt "))) {
float u, v;
if (SpanU8_read_float(&text, &u))
goto failure;
if (!SpanU8_parsing_try_read_char(&text, ' '))
goto failure;
if (SpanU8_read_float(&text, &v))
goto failure;
if (!SpanU8_parsing_try_read_char(&text, '\n'))
goto failure;
Vecvec2_append(&vertex_tex, (vec2){u, v});
} else if (SpanU8_parsing_try_read_prefix(&text, cstr("f "))) {
S32 pos_ind, tex_ind;
if (alice_obj_file_parser_try_read_vertex_data(&text,
vertex_pos.len, vertex_tex.len, &pos_ind, &tex_ind)) {
goto failure;
}
GenericMeshVertexInc A = alice_obj_file_parser_retrieve_data_from_vertex_arrays(
&vertex_pos, &vertex_tex, pos_ind, tex_ind);
if (!SpanU8_parsing_try_read_char(&text, ' '))
goto failure;
if (alice_obj_file_parser_try_read_vertex_data(&text,
vertex_pos.len, vertex_tex.len, &pos_ind, &tex_ind)) {
goto failure;
}
GenericMeshVertexInc B = alice_obj_file_parser_retrieve_data_from_vertex_arrays(
&vertex_pos, &vertex_tex, pos_ind, tex_ind);
if (!SpanU8_parsing_try_read_char(&text, ' '))
goto failure;
if (alice_obj_file_parser_try_read_vertex_data(&text,
vertex_pos.len, vertex_tex.len, &pos_ind, &tex_ind)) {
goto failure;
}
GenericMeshVertexInc C = alice_obj_file_parser_retrieve_data_from_vertex_arrays(
&vertex_pos, &vertex_tex, pos_ind, tex_ind);
if (!SpanU8_parsing_try_read_char(&text, '\n'))
goto failure;
VecGenericMeshVertexInc_append(&mesh_vertices, A);
VecGenericMeshVertexInc_append(&mesh_vertices, B);
VecGenericMeshVertexInc_append(&mesh_vertices, C);
U64 k = mesh_vertices.len;
VecU32_append_span(&mesh_indexes, (SpanU32){.data = (U32[]){k - 3, k - 2, k - 1}, .len = 3});
} else {
SpanU8_parsing_skip_entire_line(&text);
}
}
/* End */
return Some_GenericMeshTopology((GenericMeshTopology){.vertices = mesh_vertices, .indexes = mesh_indexes});
failure:
VecGenericMeshVertexInc_drop(mesh_vertices);
VecU32_drop(mesh_indexes);
return None_GenericMeshTopology();
}
GenericMeshTopology alice_expect_read_generic_mesh_from_obj_file(VecU8 file_path){
OptionGenericMeshTopology option = alice_read_generic_mesh_from_obj_file(file_path);
return OptionGenericMeshTopology_expect(option);
}
/* No beauty, just pure brute force */
#endif
#endif

View File

@ -11,6 +11,7 @@ Callbacks(..), aliceMainloop, newAlice, aliceSetSkyColor, aliceNewLucyFace,
aliceLucyFaceOfSize, lucyFaceAddGlyphs, aliceClearText, aliceAddText,
aliceAddGenericMeshHand, aliceGenericMeshResizeInstanceArr, aliceGenericMeshSetInst,
aliceAddShinyMeshHand, aliceShinyMeshResizeInstanceArr, aliceShinyMeshSetInst, aliceGetCamBack,
aliceGetCamRight, aliceGetCamUp, aliceSetFOV,
aliceGetCamPos, aliceSetCamPos, aliceSetPointLightCount, aliceSetPointLight,
aliceIsPressed
) where
@ -22,7 +23,6 @@ import Data.Int (Int8, Int16, Int32, Int64)
import Foreign.Ptr (Ptr, FunPtr, nullPtr, plusPtr, castPtr)
import Foreign.Marshal.Alloc (alloca)
import Foreign.Storable (Storable(..))
import Data.IORef (newIORef, readIORef, writeIORef, modifyIORef)
import qualified Data.Text
import Data.Text.Encoding (encodeUtf8)
import Data.ByteString (useAsCStringLen)
@ -58,17 +58,16 @@ instance Storable AliceGenericMeshInstance where
peek _ = error "Please don't"
poke ptr (AliceGenericMeshInstance modelT) = poke (castPtr ptr :: Ptr Mat4) modelT
-- model_t color_off color_on
data AliceShinyMeshInstance = AliceShinyMeshInstance Mat4 Vec3 Vec3
-- model_t color_on
data AliceShinyMeshInstance = AliceShinyMeshInstance Mat4 Vec3
instance Storable AliceShinyMeshInstance where
sizeOf _ = sizeOf (undefined :: Mat4)
sizeOf _ = sizeOf (undefined :: Mat4) + sizeOf (undefined :: Vec3)
alignment _ = 4
peek _ = error "Don't do that, please"
poke ptr (AliceShinyMeshInstance modelT colorOff colorOn) = do
poke ptr (AliceShinyMeshInstance modelT colorOn) = do
poke (castPtr ptr :: Ptr Mat4) modelT
poke (castPtr (ptr `plusPtr` (sizeOf (undefined :: Mat4)) ) :: Ptr Vec3) colorOff
poke (castPtr (ptr `plusPtr` (sizeOf (undefined :: Mat4)) `plusPtr` (sizeOf (undefined :: Vec3))) :: Ptr Vec3) colorOn
poke (castPtr (ptr `plusPtr` (sizeOf (undefined :: Mat4))) :: Ptr Vec3) colorOn
-- pos color
data AlicePointLight = AlicePointLight Vec3 Vec3
@ -97,17 +96,6 @@ aliceMainloop alice cb = alloca $ \ptr -> do
poke ptr cb
allieAliceMainloop alice ptr
--aliceClearScreenTextLabel :: AliceAnotherFrameCap s -> IO ()
--aliceClearScreenTextLabel (AliceAnotherFrameCap alice) = allieAliceClearScreenText alice
--aliceAddScreenTextLabel :: AliceAnotherFrameCap s -> String -> IO ()
--aliceAddScreenTextLabel (AliceAnotherFrameCap alice) str = useAsCStringLen
-- (encodeUtf8 $ Data.Text.pack $ str) $ \(cstr, len) ->
-- allieAliceAddScreenTextLabel alice (castPtr cstr) (fromIntegral len)
--allieRunAlice :: Callbacks ->
useAsUtf8StringLen :: String -> (Ptr Word8 -> Word64 -> IO a) -> IO a
useAsUtf8StringLen str cb = useAsCStringLen (encodeUtf8 $ Data.Text.pack $ str) $ \(cstr, len) -> cb (castPtr cstr) (fromIntegral len)
@ -180,7 +168,20 @@ aliceGetCamBack alice = alloca $ \ptr -> do
allie_alice_get_cam_back alice ptr
peek ptr
-- todo: add right and up
foreign import ccall "allie_alice_get_cam_right" allie_alice_get_cam_right :: Alice -> Ptr Vec3 -> IO ()
aliceGetCamRight :: Alice -> IO Vec3
aliceGetCamRight alice = alloca $ \ptr -> do
allie_alice_get_cam_right alice ptr
peek ptr
foreign import ccall "allie_alice_get_cam_up" allie_alice_get_cam_up :: Alice -> Ptr Vec3 -> IO ()
aliceGetCamUp :: Alice -> IO Vec3
aliceGetCamUp alice = alloca $ \ptr -> do
allie_alice_get_cam_up alice ptr
peek ptr
foreign import ccall "allie_alice_get_cam_pos" allie_alice_get_cam_pos :: Alice -> Ptr Vec3 -> IO ()
@ -194,6 +195,9 @@ foreign import ccall "allie_alice_set_cam_pos" allie_alice_set_cam_pos :: Alice
aliceSetCamPos :: Alice -> Vec3 -> IO ()
aliceSetCamPos alice (Vec3 x y z) = allie_alice_set_cam_pos alice x y z
-- Easy mapping
foreign import ccall "allie_alice_set_fov" aliceSetFOV :: Alice -> Float -> IO ()
-- Maps well
foreign import ccall "allie_alice_set_point_light_count" aliceSetPointLightCount :: Alice -> Int -> IO ()

View File

@ -1,4 +1,5 @@
module Geom(Vec2(..), Vec3(..), Vec4(..), Mat4(..), Addable(..), Multipliable(..), mat4Transit) where
module Geom(Vec2(..), Vec3(..), Vec4(..), Mat4(..), Addable(..), Multipliable(..), mat4Transit, mat4rot3d,
HasLength, normalize) where
import Foreign.Storable(Storable(..))
import Foreign.Ptr (Ptr, castPtr, plusPtr)
@ -43,10 +44,24 @@ instance Multipliable Vec4 Float Vec4 where
data Mat4 = Mat4 !Vec4 !Vec4 !Vec4 !Vec4
instance Multipliable Mat4 Vec4 Vec4 where
(Mat4 vx vy vz vw) ^*^ (Vec4 ax ay az aw) = (vx ^*^ ax ^+^ vy ^*^ ay ^+^ vz ^*^ az ^+^ vw ^*^ aw)
instance Multipliable Mat4 Mat4 Mat4 where
m ^*^ (Mat4 bx by bz bw) = Mat4 (m ^*^ bx) (m ^*^ by) (m ^*^ bz) (m ^*^ bw)
mat4Transit :: Vec3 -> Mat4
mat4Transit (Vec3 x y z) = Mat4 (Vec4 1 0 0 0) (Vec4 0 1 0 0) (Vec4 0 0 1 0) (Vec4 x y z 1)
mat4rot3d :: Vec3 -> Float -> Mat4
mat4rot3d (Vec3 rx ry rz) a = let cosa = cos(a) in let sina = sin(a) in
Mat4
(Vec4 (rx * rx * (1 - cosa) + cosa) (rx * ry * (1 - cosa) + sina * rz) (rx * rz * (1 - cosa) - sina * ry) 0)
(Vec4 (rx * ry * (1 - cosa) - sina * rz) (ry * ry * (1 - cosa) + cosa) (ry * rz * (1 - cosa) + sina * rx) 0)
(Vec4 (rx * rz * (1 - cosa) + sina * ry) (ry * rz * (1 - cosa) - sina * rx) (rz * rz * (1 - cosa) + cosa) 0)
(Vec4 0 0 0 1)
instance Storable Vec2 where
sizeOf _ = 2 * sizeOf (undefined :: Float)
@ -112,4 +127,13 @@ instance Storable Mat4 where
poke (castPtr ptr) v1
poke (ptr `plusPtr` vec4Size) v2
poke (ptr `plusPtr` (2 * vec4Size)) v3
poke (ptr `plusPtr` (3 * vec4Size)) v4
poke (ptr `plusPtr` (3 * vec4Size)) v4
class HasLength a where
vlength :: a -> Float
normalize :: (Multipliable a Float a, HasLength a) => a -> a
normalize v = v ^*^ (1 / (vlength v))
instance HasLength Vec2 where
vlength (Vec2 a b) = sqrt (a * a + b * b)

View File

@ -431,35 +431,35 @@ AlicePipeline0b create_graphics_pipeline_0_b(
{
.location = 1, .binding = 0,
.format = VK_FORMAT_R32G32B32_SFLOAT,
.offset = offsetof(ShinyMeshVertexInc, color),
},
{
.location = 2, .binding = 0,
.format = VK_FORMAT_R32G32B32_SFLOAT,
.offset = offsetof(ShinyMeshVertex, normal),
},
/* This is a mat4 datatype, so it will take 4 entire 'locations' */
{
.location = 2, .binding = 1,
.location = 3, .binding = 1,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = offsetof(ShinyMeshInstanceInc, model_t) + offsetof(mat4, x)
},
{
.location = 3, .binding = 1,
.location = 4, .binding = 1,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = offsetof(ShinyMeshInstanceInc, model_t) + offsetof(mat4, y)
},
{
.location = 4, .binding = 1,
.location = 5, .binding = 1,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = offsetof(ShinyMeshInstanceInc, model_t) + offsetof(mat4, z)
},
{
.location = 5, .binding = 1,
.location = 6, .binding = 1,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = offsetof(ShinyMeshInstanceInc, model_t) + offsetof(mat4, w)
},
{
.location = 6, .binding = 1,
.format = VK_FORMAT_R32G32B32_SFLOAT,
.offset = offsetof(ShinyMeshInstanceInc, color_off)
},
{
.location = 7, .binding = 1,
.format = VK_FORMAT_R32G32B32_SFLOAT,
@ -660,7 +660,6 @@ void Jane_alice_destroy(VkDevice device, Jane_alice jane) {
vkDestroyFence(device, jane.roxy, NULL);
}
// todo: handle case where presentation and graphics are from the same family
typedef struct {
VkQueue graphics_queue;
VkQueue presentation_queue;
@ -824,7 +823,14 @@ struct Alice {
};
ListNodeAliceGenericMeshHand* Alice_add_generic_mesh(Alice* alice, AliceGenericMeshPath paths){
GenericMeshTopology topology = alice_expect_read_generic_mesh_from_file(paths.topology_path);
GenericMeshTopology topology;
if (SpanU8_is_postfix(cstr(".AliceGenericMesh"), VecU8_to_span(&paths.topology_path) )) {
topology = alice_expect_read_generic_mesh_from_file(paths.topology_path);
} else if (SpanU8_is_postfix(cstr(".obj"), VecU8_to_span(&paths.topology_path) )) {
topology = alice_expect_read_generic_mesh_from_obj_file(paths.topology_path);
} else {
abortf("Иди своей дорогой\n");
}
ListNodeAliceGenericMeshHand* mm_node = safe_calloc(1, sizeof(ListNodeAliceGenericMeshHand));
AliceGenericMeshHand* mm = &mm_node->el;
@ -1395,83 +1401,6 @@ void recreate_swapchain(Alice *alice) {
alice->swfb = new_swfb;
}
// todo: delete it
/* It is just a stupid example */
void update_state(Alice* alice) {
float fl = AliceWaylandApp_get_elapsed_time(&alice->wl);
// todo: ok, maybe I don't want an example. I am good enough
// if (alice->wl.first_0x80_keys[XKB_KEY_w])
// CamControlInfo_forward(&alice->scene.cam, fl);
// if (alice->wl.first_0x80_keys[XKB_KEY_s])
// CamControlInfo_backward(&alice->scene.cam, fl);
// if (alice->wl.first_0x80_keys[XKB_KEY_a])
// CamControlInfo_left(&alice->scene.cam, fl);
// if (alice->wl.first_0x80_keys[XKB_KEY_d])
// CamControlInfo_right(&alice->scene.cam, fl);
// if (alice->wl.first_0x80_keys[XKB_KEY_q])
// CamControlInfo_down(&alice->scene.cam, fl);
// if (alice->wl.first_0x80_keys[XKB_KEY_e])
// CamControlInfo_up(&alice->scene.cam, fl);
//
// if (alice->wl.first_0x80_keys[XKB_KEY_bracketright]) {
// for (size_t i = 0; i < alice->scene.smeshnyavka_3.len; i++) {
// ObjectInfo* oi = &alice->scene.smeshnyavka_3.buf[i];
// vec3 p1 = alice->scene.cam.pos;
// vec3 r = vec3_normalize(vec3_minus_vec3(p1, oi->pos));
// oi->rotation = mat3_mul_mat3(marie_3d_rot_mat3(r, fl * 0.7f), oi->rotation);
// Scene_update_smeshnyavka_3(&alice->scene, i);
// }
// }
// if (alice->wl.first_0x80_keys[XKB_KEY_bracketleft]) {
// for (size_t i = 0; i < alice->scene.smeshnyavka_1.len; i++) {
// ObjectInfo* oi = &alice->scene.smeshnyavka_1.buf[i];
// oi->rotation = mat3_mul_mat3(marie_3d_rot_mat3((vec3){0, 0, 1}, fl * 0.4f), oi->rotation);
// Scene_update_smeshnyavka_1(&alice->scene, i);
// }
// }
// if (alice->wl.first_0x80_keys[XKB_KEY_minus]) {
// for (size_t i = 0; i < alice->scene.smeshnyavka_3.len; i++) {
// ObjectInfo* oi = &alice->scene.smeshnyavka_3.buf[i];
// vec3 p1 = alice->scene.cam.pos;
// float dist = vec3_length(vec3_minus_vec3(p1, oi->pos));
// float fac = 80/dist;
// oi->scale *= (1 - 0.01f * fl * fac);
// Scene_update_smeshnyavka_3(&alice->scene, i);
// }
// }
// if (alice->wl.first_0x80_keys[XKB_KEY_equal]) {
// for (size_t i = 0; i < alice->scene.smeshnyavka_3.len; i++) {
// ObjectInfo* oi = &alice->scene.smeshnyavka_3.buf[i];
// vec3 p1 = alice->scene.cam.pos;
// float dist = vec3_length(vec3_minus_vec3(p1, oi->pos));
// float fac = 80/dist;
// oi->scale *= (1 + 0.01f * fl * fac);
// Scene_update_smeshnyavka_3(&alice->scene, i);
// }
// }
//
// {
// GenericModelOnSceneMem* model = VecGenericModelOnSceneMem_mat(&alice->scene.generic_models, 0);
// assert(model->instance_attr.count >= 1);
// if (alice->wl.first_0x80_keys[XKB_KEY_j]) {
// alice->scene.smeshnyavka_1.buf[0].pos.x -= fl;
// Scene_update_smeshnyavka_1(&alice->scene, 0);
// }
// if (alice->wl.first_0x80_keys[XKB_KEY_k]) {
// alice->scene.smeshnyavka_1.buf[0].pos.z -= fl;
// Scene_update_smeshnyavka_1(&alice->scene, 0);
// }
// if (alice->wl.first_0x80_keys[XKB_KEY_l]) {
// alice->scene.smeshnyavka_1.buf[0].pos.z += fl;
// Scene_update_smeshnyavka_1(&alice->scene, 0);
// }
// if (alice->wl.first_0x80_keys[XKB_KEY_semicolon]) {
// alice->scene.smeshnyavka_1.buf[0].pos.x += fl;
// Scene_update_smeshnyavka_1(&alice->scene, 0);
// }
// }
}
/* It creates image views, descriptor sets, framebuffers. But not for generic models.
* If we ever gonna do defragmentation, this step would have to be repeated */
void alice_create_mem_dependant_vk_obj(Alice* alice){
@ -1737,18 +1666,6 @@ static void alice_mainloop_h_wl_keyboard_key(
alice->callbacks.on_wl_keyboard_key(alice->guest, keysym, key_action);
if (key_action == WL_KEYBOARD_KEY_STATE_RELEASED) {
if (keysym == XKB_KEY_1) {
// vec3 p = alice->cam_info.pos;
// p.y += 1.5f;
// ShinyModelOnSceneMem* model = VecShinyModelOnSceneMem_mat(&alice->scene.shiny_models, 0);
// assert(model->instance_attr.count >= 1);
// VecObjectInfo_mat(&alice->scene.smeshnyavka_3, 0)->pos = p;
// Scene_update_smeshnyavka_3(&alice->scene, 0);
//
// Pipeline0UBO* ubo = (Pipeline0UBO*)MargaretSubbuf_get_mapped(&alice->scene.pipeline0_ubo.staging_updatable);
// assert(ubo->point_light_count >= 1);
// ubo->point_light_arr[0].pos = p;
//
// printf("Point light source pos set to %f %f %f\n", p.x, p.y, p.z);
} else if (keysym == XKB_KEY_2) {
alice->rendering_config.hdr_factor /= 1.05f;
printf("hdr factor decreased to %f\n", alice->rendering_config.hdr_factor);
@ -1974,8 +1891,13 @@ Alice* Alice_new(){
alice->device = margaret_create_logical_device(alice->physical_device, alice->queue_fam);
vkGetDeviceQueue(alice->device, alice->queue_fam.for_graphics, 0, &alice->queues.graphics_queue);
vkGetDeviceQueue(alice->device, alice->queue_fam.for_presentation, 0, &alice->queues.presentation_queue);
if (alice->queue_fam.for_graphics == alice->queue_fam.for_presentation) {
vkGetDeviceQueue(alice->device, alice->queue_fam.for_graphics, 0, &alice->queues.graphics_queue);
alice->queues.presentation_queue = alice->queues.graphics_queue;
} else {
vkGetDeviceQueue(alice->device, alice->queue_fam.for_graphics, 0, &alice->queues.graphics_queue);
vkGetDeviceQueue(alice->device, alice->queue_fam.for_presentation, 0, &alice->queues.presentation_queue);
}
ResultMargaretChosenSwapchainDetailsOrSpanU8 swapchain_details_res = margaret_choose_swapchain_details(
alice->physical_device, alice->surface, alice->wl.sane_image_extent_limit);
@ -2042,11 +1964,10 @@ Alice* Alice_new(){
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
/* | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT */,
mem_type_id_device_local, 6, false, 16);
mem_type_id_device_local, 6, false, 10000);
alice->dev_local_images = MargaretImgAllocator_new(alice->device, alice->physical_device,
mem_type_id_device_local, 16);
mem_type_id_device_local, 16000000);
alice->jane = Jane_alice_create(alice->device);
/* Luckily, swapchain image allocation is not managed by me */
@ -2106,15 +2027,6 @@ void Alice_set_point_light(Alice* alice, int index, Pipeline0PointLight data){
ubo->point_light_arr[index] = data;
}
void Alice_clear_screen_text(Alice* alice){
LucyRenderer_clear(&alice->lucy_renderer);
}
void Alice_add_screen_text(Alice* alice, RBTreeNodeLucyFaceFixedSize* ffs, vec4 color, SpanU8 text, ivec2 start_pos){
LucyRenderer_add_text(&alice->lucy_renderer, ffs, color, 0, text, start_pos);
}
/* This function actually consumes alice handler. Alice must not be used after */
void Alice_mainloop(Alice* alice, const AliceCallbacks* callbacks) {
alice->callbacks.on_wl_keyboard_key = callbacks->on_wl_keyboard_key;
@ -2206,7 +2118,7 @@ void allie_alice_clear_text(Alice* alice){
void allie_alice_add_text(Alice* alice, RBTreeNodeLucyFaceFixedSize* ffs,
float color_x, float color_y, float color_z, float color_w, const U8* text_data, U64 text_len,
S32 start_pos_x, S32 start_pos_y){
LucyRenderer_add_text(&alice->lucy_renderer, ffs, (vec4){color_x, color_y, color_z, color_w}, 0,
LucyRenderer_add_simple_label(&alice->lucy_renderer, ffs, (vec4){color_x, color_y, color_z, color_w}, 0,
(SpanU8){text_data, text_len}, (ivec2){start_pos_x, start_pos_y});
}
@ -2236,26 +2148,6 @@ void allie_alice_shiny_mesh_resize_instance_arr(Alice* alice, ListNodeAliceShiny
AliceShinyMeshHand_resize_instance_arr(alice, &mesh_hand->el, new_count);
}
// void allie_alice_generic_mesh_set_inst(
// ListNodeAliceGenericMeshHand* mesh_hand, U64 index,
// float xx, float xy, float xz, float xw, float yx, float yy, float yz, float yw,
// float zx, float zy, float zz, float zw, float wx, float wy, float wz, float ww){
// AliceGenericMeshHand_set_inst(&mesh_hand->el, index, (GenericMeshInstanceInc){.model_t = {
// .x = {xx, xy, xz, xw}, .y = {yx, yy, yz, yw}, .z = {zx, zy, zz, zw}, .w = {wx, wy, wz, ww},
// }});
// }
//
// void allie_alice_shiny_mesh_set_inst(
// ListNodeAliceGenericMeshHand* mesh_hand, U64 index,
// float xx, float xy, float xz, float xw, float yx, float yy, float yz, float yw,
// float zx, float zy, float zz, float zw, float wx, float wy, float wz, float ww,
// float clr_off_x, float clr_off_y, float clr_off_z, float clr_off_w,
// float clr_on_x, float clr_on_y, float clr_on_z, float clr_on_w){
// AliceShinyMeshHand_set_inst(&mesh_hand->el, index, (ShinyMeshInstanceInc){.model_t = {
// }, .color_on = {}});
//
// }
void allie_alice_generic_mesh_set_inst(
ListNodeAliceGenericMeshHand* mesh_hand, U64 index, const GenericMeshInstanceInc* inst){
AliceGenericMeshHand_set_inst(&mesh_hand->el, index, *inst);
@ -2287,7 +2179,7 @@ void allie_alice_set_cam_pos(Alice* alice, float x, float y, float z){
}
void allie_alice_set_fov(Alice* alice, float fov){
alice->cam_info.cam.fov = fov;
alice->cam_info.cam.fov = MIN_float(MAX_float(fov, 0.001), M_PIf - 0.01);
}
void allie_alice_set_point_light_count(Alice* alice, int new_count){

View File

@ -598,37 +598,37 @@ GenericMeshTopology generate_one_fourth_of_a_cylinder(float w, float r, U32 k) {
U32 quad_to_triangles_conv_arr[6] = {0, 1, 2, 0, 2, 3};
ShinyMeshTopology generate_shiny_cube(float r) {
ShinyMeshTopology generate_shiny_cube(vec3 color) {
ShinyMeshVertexInc vert[24] = {
{{+r, +r, +r}},
{{+r, -r, +r}},
{{+r, -r, -r}},
{{+r, +r, -r}},
{{+1, +1, +1}, color},
{{+1, -1, +1}, color},
{{+1, -1, -1}, color},
{{+1, +1, -1}, color},
{{-r, -r, -r}},
{{-r, -r, +r}},
{{-r, +r, +r}},
{{-r, +r, -r}},
{{-1, -1, -1}, color},
{{-1, -1, +1}, color},
{{-1, +1, +1}, color},
{{-1, +1, -1}, color},
{{+r, +r, +r}},
{{+r, +r, -r}},
{{-r, +r, -r}},
{{-r, +r, +r}},
{{+1, +1, +1}, color},
{{+1, +1, -1}, color},
{{-1, +1, -1}, color},
{{-1, +1, +1}, color},
{{-r, -r, -r}},
{{+r, -r, -r}},
{{+r, -r, +r}},
{{-r, -r, +r}},
{{-1, -1, -1}, color},
{{+1, -1, -1}, color},
{{+1, -1, +1}, color},
{{-1, -1, +1}, color},
{{+r, +r, +r}},
{{-r, +r, +r}},
{{-r, -r, +r}},
{{+r, -r, +r}},
{{+1, +1, +1}, color},
{{-1, +1, +1}, color},
{{-1, -1, +1}, color},
{{+1, -1, +1}, color},
{{-r, -r, -r}},
{{-r, +r, -r}},
{{+r, +r, -r}},
{{+r, -r, -r}},
{{-1, -1, -1}, color},
{{-1, +1, -1}, color},
{{+1, +1, -1}, color},
{{+1, -1, -1}, color},
};
VecShinyMeshVertexInc vertices_vec = VecShinyMeshVertexInc_from_span(
(SpanShinyMeshVertexInc){ .data = vert, .len = ARRAY_SIZE(vert) });
@ -685,6 +685,22 @@ MarieTriangle restore_triangle_from_mesh_topology(const VecGenericMeshVertexInc*
};
}
void r4_generate_flat_normal_map(VecU8 save_path){
TextureDataR8G8B8A8 normal = TextureDataR8G8B8A8_new(1, 1);
*TextureDataR8G8B8A8_mat(&normal, 0, 0) = compress_normal_vec_into_norm_texel((vec3){0, 1, 0});
TextureDataR8G8B8A8_write_to_png_nofail(&normal, VecU8_to_span(&save_path));
VecU8_drop(save_path);
TextureDataR8G8B8A8_drop(normal);
}
void generate_single_pixel_gray_tex(VecU8 save_path, U8 clr){
TextureDataR8 tex = TextureDataR8_new(1, 1);
*TextureDataR8_mat(&tex, 0, 0) = clr;
TextureDataR8_write_to_png_nofail(&tex, VecU8_to_span(&save_path));
VecU8_drop(save_path);
TextureDataR8_drop(tex);
}
/* r is radius, w is length of cylinder. Will write everything into files for us */
void r4_asset_gen_generic_mesh_cylinder(float s_resol, float r, float w, U32 k,
VecU8 path_to_mesh, VecU8 path_to_template_tex, VecU8 path_to_normal_tex){
@ -791,13 +807,8 @@ void r4_asset_gen_generic_mesh_cylinder(float s_resol, float r, float w, U32 k,
VecU8_drop(path_to_template_tex);
TextureDataR8G8B8A8_drop(template);
/* Here I generate normal tex trivially. */
TextureDataR8G8B8A8 normal = TextureDataR8G8B8A8_new(1, 1);
*TextureDataR8G8B8A8_mat(&normal, 0, 0) = compress_normal_vec_into_norm_texel((vec3){0, 1, 0});
/* Right now it's just a pixel... */
TextureDataR8G8B8A8_write_to_png_nofail(&normal, VecU8_to_span(&path_to_normal_tex));
VecU8_drop(path_to_normal_tex);
TextureDataR8G8B8A8_drop(normal);
r4_generate_flat_normal_map(path_to_normal_tex);
}
void r4_asset_gen_generic_mesh_quad(float width, float length, VecU8 path_to_save){
@ -884,15 +895,16 @@ int gen_assets_for_r4() {
mkdir_nofail("l2/textures");
mkdir_nofail("l2/textures/r4");
generate_one_forth_of_a_cylinder_with_bublazhuzhka(10, 2, 6);
alice_write_shiny_mesh_to_file(generate_shiny_cube(0.3f), vcstr("l2/models/cube.AliceShinyMesh"));
alice_write_shiny_mesh_to_file(generate_shiny_cube((vec3){0.6f, 0.6f, 0.7f}), vcstr("l2/models/cube.AliceShinyMesh"));
alice_write_shiny_mesh_to_file(generate_shiny_lamp(0.3f, 0.13f, 0.19f), vcstr("l2/models/lamp.AliceShinyMesh"));
r4_asset_gen_generic_mesh_quad(10, 10, vcstr("l2/models/quad.AliceGenericMesh"));
r4_asset_gen_generic_mesh_cylinder(200, 0.4f, 0.06f, 5, vcstr("l2/models/puck.AliceGenericMesh"),
r4_asset_gen_generic_mesh_cylinder(200, 0.4f, 0.17f, 30, vcstr("l2/models/puck.AliceGenericMesh"),
vcstr("l2/textures/puck_TEMPLATE.png"), vcstr("l2/textures/puck_NORMAL.png"));
r4_asset_gen_generic_mesh_cylinder(80, 0.13f, 1.5f, 4, vcstr("l2/models/stick.AliceGenericMesh"),
r4_asset_gen_generic_mesh_cylinder(100, 0.04f, 1.5f, 4, vcstr("l2/models/stick.AliceGenericMesh"),
vcstr("l2/textures/stick_TEMPLATE.png"), vcstr("l2/textures/stick_NORMAL.png"));
r4_generate_flat_normal_map(vcstr("l2/textures/flat_NORMAL.png"));
generate_single_pixel_gray_tex(vcstr("l2/textures/no_SPECULAR.png"), 0);
return 0;
}
#endif
#endif

7
src/l2/gui/label.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef prototype1_src_l2_gui_label_h
#define prototype1_src_l2_gui_label_h
#include "../lucy/glyph_render.h"
#endif

104
src/l2/gui/widget.h Normal file
View File

@ -0,0 +1,104 @@
#ifndef prototype1_src_l2_gui_widget_h
#define prototype1_src_l2_gui_widget_h
#include "../../../gen/l1/geom.h"
#include "../../l1/core/util.h"
#define WIDGET_DIM_INF 1000000
bool is_widget_size_limit_contain_inf(uvec2 max_limits){
return max_limits.x >= WIDGET_DIM_INF || max_limits.y >= WIDGET_DIM_INF;
}
void assert_sane_widget_size(uvec2 sz){
assert(sz.x < WIDGET_DIM_INF || sz.y < WIDGET_DIM_INF);
}
void assert_sane_widget_size_limits(uvec2 max_limits){
assert(max_limits.x <= WIDGET_DIM_INF || max_limits.y <= WIDGET_DIM_INF);
}
typedef struct{
ivec2 lt, rb;
} BorderS32;
bool BorderS32_empty(BorderS32 self){
return self.lt.x >= self.rb.x || self.lt.y >= self.rb.y;
}
BorderS32 BorderS32_intersect(BorderS32 a, BorderS32 b){
return (BorderS32){
{MAX_S32(a.lt.x, b.lt.x), MAX_S32(a.lt.y, b.lt.y)},
{MAX_S32(a.rb.x, b.rb.x), MAX_S32(a.rb.y, b.rb.y)},
};
}
uvec2 widget_size_max_of_all(uvec2 a, uvec2 b){
return (uvec2){MAX_U32(a.x, b.x), MAX_U32(a.y, b.y)};
}
uvec2 widget_size_min_of_all(uvec2 a, uvec2 b){
return (uvec2){MIN_U32(a.x, b.x), MIN_U32(a.y, b.y)};
}
typedef struct {
/* .x == WIDGET_DIM_INF indicates that no preparation was made before the draw operation.
* Calling draw at that state will cause abort. draw operation will reset this flag. This makes framework foolproof.
* Initialize and reset with {WIDGET_DIM_INF, 0} */
uvec2 sz_my_choice;
} Widget;
Widget Widget_new(){
return (Widget){.sz_my_choice = {WIDGET_DIM_INF, 0}};
}
#include "../../../gen/l1_5/eve/gui/Widget.h"
uvec2 MutRefWidget_draw_prepare(MutRefWidget self, uvec2 max_limits){
if (!self.r)
return (uvec2){0};
self.r->sz_my_choice = MutRefWidget_DRAW_PREPARE(self, max_limits);
assert_sane_widget_size(self.r->sz_my_choice);
return self.r->sz_my_choice;
}
void MutRefWidget_draw(MutRefWidget self, ivec2 drawing_offset, uvec2 surface_sz, BorderS32 border){
if (!self.r)
return;
if (self.r->sz_my_choice.x >= WIDGET_DIM_INF)
abortf("Drawing widget before negotiating it's size\n");
MutRefWidget_draw(self, drawing_offset, surface_sz, border);
self.r->sz_my_choice = (uvec2){WIDGET_DIM_INF, 0};
}
/* Some very simple widgets */
typedef struct {
Widget base;
U32 width;
U32 height;
} EmptyWidget;
uvec2 Widget_Table_EmptyWidget_DRAW_PREPARE(Widget* ug, uvec2 limits){
EmptyWidget* self = (EmptyWidget*)ug;
uvec2 R = widget_size_min_of_all((uvec2){self->width, self->height}, limits);
return is_widget_size_limit_contain_inf(R) ? (uvec2){0, 0} : R;
}
void Widget_Table_EmptyWidget_DRAW(Widget* ug, ivec2 drawing_offset, uvec2 surface_sz, BorderS32 border){}
void Widget_Table_EmptyWidget_drop(Widget* ug){}
const Widget_Table Widget_Table_EmptyWidget = {
.DRAW_PREPARE = Widget_Table_EmptyWidget_DRAW_PREPARE,
.DRAW = Widget_Table_EmptyWidget_DRAW,
.drop = Widget_Table_EmptyWidget_drop,
};
BoxWidget EmptyWidget_new_box(U32 width, U32 height){
EmptyWidget* r = safe_malloc(sizeof(EmptyWidget));
*r = (EmptyWidget){.base = Widget_new(), .width = width, .height = height};
return (BoxWidget){.r = (Widget*)r, .t = &Widget_Table_EmptyWidget};
}
#endif

View File

@ -3,35 +3,7 @@
#include "playing_sound_loop.h"
// todo: rewrite with the help of l1_5
typedef struct {
/* self (takes ownership) */
void (*drop)(void*);
/* self, frequency, time, returns: new sound box */
BoxLizaSound (*ding)(const void*, double, double);
// todo: request options for instrument
} LizaInstrument_Table;
typedef struct {
const void* r;
const LizaInstrument_Table* t;
} RefLizaInstrument;
typedef struct {
void* r;
const LizaInstrument_Table* t;
} MutLizaInstrument;
typedef struct {
void* m;
const LizaInstrument_Table* t;
} BoxLizaInstrument;
void BoxLizaInstrument_drop(BoxLizaInstrument self) {
self.t->drop(self.m);
}
#include "../../../gen/l1_5/eve/liza/LizaInstrument.h"
#include "../../../gen/l1/eve/liza/VecBoxLizaInstrument.h"

View File

@ -4,6 +4,7 @@
// todo: move loop here and rewrite with l1_5 help
#include "../../l1/core/int_primitives.h"
#include <stdlib.h>
typedef struct {
/* self (takes ownership) */

View File

@ -7,12 +7,15 @@
#include "../../../gen/l1/VecAndSpan_U32Segment.h"
#include "../../../gen/l1/vulkan/VecVkDescriptorImageInfo.h"
#include "../../../gen/l1/pixel_masses.h"
#include "../../../gen/l1/VecAndSpan_U32.h"
#include "../../l1_5/core/buff_rb_tree_node.h"
#include "../../l1_5/core/rb_tree_node.h"
#define LUCY_MAX_DESCRIPTOR_COUNT 100
typedef U32 lucy_image_index_t;
typedef struct {
/* This value is actually Option<MargaretSubbuf>. If staging_buffer is already deleted (after it is no longer used),
* staging_buffer.len will be 0 */
@ -20,18 +23,16 @@ typedef struct {
MargaretImg img;
VkImageView img_view;
U64 usage;
U64 pos_in_desc_array;
/* 0 if this image isn't scheduled for deletion on th next cycle.
* 1 if it is */
int scheduled_for_deletion;
} LucyImage;
#include "../../../gen/l1/eve/lucy/ListLucyImage.h"
typedef ListNodeLucyImage* RefListNodeLucyImage;
#include "../../../gen/l1/eve/lucy/VecRefListNodeLucyImage.h"
#include "../../../gen/l1/eve/lucy/OptionLucyImage.h"
#include "../../../gen/l1/eve/lucy/VecOptionLucyImage.h"
typedef struct {
ListNodeLucyImage* img;
U32 img_slot_id;
U32 w, h;
U32 advance_x;
ivec2 bearing;
@ -71,22 +72,28 @@ struct LucyFace {
struct LucyGlyphCache {
MargaretEngineReference ve;
ListLucyImage images;
VecOptionLucyImage image_slots;
VkDescriptorSetLayout descriptor_set_layout;
VkDescriptorSet descriptor_set;
/* to_be_freed_of_old_staging_next_cycle never intersect with to_be_copied_to_device_next_cycle */
VecRefListNodeLucyImage to_be_freed_of_old_staging_next_cycle;
VecRefListNodeLucyImage to_be_copied_to_device_next_cycle;
VecU32 to_be_freed_of_old_staging_next_cycle;
VecU32 to_be_copied_to_device_next_cycle;
/* deletion will be performed last */
VecRefListNodeLucyImage to_be_deleted;
VecU32 to_be_deleted;
};
LucyGlyphCache LucyGlyphCache_new(MargaretEngineReference ve){
VkDescriptorSetLayout my_desc_set_layout;
VkDescriptorSetLayoutBindingFlagsCreateInfo set_layout_crinfo_flags = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO,
.bindingCount = 1,
.pBindingFlags = (VkDescriptorBindingFlags[]){ VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT }
};
check(vkCreateDescriptorSetLayout(ve.device, &(VkDescriptorSetLayoutCreateInfo){
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.pNext = &set_layout_crinfo_flags,
.bindingCount = 1,
.pBindings = (VkDescriptorSetLayoutBinding[]){{
.binding = 0,
@ -97,20 +104,31 @@ LucyGlyphCache LucyGlyphCache_new(MargaretEngineReference ve){
}, NULL, &my_desc_set_layout) == VK_SUCCESS);
VkDescriptorSet descriptor_set = margaret_allocate_descriptor_set(ve.device, ve.descriptor_pool,
my_desc_set_layout);
return (LucyGlyphCache){.ve = ve, .images = ListLucyImage_new(),
.descriptor_set_layout = my_desc_set_layout, .descriptor_set = descriptor_set};
VecOptionLucyImage image_slots = VecOptionLucyImage_new_zeroinit(LUCY_MAX_DESCRIPTOR_COUNT);
for (size_t i = 0; i < LUCY_MAX_DESCRIPTOR_COUNT; i++) {
image_slots.buf[i].variant = Option_None;
}
return (LucyGlyphCache){
.ve = ve, .image_slots = image_slots,
.descriptor_set_layout = my_desc_set_layout, .descriptor_set = descriptor_set,
.to_be_freed_of_old_staging_next_cycle = VecU32_new(),
.to_be_copied_to_device_next_cycle = VecU32_new(),
.to_be_deleted = VecU32_new()};
}
void LucyFaceFixedSize_get_rid_of_myself(LucyFaceFixedSize* self){
LucyGlyphCache* cache = self->p->p;
BufRBTree_MapU32ToLucyStoredGlyph* glyphs = &self->glyphs;
for (size_t gid = 0; gid < glyphs->el.len; gid++) {
ListNodeLucyImage* img = glyphs->el.buf[gid].value.img;
assert(img->el.usage > 0);
if (--img->el.usage) {
assert(!img->el.scheduled_for_deletion);
img->el.scheduled_for_deletion = 1;
VecRefListNodeLucyImage_append(&cache->to_be_deleted, img);
U32 slot_id = glyphs->el.buf[gid].value.img_slot_id;
OptionLucyImage* img_slot = VecOptionLucyImage_mat(&cache->image_slots, slot_id);
assert(img_slot->variant == Option_Some);
LucyImage* img = &img_slot->some;
assert(img->usage > 0);
if (--img->usage) {
assert(!img->scheduled_for_deletion);
img->scheduled_for_deletion = 1;
VecU32_append(&cache->to_be_deleted, slot_id);
}
}
BufRBTree_MapU32ToLucyStoredGlyph_sink(glyphs);
@ -134,7 +152,7 @@ typedef struct {
TextureDataR8 bitmap;
/* Will be determined in the next phase */
uvec2 pos;
ListNodeLucyImage* img;
U32 img_slot_id;
} LucyPositionedStagingGlyph;
bool LucyPositionedStagingGlyph_less_LucyPositionedStagingGlyph(
@ -149,18 +167,37 @@ void LucyPositionedStagingGlyph_drop(LucyPositionedStagingGlyph self){
/* Instantiation for helper type */
#include "../../../gen/l1/eve/lucy/VecLucyPositionedStagingGlyph.h"
/* Helper function */
U32 LucyGlyphCache_add_glyphs__find_image_slot(LucyGlyphCache* cache){
for (U32 i = 0; i < cache->image_slots.len; i++) {
OptionLucyImage* slot = &cache->image_slots.buf[i];
if (slot->variant == Option_None) {
slot->variant = Option_Some;
slot->some.scheduled_for_deletion = 0;
slot->some.usage = 0;
return i;
}
}
abortf("LucyCache run out of image descriptor in a descriptor set (dictated by layout).\n"
"You better add up on them\n");
}
/* Helper function */
void LucyGlyphCache_add_glyphs__close_img(
LucyGlyphCache* cache, ListNodeLucyImage* img, U32 img_width, U32 img_height
LucyGlyphCache* cache, U32 img_slot_id, U32 img_width, U32 img_height
){
assert(img->el.usage > 0);
OptionLucyImage* img_slot = VecOptionLucyImage_mat(&cache->image_slots, img_slot_id);
assert(img_slot->variant == Option_Some);
LucyImage* img = &img_slot->some;
assert(img->usage > 0);
assert(!img->scheduled_for_deletion);
img_width = MAX_U32(img_width, 10); // Just a precaution. empty buffers aren't supported by Margaret
img_height = MAX_U32(img_height, 10);
VecRefListNodeLucyImage_append(&cache->to_be_copied_to_device_next_cycle, img);
img->el.staging_buffer = MargaretBufAllocator_alloc(cache->ve.staging_buffers, img_width * img_height * 1);
img->el.img = MargaretImgAllocator_alloc(cache->ve.dev_local_images, img_width, img_height, VK_FORMAT_R8_UNORM,
VecU32_append(&cache->to_be_copied_to_device_next_cycle, img_slot_id);
img->staging_buffer = MargaretBufAllocator_alloc(cache->ve.staging_buffers, img_width * img_height * 1);
img->img = MargaretImgAllocator_alloc(cache->ve.dev_local_images, img_width, img_height, VK_FORMAT_R8_UNORM,
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
img->el.img_view = margaret_create_view_for_image(cache->ve.device, img->el.img.a.image,
img->img_view = margaret_create_view_for_image(cache->ve.device, img->img.a.image,
VK_FORMAT_R8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT);
}
@ -228,11 +265,14 @@ void LucyGlyphCache_add_glyphs(VecLucyGlyphCachingRequest requests_for_faces){
U32 starting_x = 0;
VecU32 landscape = VecU32_new_reserved(200);
U32 img_width = 0, img_height = 0;
ListNodeLucyImage* img = ListLucyImage_insert(&cache->images, (LucyImage){0});
U32 img_slot_id = LucyGlyphCache_add_glyphs__find_image_slot(cache);
for (size_t j = 0; j < ready.len; j++) {
LucyPositionedStagingGlyph* p_glyph;
one_more_chance:
{}
int s = 23123;
p_glyph = &ready.buf[j];
LucyImage* img = &VecOptionLucyImage_mat(&cache->image_slots, img_slot_id)->some;
U64 new_width_required = p_glyph->bitmap.width + starting_x;
if (new_width_required > max_dim) {
/* Resetting row */
@ -250,12 +290,12 @@ void LucyGlyphCache_add_glyphs(VecLucyGlyphCachingRequest requests_for_faces){
U64 new_height_required = height_here + p_glyph->bitmap.height;
if (new_height_required > max_dim) {
/* Resetting image */
LucyGlyphCache_add_glyphs__close_img(cache, img, img_width, img_height);
LucyGlyphCache_add_glyphs__close_img(cache, img_slot_id, img_width, img_height);
starting_x = 0;
landscape.len = 0;
img_width = 0;
img_height = 0;
img = ListLucyImage_insert(&cache->images, (LucyImage){0});
img_slot_id = LucyGlyphCache_add_glyphs__find_image_slot(cache);
goto one_more_chance;
}
/* Success */
@ -263,24 +303,25 @@ void LucyGlyphCache_add_glyphs(VecLucyGlyphCachingRequest requests_for_faces){
*VecU32_mat(&landscape, starting_x + x) = new_height_required;
}
img_height = MAX_U64(img_height, new_height_required);
p_glyph->img = img;
p_glyph->img_slot_id = img_slot_id;
p_glyph->pos = (uvec2){starting_x, height_here};
img->el.usage++; /* p_glyph uses it, that's a rock fact */
img->usage++; /* p_glyph uses it, that's a rock fact */
BufRBTree_MapU32ToLucyStoredGlyph *glyphs = &p_glyph->sized_face->glyphs;
U64 map_it = BufRBTree_MapU32ToLucyStoredGlyph_find(glyphs, p_glyph->codepoint);
assert(map_it > 0 && map_it < glyphs->tree.len);
LucyStoredGlyph* actual_glyph = &glyphs->el.buf[map_it - 1].value;
actual_glyph->pos_on_atlas = (uvec2){starting_x, height_here};
actual_glyph->img = img;
actual_glyph->img_slot_id = img_slot_id;
starting_x += p_glyph->bitmap.width;
}
LucyGlyphCache_add_glyphs__close_img(cache, img, img_width, img_height);
LucyGlyphCache_add_glyphs__close_img(cache, img_slot_id, img_width, img_height);
/* Phase 3. We have all the data. Now what?
* Now we fill staging buffers with glyphs bitsets from `ready` vector */
for (size_t j = 0; j < ready.len; j++) {
LucyPositionedStagingGlyph* p_glyph = &ready.buf[j];
U64 staging_width = p_glyph->img->el.img.width;
U8* staging = (U8*)MargaretSubbuf_get_mapped(&p_glyph->img->el.staging_buffer);
LucyImage* image = &VecOptionLucyImage_mat(&cache->image_slots, p_glyph->img_slot_id)->some;
U64 staging_width = image->img.width;
U8* staging = (U8*)MargaretSubbuf_get_mapped(&image->staging_buffer);
for (U64 y = 0; y < p_glyph->bitmap.height; y++) {
U64 Y = y + p_glyph->pos.y;
for (U64 x = 0; x < p_glyph->bitmap.width; x++) {
@ -296,65 +337,59 @@ void LucyGlyphCache_add_glyphs(VecLucyGlyphCachingRequest requests_for_faces){
/* This must not happen before all the LucyFaceFixedSizes are destroyed */
void LucyGlyphCache_drop(LucyGlyphCache self){
assert(self.images.first == NULL);
VecRefListNodeLucyImage_drop(self.to_be_freed_of_old_staging_next_cycle);
VecRefListNodeLucyImage_drop(self.to_be_copied_to_device_next_cycle);
VecRefListNodeLucyImage_drop(self.to_be_deleted);
for (size_t i = 0; i < self.image_slots.len; i++) {
assert(self.image_slots.buf[i].variant == Option_None);
}
VecU32_drop(self.to_be_freed_of_old_staging_next_cycle);
VecU32_drop(self.to_be_copied_to_device_next_cycle);
VecU32_drop(self.to_be_deleted);
}
void LucyGlyphCache_another_frame(LucyGlyphCache* self){
for (size_t i = 0; i < self->to_be_freed_of_old_staging_next_cycle.len; i++) {
LucyImage* img = &self->to_be_freed_of_old_staging_next_cycle.buf[i]->el;
U32 slot_id = self->to_be_freed_of_old_staging_next_cycle.buf[i];
LucyImage* img = &self->image_slots.buf[slot_id].some;
assert(img->staging_buffer.len != 0);
MargaretBufAllocator_free(self->ve.staging_buffers, img->staging_buffer);
img->staging_buffer.len = 0;
}
for (size_t i = 0; i < self->to_be_copied_to_device_next_cycle.len; i++) {
ListNodeLucyImage* img_node = self->to_be_copied_to_device_next_cycle.buf[i];
LucyImage* img = &img_node->el;
U32 slot_id = self->to_be_copied_to_device_next_cycle.buf[i];
OptionLucyImage* img_slot = &self->image_slots.buf[slot_id];
assert(img_slot->variant == Option_Some);
LucyImage* img = &img_slot->some;
assert(img->staging_buffer.len != 0);
if (img->scheduled_for_deletion)
continue;
margaret_rec_cmd_copy_buffer_to_image_one_to_one_color_aspect(self->ve.transfer_cmd_buffer,
&img->staging_buffer, &img->img, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT);
VecRefListNodeLucyImage_append(&self->to_be_freed_of_old_staging_next_cycle, img_node);
VecU32_append(&self->to_be_freed_of_old_staging_next_cycle, slot_id);
vkUpdateDescriptorSets(self->ve.device, 1, &(VkWriteDescriptorSet){
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = self->descriptor_set, .dstBinding = 0, .dstArrayElement = slot_id,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.pImageInfo = &(VkDescriptorImageInfo){
.sampler = self->ve.nearest_sampler, .imageView = img->img_view,
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
}
}, 0, NULL);
}
/* We technically could carry out each deletion request in O(1) and each img creation request in O(1),
* but who cares, it's no problem going over the entire descriptor set when something get's added or deleted */
for (size_t i = 0; i < self->to_be_deleted.len; i++) {
ListNodeLucyImage* img_node = self->to_be_deleted.buf[i];
LucyImage* img = &img_node->el;
U32 slot_id = self->to_be_copied_to_device_next_cycle.buf[i];
OptionLucyImage* img_slot = &self->image_slots.buf[slot_id];
assert(img_slot->variant == Option_Some);
LucyImage* img = &img_slot->some;
assert(img->scheduled_for_deletion);
assert(img->usage == 0);
if (img->staging_buffer.len != 0)
MargaretBufAllocator_free(self->ve.staging_buffers, img->staging_buffer);
MargaretImgAllocator_free(self->ve.dev_local_images, img->img.a);
ListLucyImage_erase_by_it(&self->images, img_node);
}
if ((self->to_be_copied_to_device_next_cycle.len > 0) || (self->to_be_deleted.len > 0)) {
U32 descriptor_i = 0;
VecVkDescriptorImageInfo desc_elements = VecVkDescriptorImageInfo_new();
for (ListNodeLucyImage* list_node = self->images.first; list_node; list_node = list_node->next) {
if (descriptor_i == LUCY_MAX_DESCRIPTOR_COUNT) {
abortf("Today you are out of luck\n");
}
LucyImage* img = &list_node->el;
img->pos_in_desc_array = descriptor_i;
VecVkDescriptorImageInfo_append(&desc_elements, (VkDescriptorImageInfo){
.sampler = self->ve.nearest_sampler, .imageView = img->img_view,
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
});
descriptor_i++;
}
vkUpdateDescriptorSets(self->ve.device, 1, &(VkWriteDescriptorSet){
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = self->descriptor_set, .dstBinding = 0, .dstArrayElement = 0,
.descriptorCount = desc_elements.len,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.pImageInfo = desc_elements.buf
}, 0, NULL);
VecVkDescriptorImageInfo_drop(desc_elements);
img_slot->variant = Option_None;
}
self->to_be_freed_of_old_staging_next_cycle.len = 0;
self->to_be_copied_to_device_next_cycle.len = 0;

View File

@ -6,12 +6,22 @@
#include "../../../gen/l1/geom.h"
// todo: rewrite this crrp crap using instances
typedef struct{
// typedef struct{
// vec4 color;
// vec2 pos;
// vec2 tex_cord;
// U32 tex_ind;
// } LucyVertex;
typedef struct {
vec4 color;
vec2 pos;
vec2 tex_cord;
vec2 lt_pos;
vec2 br_pos;
vec2 lt_tex;
vec2 br_tex;
U32 tex_ind;
} LucyVertex;
} LucyRenderInstance;
typedef struct {
MargaretEngineReference ve;
@ -19,7 +29,7 @@ typedef struct {
VkPipelineLayout pipeline_layout;
VkPipeline pipeline;
U64 vertex_count;
U64 glyphs_count;
MargaretSubbuf staging_vbo;
MargaretSubbuf vbo;
bool need_to_transfer;
@ -51,23 +61,27 @@ LucyRenderer LucyRenderer_new(
.fragment_shader_code = read_file_by_path(VecU8_fmt("%s/gen/l_adele/lucy/frag.spv", root_dir)),
.vertexBindingDescriptionCount = 1,
.pVertexBindingDescriptions = (VkVertexInputBindingDescription[]){
{ .binding = 0, .stride = sizeof(LucyVertex), .inputRate = VK_VERTEX_INPUT_RATE_VERTEX } },
.vertexAttributeDescriptionCount = 4,
{ .binding = 0, .stride = sizeof(LucyRenderInstance), .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE } },
.vertexAttributeDescriptionCount = 6,
.pVertexAttributeDescriptions = (VkVertexInputAttributeDescription[]){
{.location = 0, .binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT, .offset = offsetof(LucyVertex, color)},
.format = VK_FORMAT_R32G32B32A32_SFLOAT, .offset = offsetof(LucyRenderInstance, color)},
{.location = 1, .binding = 0,
.format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(LucyVertex, pos)},
.format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(LucyRenderInstance, lt_pos)},
{.location = 2, .binding = 0,
.format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(LucyVertex, tex_cord)},
.format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(LucyRenderInstance, br_pos)},
{.location = 3, .binding = 0,
.format = VK_FORMAT_R32_UINT, .offset = offsetof(LucyVertex, tex_ind)},
.format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(LucyRenderInstance, lt_tex)},
{.location = 4, .binding = 0,
.format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(LucyRenderInstance, br_tex)},
{.location = 5, .binding = 0,
.format = VK_FORMAT_R32_UINT, .offset = offsetof(LucyRenderInstance, tex_ind)},
},
.depthTestEnable = false, .depthWriteEnable = false, .blendEnable = true,
});
return (LucyRenderer){.ve = ve, .cache = cache, .pipeline_layout = pipeline_layout, .pipeline = pipeline,
.vertex_count = 0, .staging_vbo = MargaretBufAllocator_alloc(ve.staging_buffers, 67),
.glyphs_count = 0, .staging_vbo = MargaretBufAllocator_alloc(ve.staging_buffers, 67),
.vbo = MargaretBufAllocator_alloc(ve.dev_local_buffers, 67)
};
}
@ -76,20 +90,47 @@ LucyRenderer LucyRenderer_new(
* before LucyRenderer_another_frame
*/
void LucyRenderer_clear(LucyRenderer* self){
self->vertex_count = 0;
self->glyphs_count = 0;
}
void LucyRenderer__append_vertex_to_vao(LucyRenderer* self, LucyVertex vert_data){
self->vertex_count++;
assert(self->vertex_count * sizeof(LucyVertex) <= self->staging_vbo.len);
LucyVertex* staging = (LucyVertex*)MargaretSubbuf_get_mapped(&self->staging_vbo);
staging[self->vertex_count - 1] = vert_data;
void LucyRenderer_draw_char_glyph(LucyRenderer* self, vec4 color, ivec2 pos, LucyStoredGlyph* glyph){
if (glyph->w > 0 && glyph->h > 0) {
OptionLucyImage* img_slot = VecOptionLucyImage_mat(&self->cache->image_slots, glyph->img_slot_id);
assert(img_slot->variant == Option_Some);
LucyImage* img = &img_slot->some;
float atlas_w = (float)img->img.width;
float atlas_h = (float)img->img.height;
ivec2 positioned = ivec2_add_ivec2(pos, glyph->bearing);
U64 needed_vbo_length = (self->glyphs_count + 1) * sizeof(LucyRenderInstance);
if (self->staging_vbo.len < needed_vbo_length) {
printf("LucyRenderer Staging Buffer: Gotta replace %lu with %lu\n",
self->staging_vbo.len, needed_vbo_length);
MargaretBufAllocator_expand_or_move_old_host_visible(
self->ve.staging_buffers, &self->staging_vbo, needed_vbo_length);
}
LucyRenderInstance* vbo_data = (LucyRenderInstance*)MargaretSubbuf_get_mapped(&self->staging_vbo);
vbo_data[self->glyphs_count++] = (LucyRenderInstance){
.color = color,
.lt_pos = (vec2){(float)positioned.x, (float)positioned.y},
.br_pos = (vec2){(float)(positioned.x + glyph->w), (float)(positioned.y + glyph->h)},
.lt_tex = (vec2){
(float)(glyph->pos_on_atlas.x) / atlas_w,
(float)(glyph->pos_on_atlas.y) / atlas_h
},
.br_tex = (vec2){
(float)(glyph->pos_on_atlas.x + glyph->w) / atlas_w,
(float)(glyph->pos_on_atlas.y + glyph->h) / atlas_h
}, .tex_ind = glyph->img_slot_id
};
}
}
/* When another_frame starts, you are safe to call this function, but you also have to call it
* before LucyRenderer_another_frame, because _another_frame method records transfer of data
*/
void LucyRenderer_add_text(
void LucyRenderer_add_simple_label(
LucyRenderer* self, RBTreeNodeLucyFaceFixedSize* ffs, vec4 color,
U32 additional_y_advance, SpanU8 text, ivec2 start_pos
){
@ -112,69 +153,23 @@ void LucyRenderer_add_text(
}
assert(map_it > 0 && map_it < glyphs->tree.len);
LucyStoredGlyph* glyph = &glyphs->el.buf[map_it - 1].value;
if (glyph->w > 0 && glyph->h > 0) {
float atlas_w = (float)glyph->img->el.img.width;
float atlas_h = (float)glyph->img->el.img.height;
U32 desc_elem_id = glyph->img->el.pos_in_desc_array;
ivec2 positioned = ivec2_add_ivec2(pos, glyph->bearing);
LucyVertex v0 = {
.color = color, .pos = (vec2){(float)positioned.x, (float)positioned.y},
.tex_cord = (vec2){
(float)(glyph->pos_on_atlas.x) / atlas_w,
(float)(glyph->pos_on_atlas.y) / atlas_h
}, .tex_ind = desc_elem_id
};
LucyVertex v1 = {
.color = color, .pos = (vec2){(float)(positioned.x + glyph->w), (float)positioned.y},
.tex_cord = (vec2){
(float)(glyph->pos_on_atlas.x + glyph->w) / atlas_w,
(float)(glyph->pos_on_atlas.y) / atlas_h
}, .tex_ind = desc_elem_id
};
LucyVertex v2 = {
.color = color, .pos = (vec2){(float)positioned.x, (float)(positioned.y + glyph->h)},
.tex_cord = (vec2){
(float)(glyph->pos_on_atlas.x) / atlas_w,
(float)(glyph->pos_on_atlas.y + glyph->h) / atlas_h
}, .tex_ind = desc_elem_id
};
LucyVertex v3 = {
.color = color, .pos = (vec2){(float)(positioned.x + glyph->w), (float)(positioned.y + glyph->h)},
.tex_cord = (vec2){
(float)(glyph->pos_on_atlas.x + glyph->w) / atlas_w,
(float)(glyph->pos_on_atlas.y + glyph->h) / atlas_h
}, .tex_ind = desc_elem_id
};
/* What if we run out of space? */
U64 needed_vbo_length = (self->vertex_count + 6) * sizeof(LucyVertex);
if (self->staging_vbo.len < needed_vbo_length) {
printf("LucyRenderer Staging Buffer: Gotta replace %lu with %lu\n",
self->staging_vbo.len, needed_vbo_length);
MargaretBufAllocator_expand_or_move_old_host_visible(
self->ve.staging_buffers, &self->staging_vbo, needed_vbo_length);
}
LucyRenderer__append_vertex_to_vao(self, v1);
LucyRenderer__append_vertex_to_vao(self, v0);
LucyRenderer__append_vertex_to_vao(self, v2);
LucyRenderer__append_vertex_to_vao(self, v1);
LucyRenderer__append_vertex_to_vao(self, v2);
LucyRenderer__append_vertex_to_vao(self, v3);
}
LucyRenderer_draw_char_glyph(self, color, pos, glyph);
pos.x += (S32)glyph->advance_x;
}
}
/* It only records transfer commands (transfer command buffer is passed in MargaretEngineReference object) */
void LucyRenderer_another_frame(LucyRenderer* self){
if (self->vbo.len < self->vertex_count * sizeof(LucyVertex)) {
MargaretBufAllocator_expand_or_free_old(self->ve.dev_local_buffers, &self->vbo,
self->vertex_count * sizeof(LucyVertex));
U64 needed_vbo_length = self->glyphs_count * sizeof(LucyRenderInstance);
if (self->vbo.len < needed_vbo_length) {
MargaretBufAllocator_expand_or_free_old(self->ve.dev_local_buffers, &self->vbo, needed_vbo_length);
}
if (self->need_to_transfer && self->vertex_count > 0) {
if ((self->need_to_transfer) && self->glyphs_count > 0) {
printf("LucyRenderer: we are doing copying\n");
self->need_to_transfer = false;
margaret_rec_cmd_copy_buffer_one_to_one_part(self->ve.transfer_cmd_buffer,
&self->staging_vbo, &self->vbo, 0, self->vertex_count * sizeof(LucyVertex));
&self->staging_vbo, &self->vbo, 0, needed_vbo_length);
}
}
@ -189,7 +184,7 @@ void LucyRenderer_another_frame_rec_drawing(
(VkBuffer[]){MargaretSubbuf_get_buffer(&self->vbo)}, (VkDeviceSize[]){self->vbo.start});
vkCmdBindDescriptorSets(drawing_cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, self->pipeline_layout, 0,
1, (VkDescriptorSet[]){self->cache->descriptor_set}, 0, NULL);
vkCmdDraw(drawing_cmd_buf, self->vertex_count, 1, 0, 0);
vkCmdDraw(drawing_cmd_buf, 6, self->glyphs_count, 0, 0);
}
#endif

View File

@ -241,11 +241,11 @@ void MargaretBufAllocator_free(MargaretBufAllocator* self, MargaretSubbuf alloca
bool eret = BufRBTree_MapU64ToU64_erase(&allocation.block->occupants, allocation.start);
assert(eret);
MargaretBufAllocator_debug(self);
// MargaretBufAllocator_debug(self);
}
NODISCARD MargaretSubbuf MargaretBufAllocator_alloc(MargaretBufAllocator* self, U64 req_size){
MargaretBufAllocator_debug(self);
// MargaretBufAllocator_debug(self);
req_size = margaret_bump_buffer_size_to_alignment(req_size, self->alignment_exp);
VkPhysicalDeviceMaintenance3Properties maintenance3_properties = {
@ -270,11 +270,11 @@ NODISCARD MargaretSubbuf MargaretBufAllocator_alloc(MargaretBufAllocator* self,
new_block->occupation_counter = req_size;
bool iret = BufRBTree_MapU64ToU64_insert(&new_block->occupants, 0, req_size);
assert(iret);
MargaretBufAllocator_debug(self);
// MargaretBufAllocator_debug(self);
return (MargaretSubbuf){.block = &self->blocks.first->el, 0, req_size};
}
MargaretBufAllocator__put_buf_to_a_gap(self, free_gap.some, req_size);
MargaretBufAllocator_debug(self);
// MargaretBufAllocator_debug(self);
return (MargaretSubbuf){.block = free_gap.some.block, .start = free_gap.some.start, req_size};
}
@ -305,7 +305,7 @@ NODISCARD MargaretSubbuf MargaretBufAllocator_expand(
if (allocation->start + bigger_size > right_free_space.start + right_free_space.len){
return MargaretBufAllocator_alloc(self, bigger_size);
}
MargaretBufAllocator_debug(self);
// MargaretBufAllocator_debug(self);
MargaretBufAllocator__erase_gap(self, allocation->block, right_free_space.start, right_free_space.len);
MargaretBufAllocator__insert_gap(self, allocation->block,
allocation->start + bigger_size,
@ -315,7 +315,7 @@ NODISCARD MargaretSubbuf MargaretBufAllocator_expand(
U64 my_it = BufRBTree_MapU64ToU64_find(&allocation->block->occupants, allocation->start);
assert(my_it > 0 && my_it <= allocation->block->occupants.el.len);
allocation->block->occupants.el.buf[my_it - 1].value = bigger_size;
MargaretBufAllocator_debug(self);
// MargaretBufAllocator_debug(self);
return (MargaretSubbuf){0};
}
@ -342,9 +342,9 @@ void MargaretBufAllocator_expand_or_move_old_host_visible(
memcpy(MargaretSubbuf_get_mapped(&maybe_bigger), MargaretSubbuf_get_mapped(allocation), allocation->len);
MargaretBufAllocator_free(self, *allocation);
*allocation = maybe_bigger;
MargaretBufAllocator_debug(self);
// MargaretBufAllocator_debug(self);
}
MargaretBufAllocator_debug(self);
// MargaretBufAllocator_debug(self);
}
/* It tries to expand buffer, but if it fails, it creates a freshly-new buffer. It

View File

@ -172,12 +172,6 @@
* const VkAllocationCallbacks* pAllocator)
*/
// todo: get rid of this whole VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT crap. MargaretMA is for non-host-visible
// todo: for staging buffers you better use MargaretBufferAllocator. Ou, yeah, I have yet to write them
// todo: chucking rewrite all of this. Yes, I want all of this crrp rewritten
#include "../../l1/core/util.h"
#include "../../l1_5/core/buff_rb_tree_node.h"
#include "../../../gen/l1_5/BufRBTree_MapU64ToU64.h"
@ -189,10 +183,18 @@ typedef struct{
} MargaretIAFreeSegment;
#include "../../l1/core/uint_segments.h"
// todo: substitute U64Segment_get_length_resp_alignment by my own function
U64 margaret_get_length_resp_alignment(U64 start, U64 full_len, U8 alignment_exp) {
if (start & ((1ull << alignment_exp) - 1)) {
U64 pad_left = (1ull << alignment_exp) - (start & ((1ull << alignment_exp) - 1));
return full_len >= pad_left ? full_len - pad_left : 0;
}
return full_len;
}
bool MargaretIAFreeSegment_less_resp_align(const MargaretIAFreeSegment* A, const MargaretIAFreeSegment* B, U8 alignment_exp){
U64 A_len = U64Segment_get_length_resp_alignment((U64Segment){A->start, A->len}, alignment_exp);
U64 B_len = U64Segment_get_length_resp_alignment((U64Segment){B->start, B->len}, alignment_exp);
U64 A_len = margaret_get_length_resp_alignment(A->start, A->len, alignment_exp);
U64 B_len = margaret_get_length_resp_alignment(B->start, B->len, alignment_exp);
if (A_len == B_len) {
if (A->block == B->block) {
return A->start < B->start;
@ -291,6 +293,7 @@ OptionMargaretIAFreeSegment MargaretMemFreeSpaceManager_search(
if (man->free_space_in_memory[alignment_exp].variant == Option_None) {
assert(man->set_present.len > 0);
assert(man->free_space_in_memory[man->set_present.buf[0]].variant == Option_Some);
assert(man->free_space_in_memory[alignment_exp].variant == Option_None);
BufRBTreeByLenRespAlign_SetMargaretIAFreeSegment* have = &man->free_space_in_memory[man->set_present.buf[0]].some;
man->free_space_in_memory[alignment_exp] = Some_BufRBTreeByLenRespAlign_SetMargaretIAFreeSegment(
BufRBTreeByLenRespAlign_SetMargaretIAFreeSegment_new_reserved(alignment_exp, have->el.len));
@ -298,6 +301,7 @@ OptionMargaretIAFreeSegment MargaretMemFreeSpaceManager_search(
BufRBTreeByLenRespAlign_SetMargaretIAFreeSegment_insert(
&man->free_space_in_memory[alignment_exp].some, *VecMargaretIAFreeSegment_at(&have->el, i));
}
VecU8_append(&man->set_present, alignment_exp);
}
assert(man->free_space_in_memory[alignment_exp].variant == Option_Some);
U64 sit = BufRBTreeByLenRespAlign_SetMargaretIAFreeSegment_find_min_grtr_or_eq(
@ -333,6 +337,7 @@ void MargaretImgAllocator__insert_gap(MargaretImgAllocator* self, U64 block_id,
void MargaretImgAllocator__add_block(MargaretImgAllocator* self, U64 capacity){
VkDeviceMemory memory;
printf("DEBUG MargaretImgAllocator: allocating block of size %lu\n", capacity);
check(vkAllocateMemory(self->device, &(VkMemoryAllocateInfo){
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.allocationSize = capacity, .memoryTypeIndex = self->memory_type_id
@ -340,11 +345,33 @@ void MargaretImgAllocator__add_block(MargaretImgAllocator* self, U64 capacity){
VecMargaretImgAllocatorOneBlock_append(&self->blocks, (MargaretImgAllocatorOneBlock){
.images = BufRBTree_MapU64ToU64_new_reserved(1),
.capacity = capacity,
.occupation_counter = capacity,
.occupation_counter = capacity, // sounds sus
.mem_hand = memory,
.mapped_memory = NULL /* not supported */});
}
/* Idk where to put it */
void MargaretImgAllocator__debug(const MargaretImgAllocator* self){
printf("=============================== MargaretImgAllocator ============\n"
"All blocks: { ");
for (size_t i = 0; i < self->blocks.len; i++) {
printf(" %lu/%lu ", self->blocks.buf[i].occupation_counter, self->blocks.buf[i].capacity);
}
printf("}\n");
for (size_t ai = 0; ai < self->mem_free_space.set_present.len; ai++) {
U8 alignment_exp = self->mem_free_space.set_present.buf[ai];
printf("Free spaces at alignment_exp = %d:\n", (int)alignment_exp);
assert(self->mem_free_space.free_space_in_memory[alignment_exp].variant == Option_Some);
const BufRBTreeByLenRespAlign_SetMargaretIAFreeSegment* set =
&self->mem_free_space.free_space_in_memory[alignment_exp].some;
assert(set->guest == alignment_exp);
for (size_t i = 0; i < set->el.len; i++) {
const MargaretIAFreeSegment *free_seg = &set->el.buf[i];
printf(" Block %lu, start %lu, len %lu\n", free_seg->block, free_seg->start, free_seg->len);
}
}
}
MargaretImgAllocator MargaretImgAllocator_new(
VkDevice device, VkPhysicalDevice physical_device, U8 memory_type_id, U64 initial_block_size
){
@ -357,6 +384,7 @@ MargaretImgAllocator MargaretImgAllocator_new(
};
MargaretImgAllocator__add_block(&self, initial_block_size);
MargaretImgAllocator__insert_gap(&self, 0, 0, initial_block_size);
// MargaretImgAllocator__debug(&self);
return self;
}
@ -490,6 +518,7 @@ NODISCARD MargaretImgAllocation MargaretImgAllocator__alloc(
U64 pitch = self->blocks.buf[self->blocks.len - 1].capacity;
// Old blocks remain intact
U64 new_capacity = MAX_U64(mem_requirements.size, MIN_U64(2 * pitch, maintenance3_properties.maxMemoryAllocationSize));
// U64 new_capacity = MAX_U64(mem_requirements.size, MIN_U64(pitch, maintenance3_properties.maxMemoryAllocationSize));
MargaretImgAllocator__add_block(self, new_capacity);
U64 bid = self->blocks.len - 1;
MargaretImgAllocator__insert_gap(self, bid, mem_requirements.size, new_capacity - mem_requirements.size);
@ -498,11 +527,13 @@ NODISCARD MargaretImgAllocation MargaretImgAllocator__alloc(
bool iret = BufRBTree_MapU64ToU64_insert(&block->images, 0, mem_requirements.size);
assert(iret);
check(vkBindImageMemory(self->device, fresh_img, block->mem_hand, 0) == VK_SUCCESS);
// MargaretImgAllocator__debug(self);
return (MargaretImgAllocation){.block = bid, fresh_img, 0};
}
U64 aligned_pos = MargaretImgAllocator__add_img_given_gap(self, free_gap.some, mem_requirements.size, alignment_exp);
VkDeviceMemory memory = VecMargaretImgAllocatorOneBlock_at(&self->blocks, free_gap.some.block)->mem_hand;
check(vkBindImageMemory(self->device, fresh_img, memory, aligned_pos) == VK_SUCCESS);
// MargaretImgAllocator__debug(self);
return (MargaretImgAllocation){.block = free_gap.some.block, .image = fresh_img, .start = aligned_pos};
}

View File

@ -309,20 +309,27 @@ NODISCARD VecU8 margaret_stringify_device_memory_properties_2(VkPhysicalDevice p
VkDevice margaret_create_logical_device(VkPhysicalDevice physical_device, MargaretChosenQueueFamilies queue_fam) {
VkPhysicalDeviceFeatures physical_features;
vkGetPhysicalDeviceFeatures(physical_device, &physical_features);
// todo: handle case of `two in one`
float qfam_instance_priorities[1] = {1.f};
VkDeviceQueueCreateInfo logical_device_queue_crinfo[2] = { 0 };
for (int i = 0; i < 2; i++) {
logical_device_queue_crinfo[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
logical_device_queue_crinfo[i].queueCount = 1;
logical_device_queue_crinfo[i].pQueuePriorities = qfam_instance_priorities;
float qfam_queue_priorities[1] = {1.f};
VkDeviceQueueCreateInfo queue_crinfo[2] = { 0 };
int queue_c = 0;
if (queue_fam.for_graphics == queue_fam.for_presentation) {
queue_c = 1;
queue_crinfo[0].queueFamilyIndex = queue_fam.for_graphics;
} else {
queue_c = 2;
queue_crinfo[0].queueFamilyIndex = queue_fam.for_graphics;
queue_crinfo[1].queueFamilyIndex = queue_fam.for_presentation;
}
for (int i = 0; i < queue_c; i++) {
queue_crinfo[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queue_crinfo[i].queueCount = 1;
queue_crinfo[i].pQueuePriorities = qfam_queue_priorities;
}
logical_device_queue_crinfo[0].queueFamilyIndex = queue_fam.for_graphics;
logical_device_queue_crinfo[1].queueFamilyIndex = queue_fam.for_presentation;
VkPhysicalDeviceVulkan12Features used_vk12_features = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
.runtimeDescriptorArray = true,
.descriptorBindingPartiallyBound = true,
.shaderSampledImageArrayNonUniformIndexing = true,
};
// We DEMAND synchronization2
@ -345,8 +352,8 @@ VkDevice margaret_create_logical_device(VkPhysicalDevice physical_device, Margar
VkDeviceCreateInfo device_crinfo = {
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
.pNext = (const void*)&used_features2,
.queueCreateInfoCount = ARRAY_SIZE(logical_device_queue_crinfo),
.pQueueCreateInfos = logical_device_queue_crinfo,
.queueCreateInfoCount = queue_c,
.pQueueCreateInfos = queue_crinfo,
.enabledExtensionCount = ARRAY_SIZE(needed_extensions),
.ppEnabledExtensionNames = needed_extensions,
// We leave that filed because we have specified features2 in `.pNext`
@ -583,6 +590,8 @@ MargaretScoredPhysicalDevice margaret_score_physical_device(
return (MargaretScoredPhysicalDevice){dev, -1, cstr("No shaderSampledImageArrayNonUniformIndexing")};
if (!vk12_features.runtimeDescriptorArray)
return (MargaretScoredPhysicalDevice){dev, -1, cstr("No runtimeDescriptorArray")};
if (!vk12_features.descriptorBindingPartiallyBound)
return (MargaretScoredPhysicalDevice){dev, -1, cstr("No descriptorBindingPartiallyBound")};
ResultMargaretChosenQueueFamiliesOrSpanU8 queue_families = margaret_choose_good_queue_families(dev, surface);
if (queue_families.variant == Result_Err)
return (MargaretScoredPhysicalDevice){dev, -1, queue_families.err};

View File

@ -98,5 +98,8 @@ mat4 marie_3d_scal_mat4(float scale){
0, 0, 0, 1);
}
vec2 ivec2_to_vec2(ivec2 v){
return (vec2){(float)v.x, (float)v.y};
}
#endif

View File

@ -186,10 +186,8 @@ void save_tree_to_file(const BufRBTree_SetS64* set, SpanU8 name){
}
VecU8_append_span(&graph, cstr("}\n"));
mkdir_nofail("GRAPHS");
VecU8 dot_filename_nt = VecU8_fmt("GRAPHS/GRAPH_%s.gv%c", name, 0);
write_whole_file_or_abort((CSTR)dot_filename_nt.buf, VecU8_to_span(&graph));
write_file_by_path(VecU8_fmt("GRAPHS/GRAPH_%s.gv", name), VecU8_to_span(&graph));
VecU8_drop(graph);
VecU8_drop(dot_filename_nt);
VecU8 command_nt = VecU8_fmt("dot -Tpng GRAPHS/GRAPH_%s.gv -o GRAPHS/GRAPH_%s.png%c", name, name, 0);
calling_system_func_nofail((CSTR)command_nt.buf);
VecU8_drop(command_nt);

View File

@ -118,10 +118,8 @@ void save_tree_to_file(const RBTree_SetS64* set, SpanU8 name){
}
VecU8_append_span(&graph, cstr("}\n"));
mkdir_nofail("GRAPHS");
VecU8 dot_filename_nt = VecU8_fmt("GRAPHS/GRAPH_%s.gv%c", name, 0);
write_whole_file_or_abort((CSTR)dot_filename_nt.buf, VecU8_to_span(&graph));
write_file_by_path(VecU8_fmt("GRAPHS/GRAPH_%s.gv", name), VecU8_to_span(&graph));
VecU8_drop(graph);
VecU8_drop(dot_filename_nt);
VecU8 command_nt = VecU8_fmt("dot -Tpng GRAPHS/GRAPH_%s.gv -o GRAPHS/GRAPH_%s.png%c", name, name, 0);
calling_system_func_nofail((CSTR)command_nt.buf);
VecU8_drop(command_nt);

View File

@ -1,135 +0,0 @@
#!/usr/bin/env python3
"""
Convert between custom bottomup raw files (.r8g8b8a8 / .r8b8g8 / .r8 / .a8)
and normal PNG using Pillow.
Format
------
uint32 width (littleendian)
uint32 height (littleendian)
pixel data rows bottomfirst:
* .r8g8b8a8 : R G B A (4× uint8)
* .r8b8g8 : R G B (3× uint8)
* .r8 : R (1× uint8 <- grayscale)
* .a8 : A (can convert from it, but can't convert to it)
CLI
---
raw -> png : python raw_png_conv.py to_png input.raw output.png
png -> raw : python raw_png_conv.py to_raw input.png output.raw
"""
import argparse
import struct
from pathlib import Path
from PIL import Image
# --------------------------------------------------------------------- #
# Helpers
# --------------------------------------------------------------------- #
RAW_FORMATS = {
".r8g8b8a8": {"pix_size": 4, "mode": "RGBA"},
".r8g8b8": {"pix_size": 3, "mode": "RGB"},
".r8": {"pix_size": 1, "mode": "L"},
".a8": {"pix_size": 1, "mode": None}, # special-cased (alpha-only)
}
def get_fmt(path: Path):
fmt = RAW_FORMATS.get(path.suffix.lower())
if not fmt:
raise ValueError(f"Unknown raw extension: {path.suffix}")
return fmt
def read_header_and_data(path: Path, pix_size: int):
with path.open("rb") as f:
header = f.read(8)
if len(header) != 8:
raise ValueError("File too short for header")
w, h = struct.unpack("<II", header)
expected = w * h * pix_size
data = f.read()
if len(data) != expected:
raise ValueError(
f"Pixel data length mismatch: expected {expected}, got {len(data)}"
)
return w, h, data
def read_raw(path: Path) -> Image.Image:
"""Load any supported raw file -> Pillow Image."""
spec = get_fmt(path)
w, h, data = read_header_and_data(path, spec["pix_size"])
row_len = w * spec["pix_size"]
rows = [data[i : i + row_len] for i in range(0, len(data), row_len)]
top_down = b"".join(reversed(rows)) # flip bottomup -> topdown
# Special handling for .a8 (alpha-only -> LA with black color)
if path.suffix.lower() == ".a8":
big = bytearray(4 * len(top_down))
big[3::4] = top_down
big = bytes(big)
return Image.frombytes("RGBA", (w, h), big)
# Normal cases can be constructed directly
return Image.frombytes(spec["mode"], (w, h), top_down)
def write_raw(img: Image.Image, path: Path) -> None:
"""Write Pillow Image -> raw file chosen by path suffix."""
ext = path.suffix.lower()
spec = get_fmt(path)
if ext == ".a8":
raise ValueError("Don't convert to .a8 format")
target_mode = spec["mode"]
if img.mode != target_mode:
img = img.convert(target_mode)
w, h = img.size
data = img.tobytes()
row_len = w * spec["pix_size"]
rows = [data[i : i + row_len] for i in range(0, len(data), row_len)]
bottom_first = b"".join(reversed(rows)) # topdown -> bottomup
with path.open("wb") as f:
f.write(struct.pack("<II", w, h))
f.write(bottom_first)
# --------------------------------------------------------------------- #
# CLI
# --------------------------------------------------------------------- #
def to_png(src: Path, dst: Path):
read_raw(src).save(dst, "PNG")
def to_raw(src: Path, dst: Path):
write_raw(Image.open(src), dst)
def main():
ap = argparse.ArgumentParser(description="Convert raw <-> PNG")
sub = ap.add_subparsers(dest="cmd", required=True)
p_png = sub.add_parser("to_png", help="raw -> png")
p_png.add_argument("src", type=Path)
p_png.add_argument("dst", type=Path)
p_raw = sub.add_parser("to_raw", help="png -> raw")
p_raw.add_argument("src", type=Path)
p_raw.add_argument("dst", type=Path)
args = ap.parse_args()
if args.cmd == "to_png":
to_png(args.src, args.dst)
else:
to_raw(args.src, args.dst)
if __name__ == "__main__":
main()

View File

@ -105,7 +105,7 @@ const LizaInstrument_Table LizaInstrument_Table_WeirdGuitar = {
BoxLizaInstrument BoxLizaInstrument_from_WeirdGuitar(WeirdGuitar obj) {
void* mem = safe_malloc(sizeof(WeirdGuitar));
memcpy(mem, &obj, sizeof(WeirdGuitar));
return (BoxLizaInstrument){.m = mem, .t = &LizaInstrument_Table_WeirdGuitar};
return (BoxLizaInstrument){.r = mem, .t = &LizaInstrument_Table_WeirdGuitar};
}
/* ElectroBlaster which produces AmplitudeModulationSound */
@ -192,7 +192,7 @@ const LizaInstrument_Table LizaInstrument_Table_AMKeys = {
BoxLizaInstrument BoxLizaInstrument_from_AMKeys(AMKeys obj) {
void* mem = safe_malloc(sizeof(AMKeys));
memcpy(mem, &obj, sizeof(AMKeys));
return (BoxLizaInstrument){.m = mem, .t = &LizaInstrument_Table_AMKeys};
return (BoxLizaInstrument){.r = mem, .t = &LizaInstrument_Table_AMKeys};
}
/* FMKeys which produces FrequencyModulationSound */
@ -278,7 +278,7 @@ const LizaInstrument_Table LizaInstrument_Table_FMKeys = {
BoxLizaInstrument BoxLizaInstrument_from_FMKeys(FMKeys obj) {
void* mem = safe_malloc(sizeof(FMKeys));
memcpy(mem, &obj, sizeof(FMKeys));
return (BoxLizaInstrument){.m = mem, .t = &LizaInstrument_Table_FMKeys};
return (BoxLizaInstrument){.r = mem, .t = &LizaInstrument_Table_FMKeys};
}

View File

@ -100,7 +100,8 @@ static void r2a_app_h_pw_stream_process(void *ug){
return;
}
struct spa_buffer *buf = b->buffer;
uint32_t stride = sizeof(int16_t) * DEFAULT_CHANNELS;
assert(buf->n_datas >= 1);
const uint32_t stride = sizeof(int16_t) * DEFAULT_CHANNELS;
uint32_t n_frames = buf->datas[0].maxsize / stride;
if (b->requested)
n_frames = SPA_MIN(b->requested, n_frames);
@ -515,12 +516,12 @@ static void r2a_app_h_wl_keyboard_key(
};
if (state->selected_instrument < state->instruments.len) {
// todo: add box to ref and box to mref methods
const BoxLizaInstrument* instrument = &VecMyInstrument_at(&state->instruments, state->selected_instrument)->liza;
BoxLizaInstrument* instrument = &VecMyInstrument_mat(&state->instruments, state->selected_instrument)->liza;
for (int i = 0; i < ARRAY_SIZE(octave); i++) {
if (keysym == octave[i] && key_action == WL_KEYBOARD_KEY_STATE_PRESSED) {
safe_pthread_mutex_lock(&state->audio_thread_bridge->mut);
VecBoxLizaSound_append(&state->audio_thread_bridge->cmd.new_sounds,
instrument->t->ding(instrument->m, 440 * pow(2, (double)i / 12), 0.9));
BoxLizaInstrument_ding(instrument, 440 * pow(2, (double)i / 12), 0.9));
safe_pthread_mutex_unlock(&state->audio_thread_bridge->mut);
break;
}

View File

@ -101,7 +101,7 @@ void BoxLizaSound_drop(BoxLizaSound self) {
free(self.m);
}
#include "../../../../gen/l2/eve/r2/VecBoxLizaSound.h"
#include "../../../../gen/l1/eve/r2/VecBoxLizaSound.h"
typedef struct {
bool stop;

232
src/l2/tests/r2/r2c.c Normal file
View File

@ -0,0 +1,232 @@
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sound/asound.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <errno.h>
#define DESIRED_SAMPLE_RATE 44100
#define DESIRED_CHANNELS 2 // Prefer stereo, as mono often not supported on hardware
#define DESIRED_PERIOD_SIZE 1024
#define DESIRED_PERIODS 4
#define FORMAT SNDRV_PCM_FORMAT_S16_LE
#define DURATION 5 // seconds
#define BYTES_PER_SAMPLE 2
int main() {
int card = -1, device = -1;
FILE *proc = fopen("/proc/asound/pcm", "r");
if (!proc) {
perror("Failed to open /proc/asound/pcm");
return 1;
}
printf("Opened /proc/asound/pcm\n");
char line[256];
while (fgets(line, sizeof(line), proc)) {
if (strstr(line, "playback")) {
sscanf(line, "%02d-%02d", &card, &device);
break;
}
}
fclose(proc);
if (card < 0 || device < 0) {
fprintf(stderr, "No playback devices found\n");
return 1;
}
char devname[64];
snprintf(devname, sizeof(devname), "/dev/snd/pcmC%dD%dp", card, device);
int fd = open(devname, O_WRONLY);
if (fd < 0) {
perror("Failed to open PCM device");
return 1;
}
printf("Opened device\n");
struct snd_pcm_hw_params params;
memset(&params, 0, sizeof(params));
// Initialize to full possible ranges for refinement
int i;
for (i = SNDRV_PCM_HW_PARAM_FIRST_MASK; i <= SNDRV_PCM_HW_PARAM_LAST_MASK; i++) {
struct snd_mask *mask = &params.masks[i - SNDRV_PCM_HW_PARAM_FIRST_MASK];
mask->bits[0] = ~0U;
mask->bits[1] = ~0U;
}
for (i = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; i <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; i++) {
struct snd_interval *interval = &params.intervals[i - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL];
interval->min = 0;
interval->max = ~0U;
interval->openmin = interval->openmax = 0;
interval->integer = 0;
}
params.rmask = ~0U;
params.cmask = 0;
params.info = ~0U;
// Refine to hardware-supported ranges
if (ioctl(fd, SNDRV_PCM_IOCTL_HW_REFINE, &params) < 0) {
perror("Failed initial HW_REFINE");
close(fd);
return 1;
}
printf("Refined hw params\n");
// Set access to RW_INTERLEAVED if supported
struct snd_mask *access_mask = &params.masks[SNDRV_PCM_HW_PARAM_ACCESS - SNDRV_PCM_HW_PARAM_FIRST_MASK];
unsigned int access_bit = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
if (!(access_mask->bits[access_bit / 32] & (1U << (access_bit % 32)))) {
fprintf(stderr, "RW_INTERLEAVED access not supported\n");
close(fd);
return 1;
}
memset(access_mask, 0, sizeof(*access_mask));
access_mask->bits[access_bit / 32] |= (1U << (access_bit % 32));
params.rmask |= (1U << SNDRV_PCM_HW_PARAM_ACCESS);
// Set format to S16_LE if supported
struct snd_mask *format_mask = &params.masks[SNDRV_PCM_HW_PARAM_FORMAT - SNDRV_PCM_HW_PARAM_FIRST_MASK];
unsigned int format_bit = FORMAT;
if (!(format_mask->bits[format_bit / 32] & (1U << (format_bit % 32)))) {
fprintf(stderr, "S16_LE format not supported\n");
close(fd);
return 1;
}
memset(format_mask, 0, sizeof(*format_mask));
format_mask->bits[format_bit / 32] |= (1U << (format_bit % 32));
params.rmask |= (1U << SNDRV_PCM_HW_PARAM_FORMAT);
// Set channels to nearest supported (prefer DESIRED_CHANNELS)
struct snd_interval *channels_int = &params.intervals[SNDRV_PCM_HW_PARAM_CHANNELS - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL];
unsigned int channels = DESIRED_CHANNELS;
if (channels < channels_int->min) channels = channels_int->min;
if (channels > channels_int->max) channels = channels_int->max;
if (channels != DESIRED_CHANNELS) {
fprintf(stderr, "Adjusted channels to %u (hardware range: %u-%u)\n", channels, channels_int->min, channels_int->max);
}
channels_int->min = channels_int->max = channels;
channels_int->integer = 1;
params.rmask |= (1U << SNDRV_PCM_HW_PARAM_CHANNELS);
// Set sample rate to nearest supported
struct snd_interval *rate_int = &params.intervals[SNDRV_PCM_HW_PARAM_RATE - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL];
unsigned int sample_rate = DESIRED_SAMPLE_RATE;
if (sample_rate < rate_int->min) sample_rate = rate_int->min;
if (sample_rate > rate_int->max) sample_rate = rate_int->max;
if (sample_rate != DESIRED_SAMPLE_RATE) {
fprintf(stderr, "Adjusted sample rate to %u Hz (hardware range: %u-%u)\n", sample_rate, rate_int->min, rate_int->max);
}
rate_int->min = rate_int->max = sample_rate;
rate_int->integer = 1;
params.rmask |= (1U << SNDRV_PCM_HW_PARAM_RATE);
// Set period size to nearest supported
struct snd_interval *period_size_int = &params.intervals[SNDRV_PCM_HW_PARAM_PERIOD_SIZE - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL];
unsigned int period_size = DESIRED_PERIOD_SIZE;
if (period_size < period_size_int->min) period_size = period_size_int->min;
if (period_size > period_size_int->max) period_size = period_size_int->max;
if (period_size != DESIRED_PERIOD_SIZE) {
fprintf(stderr, "Adjusted period size to %u frames (hardware range: %u-%u)\n", period_size, period_size_int->min, period_size_int->max);
}
period_size_int->min = period_size_int->max = period_size;
period_size_int->integer = 1;
params.rmask |= (1U << SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
// Set periods (less strict, clamp to range)
struct snd_interval *periods_int = &params.intervals[SNDRV_PCM_HW_PARAM_PERIODS - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL];
unsigned int periods = DESIRED_PERIODS;
if (periods < periods_int->min) periods = periods_int->min;
if (periods > periods_int->max) periods = periods_int->max;
if (periods != DESIRED_PERIODS) {
fprintf(stderr, "Adjusted periods to %u (hardware range: %u-%u)\n", periods, periods_int->min, periods_int->max);
}
periods_int->min = periods_int->max = periods;
periods_int->integer = 1;
params.rmask |= (1U << SNDRV_PCM_HW_PARAM_PERIODS);
// Refine again with desired values to confirm
if (ioctl(fd, SNDRV_PCM_IOCTL_HW_REFINE, &params) < 0) {
perror("Failed to refine desired HW params");
close(fd);
return 1;
}
printf("Refined hw params the last time\n");
// Now apply the parameters
if (ioctl(fd, SNDRV_PCM_IOCTL_HW_PARAMS, &params) < 0) {
perror("Failed to set HW params");
close(fd);
return 1;
}
printf("HW params set\n");
if (ioctl(fd, SNDRV_PCM_IOCTL_PREPARE, 0) < 0) {
perror("Failed to prepare PCM");
close(fd);
return 1;
}
printf("Prepared\n");
// Generate and play sine wave
size_t frame_size = channels * BYTES_PER_SAMPLE;
short *buffer = malloc(period_size * frame_size);
if (!buffer) {
perror("Failed to allocate buffer");
close(fd);
return 1;
}
unsigned long total_frames = (unsigned long)sample_rate * DURATION;
unsigned long frames_written = 0;
double phase = 0.0;
const double freq = 440.0; // Hz
const double phase_inc = 2.0 * M_PI * freq / sample_rate;
while (frames_written < total_frames) {
size_t frames_to_write = period_size;
if (frames_written + frames_to_write > total_frames) {
frames_to_write = total_frames - frames_written;
}
for (size_t j = 0; j < frames_to_write; ++j) {
short sample = (short)(32767.0 * sin(phase));
for (unsigned int ch = 0; ch < channels; ++ch) {
buffer[j * channels + ch] = sample;
}
phase += phase_inc;
if (phase >= 2.0 * M_PI) phase -= 2.0 * M_PI;
}
ssize_t bytes_written = write(fd, buffer, frames_to_write * frame_size);
printf("bytes written = %lu\n", bytes_written);
if (bytes_written < 0) {
if (errno == EPIPE) {
// Underrun: recover
ioctl(fd, SNDRV_PCM_IOCTL_PREPARE, 0);
continue;
}
perror("Write failed");
break;
}
frames_written += bytes_written / frame_size;
}
free(buffer);
// Drain remaining data
ioctl(fd, SNDRV_PCM_IOCTL_DRAIN, 0);
close(fd);
return 0;
}

Binary file not shown.

Binary file not shown.

BIN
src/l3/models/bone.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 916 KiB

6026920
src/l3/models/skeleton.obj Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,16 @@
import Allie
import Geom
import Control.Monad (forM_)
import Control.Monad (forM_, when)
import Data.Char (ord)
import Data.IORef (newIORef, readIORef, writeIORef, modifyIORef)
import Data.Word(Word32, Word64)
lucyFaceAddGlyphRange :: LucyFaceFixedSize -> Char -> Char -> IO ()
lucyFaceAddGlyphRange ffs a b = lucyFaceAddGlyphs ffs aInt (bInt - aInt + 1)
where aInt = ((fromIntegral $ ord a) :: Word32)
bInt = ((fromIntegral $ ord b) :: Word32)
-- Game configurable
goodColorOfCube :: (Integral a) => a -> Vec3
goodColorOfCube i = ((Vec3 100 0 0) ^*^ t) ^+^ ((Vec3 0 50 90) ^*^ (1 - t)) where t = ((fromIntegral i :: Float) / 4)
@ -8,49 +18,114 @@ goodColorOfCube i = ((Vec3 100 0 0) ^*^ t) ^+^ ((Vec3 0 50 90) ^*^ (1 - t)) wher
goodLightPos :: (Integral a) => a -> Vec3
goodLightPos i = ((Vec3 0 2 1) ^*^ t) ^+^ ((Vec3 5 1 1) ^*^ (1 - t)) where t = ((fromIntegral i :: Float) / 4)
projectDirOntoPlane :: Vec3 -> Vec2
projectDirOntoPlane (Vec3 x y z) = normalize (Vec2 x z)
heroHeight :: Float
heroHeight = 1.89
heroCamPos :: Vec2 -> Vec3
heroCamPos (Vec2 x z) = Vec3 x heroHeight z
puckLevitationHeight :: Float
puckLevitationHeight = 0.4 + 0.2
puckSpots :: [Vec2]
puckSpots = [(Vec2 (-10) (-10)), (Vec2 (-15) (-15)) , (Vec2 (-18) (-18)), (Vec2 (-18) (-25)), (Vec2 (-18) (-30))]
introText :: String
introText = "Накануне новогодняя сессия 2025 года. Все были готовы провести экзамен по матану, но злой Гринч похитил 67 " ++
"шайб с бергамотом Матвея и улетел. Вся надежда была потеряна, но в полёте Гринч выронил все шайбы, и те упали в Дубки. Тебе " ++
"необходимо вернуть их Матвею.\n" ++
"Естесственно, вернёшь ты их Гринчу, так как ты и сам не понимаешь преобразования Фурье и хочешь помочь сорвать " ++
"экзамен.\n\n" ++
"Итак, ты в Дубках..."
main :: IO()
main = do
alice <- newAlice
aliceSetSkyColor alice (Vec4 0.9 0 0.6 1)
aliceSetCamPos alice (Vec3 0 heroHeight 0)
face <- aliceNewLucyFace alice "src/l3/fonts/DMSerifText-Regular.ttf"
faceOf40 <- aliceLucyFaceOfSize face 40
lucyFaceAddGlyphs faceOf40 32 (126 - 32 + 1)
lucyFaceAddGlyphRange faceOf40 ' ' '~'
lucyFaceAddGlyphRange faceOf40 'а' 'я'
lucyFaceAddGlyphRange faceOf40 'А' 'Я'
aliceAddText alice faceOf40 (Vec4 1 1 0 1) "Privet" 100 200
weirdStructure <- aliceAddGenericMeshHand alice "gen/l2/models/log_10_2_6.AliceGenericMesh"
"src/l3/textures/log_10_2_6_diffuse.png" "gen/l2/textures/log_10_2_6_NORMAL.png" "src/l3/textures/log_10_2_6_specular.png"
aliceGenericMeshResizeInstanceArr alice weirdStructure 1
aliceGenericMeshSetInst weirdStructure 0 (AliceGenericMeshInstance (mat4Transit (Vec3 (-3.0) (-2.0) (-5.0))))
aliceGenericMeshSetInst weirdStructure 0 (AliceGenericMeshInstance (mat4Transit (Vec3 (-3.0) (0.0) (-5.0))))
floorTile <- aliceAddGenericMeshHand alice "gen/l2/models/quad.AliceGenericMesh"
"src/l3/textures/asphalt_diffuse.png" "gen/l2/textures/flat_NORMAL.png" "src/l3/textures/funny_floor_specular.png"
aliceGenericMeshResizeInstanceArr alice floorTile 49
puck <- aliceAddGenericMeshHand alice "gen/l2/models/puck.AliceGenericMesh"
"src/l3/textures/puck_diffuse.png" "gen/l2/textures/puck_NORMAL.png" "src/l3/textures/puck_specular.png"
forM_ [0..6] $ \x -> forM_ [0..6] $ \z ->
aliceGenericMeshSetInst floorTile (z * 7 + x) (AliceGenericMeshInstance
(mat4Transit (Vec3 ((fromIntegral x) * 10 - 35) 0 ((fromIntegral z) * 10 - 35))))
cube <- aliceAddShinyMeshHand alice "gen/l2/models/cube.AliceShinyMesh"
aliceShinyMeshResizeInstanceArr alice cube 5
aliceSetPointLightCount alice 5
forM_ [0..4] $ \i -> do
aliceShinyMeshSetInst cube i (AliceShinyMeshInstance (mat4Transit (goodLightPos i)) (Vec3 1 1 1) (goodColorOfCube i))
aliceShinyMeshSetInst cube i (AliceShinyMeshInstance (mat4Transit (goodLightPos i)) (goodColorOfCube i))
aliceSetPointLight alice (fromIntegral i) (AlicePointLight (goodLightPos i) (goodColorOfCube i))
-- state <- newIORef 67
aliceGenericMeshResizeInstanceArr alice puck (fromIntegral $ length puckSpots)
forM_ (zip[0..] puckSpots) $ \(i, (Vec2 x z)) -> aliceGenericMeshSetInst puck (fromIntegral i) (AliceGenericMeshInstance
(mat4Transit (Vec3 x puckLevitationHeight z )))
heroPos <- newIORef (Vec2 0 0)
puckRotation <- newIORef (0 :: Float)
-- Create the Callbacks structure.
let callbacks = Callbacks myonKeyboardKey myonAnotherFrame where
myonKeyboardKey keysym keyAction = do
-- old <- readIORef state
-- writeIORef state (old + 1)
putStrLn ("Got a keypress")
myonAnotherFrame fl = do
oldPos <- aliceGetCamPos alice
goForward <- aliceIsPressed alice 0x77
if goForward
then do
backDir <- aliceGetCamBack alice
aliceSetCamPos alice (oldPos ^+^ (backDir ^*^ (-fl * 10)))
else return ()
curPuckRotation <- readIORef puckRotation
writeIORef puckRotation (curPuckRotation + fl * 0.2)
--forM_ (zip[0..] puckSpots) $ \(i, (Vec2 x z)) -> aliceGenericMeshSetInst puck (fromIntegral i) (AliceGenericMeshInstance
-- (rot4) ^*^ (mat4Transit (Vec3 x puckLevitationHeight z )))
backDir <- aliceGetCamBack alice
let projBack = projectDirOntoPlane backDir
rightDir <- aliceGetCamRight alice
let projRight = projectDirOntoPlane rightDir
goForward <- aliceIsPressed alice (fromIntegral $ ord 'w')
when goForward $ do
curHeroPos <- readIORef heroPos
let nextHeroPos = (curHeroPos ^+^ (projBack ^*^ (fl * (-10))))
writeIORef heroPos nextHeroPos
aliceSetCamPos alice $ heroCamPos nextHeroPos
goBackward <- aliceIsPressed alice (fromIntegral $ ord 's')
when goBackward $ do
curHeroPos <- readIORef heroPos
let nextHeroPos = (curHeroPos ^+^ (projBack ^*^ (fl * (10))))
writeIORef heroPos nextHeroPos
aliceSetCamPos alice $ heroCamPos nextHeroPos
goLeft <- aliceIsPressed alice (fromIntegral $ ord 'a')
when goLeft $ do
curHeroPos <- readIORef heroPos
let nextHeroPos = (curHeroPos ^+^ (projRight ^*^ (fl * (-10))))
writeIORef heroPos nextHeroPos
aliceSetCamPos alice $ heroCamPos nextHeroPos
goRight <- aliceIsPressed alice (fromIntegral $ ord 'd')
when goRight $ do
curHeroPos <- readIORef heroPos
let nextHeroPos = (curHeroPos ^+^ (projRight ^*^ (fl * (10))))
writeIORef heroPos nextHeroPos
aliceSetCamPos alice $ heroCamPos nextHeroPos
--cur <- readIORef state
--aliceClearScreenTextLabel alicePerm
--aliceAddScreenTextLabel alicePerm ("Current value is = " ++ show cur)
-- Allocate space for the struct, poke it, and pass to C.
aliceMainloop alice callbacks

View File

@ -18,71 +18,107 @@ AliceGenericMeshPath AliceGenericMeshPath_for_puck(){
};
}
void main_h_on_wayland_keyboard_key(void* data, U32 keysym, U32 act){
typedef struct{
Alice* alice;
LucyFace* font_face;
RBTreeNodeLucyFaceFixedSize* font_face_of_size_40;
} R4AlphaStuff;
void main_h_on_wayland_keyboard_key(void* data, U32 keysym, U32 act){
}
void main_h_on_another_frame(void* data, float fl){
R4AlphaStuff *st = data;
Alice* alice = st->alice;
margaret_ns_time TIME = margaret_clock_gettime_monotonic_raw();
// printf("Updating text\n");
// LucyRenderer_clear(&alice->lucy_renderer);
// VecU8 text = VecU8_fmt("Time is %u.%u\nHave a good day sir\n", (U64)TIME.tv_sec, (U64)TIME.tv_nsec);
// LucyRenderer_add_text(&alice->lucy_renderer, st->font_face_of_size_40, (vec4){0.1f, 0.2f, 0, 1}, 0,
// VecU8_to_span(&text), (ivec2){100, 100});
}
int main(){
R4AlphaStuff st;
Alice* alice = Alice_new();
st.alice = alice;
st.alice->guest = &st;
LucyFace* font_face = LucyFace_new(alice->ft_library, &alice->lucy_cache,
VecU8_fmt("%s/src/l3/fonts/DMSerifText-Regular.ttf", cstr(".")));
RBTreeNodeLucyFaceFixedSize* font_face_of_size_40 = LucyFace_of_size(font_face, 40);
// st.font_face = LucyFace_new(st.alice->ft_library, &st.alice->lucy_cache,
// VecU8_fmt("%s/src/l3/fonts/DMSerifText-Regular.ttf", cstr(".")));
st.font_face = LucyFace_new(st.alice->ft_library, &st.alice->lucy_cache,
VecU8_fmt("%s/src/l3/fonts/GreatVibes-Regular.ttf", cstr(".")));
st.font_face_of_size_40 = LucyFace_of_size(st.font_face, 40);
VecLucyGlyphCachingRequest lucy_requests = VecLucyGlyphCachingRequest_new();
VecU32Segment ranges_needed = VecU32Segment_new();
VecU32Segment_append(&ranges_needed, (U32Segment){.start = 32, .len = 126 - 32 + 1});
VecLucyGlyphCachingRequest_append(&lucy_requests, (LucyGlyphCachingRequest){
.sized_face = font_face_of_size_40, .codepoint_ranges = ranges_needed,
.sized_face = st.font_face_of_size_40, .codepoint_ranges = ranges_needed,
});
LucyGlyphCache_add_glyphs(lucy_requests);
lucy_requests = VecLucyGlyphCachingRequest_new();
ranges_needed = VecU32Segment_new();
VecU32Segment_append(&ranges_needed, (U32Segment){.start = 0x430, .len = 0x44f - 0x430 + 1});
VecLucyGlyphCachingRequest_append(&lucy_requests, (LucyGlyphCachingRequest){
.sized_face = st.font_face_of_size_40, .codepoint_ranges = ranges_needed,
});
LucyRenderer_add_text(&alice->lucy_renderer, font_face_of_size_40, (vec4){1, 0, 0, 1}, 0,
cstr("Bebra budet\notnyahana"), (ivec2){10, 10});
LucyGlyphCache_add_glyphs(lucy_requests);
LucyRenderer_add_simple_label(&st.alice->lucy_renderer, st.font_face_of_size_40, (vec4){0, 0, 0, 1}, 0,
cstr("Bebra budet\nотнюхана\n"), (ivec2){10, 10});
ListNodeAliceGenericMeshHand* model_gen = Alice_add_generic_mesh(alice, AliceGenericMeshPath_for_log(cstr("."), 10, 2, 6));
AliceGenericMeshHand_resize_instance_arr(alice, &model_gen->el, 1);
for (int X = 0; X < 1; X++) {
for (int Z = 0; Z < 1; Z++) {
AliceGenericMeshHand_set_inst(&model_gen->el, X * 10 + Z, (GenericMeshInstanceInc){
.model_t = marie_translation_mat4((vec3){11.f * (float)X, -6, 4.f * (float)Z}),
});
}
}
// ListNodeAliceShinyMeshHand *model_sh = Alice_add_shiny_mesh(alice, vcstr("./gen/l2/models/cube.AliceShinyMesh"));
// AliceShinyMeshHand_resize_instance_arr(alice, &model_sh->el, 100);
// for (int X = 0; X < 10; X++) {
// for (int Z = 0; Z < 10; Z++) {
// AliceShinyMeshHand_set_inst(&model_sh->el, X * 10 + Z, (ShinyMeshInstanceInc){
// .color_on = {0, 1, 0}, .color_off = {0.3f, 0.6f, 0.3f},
// .model_t = marie_translation_mat4((vec3){11.f * (float)X - 20, 10, 4.f * (float)Z - 10}),
// ListNodeAliceGenericMeshHand* model_gen = Alice_add_generic_mesh(st.alice, AliceGenericMeshPath_for_log(cstr("."), 10, 2, 6));
// AliceGenericMeshHand_resize_instance_arr(st.alice, &model_gen->el, 1);
//
// for (int X = 0; X < 1; X++) {
// for (int Z = 0; Z < 1; Z++) {
// AliceGenericMeshHand_set_inst(&model_gen->el, X * 10 + Z, (GenericMeshInstanceInc){
// .model_t = marie_translation_mat4((vec3){11.f * (float)X, -6, 4.f * (float)Z}),
// });
// }
// }
// Pipeline0UBO* ubo = (Pipeline0UBO*)MargaretSubbuf_get_mapped(&alice->pipeline0_ubo.staging);
// assert(pipeline_0_ubo_point_light_max_count >= 100);
// ubo->point_light_count = 100;
// ubo->spotlight_count = 0;
// for (int X = 0; X < 10; X++) {
// for (int Z = 0; Z < 10; Z++) {
// ubo->point_light_arr[X * 10 + Z] = (Pipeline0PointLight){
// .pos = (vec3){11.f * (float)X - 20, 10, 4.f * (float)Z - 10},
// .color = {5, 5, 5}
// };
// }
// }
// ubo->point_light_arr[0].color = (vec3){100, 100, 100};
ListNodeAliceShinyMeshHand *model_sh = Alice_add_shiny_mesh(st.alice, vcstr("./gen/l2/models/cube.AliceShinyMesh"));
AliceShinyMeshHand_resize_instance_arr(st.alice, &model_sh->el, 100);
for (int X = 0; X < 10; X++) {
for (int Z = 0; Z < 10; Z++) {
AliceShinyMeshHand_set_inst(&model_sh->el, X * 10 + Z, (ShinyMeshInstanceInc){
.color_on = {0, 1, 0},
.model_t = marie_translation_mat4((vec3){11.f * (float)X - 20, 10, 4.f * (float)Z - 10}),
});
}
}
Pipeline0UBO* ubo = (Pipeline0UBO*)MargaretSubbuf_get_mapped(&st.alice->pipeline0_ubo.staging);
assert(pipeline_0_ubo_point_light_max_count >= 100);
ubo->point_light_count = 100;
ubo->spotlight_count = 0;
for (int X = 0; X < 10; X++) {
for (int Z = 0; Z < 10; Z++) {
ubo->point_light_arr[X * 10 + Z] = (Pipeline0PointLight){
.pos = (vec3){11.f * (float)X - 20, 10, 4.f * (float)Z - 10},
.color = {5, 5, 5}
};
}
}
ubo->point_light_arr[0].color = (vec3){100, 100, 100};
// ListNodeAliceGenericMeshHand* model_puck = Alice_add_generic_mesh(alice, AliceGenericMeshPath_for_puck());
// AliceGenericMeshHand_resize_instance_arr(alice, &model_puck->el, 100);
ListNodeAliceGenericMeshHand* skeleton_mesh = Alice_add_generic_mesh(st.alice, (AliceGenericMeshPath){
.topology_path = vcstr("./src/l3/models/skeleton.obj"),
.diffuse_texture_path = vcstr("./src/l3/models/bone.png"),
.normal_texture_path = vcstr("./gen/l2/textures/flat_NORMAL.png"),
.specular_texture_path = vcstr("./gen/l2/textures/flat_NORMAL.png"),
});
AliceGenericMeshHand_resize_instance_arr(alice, &skeleton_mesh->el, 1);
AliceGenericMeshHand_set_inst(&skeleton_mesh->el, 0, (GenericMeshInstanceInc){
.model_t = marie_translation_mat4((vec3){5.f, -3, 12.f}),
});
// ListNodeAliceGenericMeshHand* model_puck = Alice_add_generic_mesh(st->alice, AliceGenericMeshPath_for_puck());
// AliceGenericMeshHand_resize_instance_arr(st->alice, &model_puck->el, 100);
// for (int X = 0; X < 10; X++) {
// for (int Z = 0; Z < 10; Z++) {
// AliceGenericMeshHand_set_inst(&model_puck->el, X * 10 + Z, (GenericMeshInstanceInc){
@ -90,7 +126,7 @@ int main(){
// });
// }
// }
Alice_mainloop(alice, &(AliceCallbacks){
Alice_mainloop(st.alice, &(AliceCallbacks){
.on_wl_keyboard_key = main_h_on_wayland_keyboard_key,
.on_another_frame = main_h_on_another_frame,
});

View File

Before

Width:  |  Height:  |  Size: 2.5 MiB

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 B

View File

@ -1,7 +1,7 @@
#version 450
layout(location = 0) in vec3 norm;
layout(location = 1) in vec3 color_off;
layout(location = 1) in vec3 color_off;
layout(location = 2) in vec3 color_on;
layout(location = 3) in vec3 pos;
@ -50,6 +50,6 @@ void main(){
for (int i = 0; i < spotlight_count; i++) {
Pipeline0Spotlight lamp = spotlight_arr[i];
}
vec3 color = color_off * diffuse_illumination + 0.5 * specular_illumination + color_on;
vec3 color = color_off * diffuse_illumination + (0.05 + 0.45 * length(color_off)) * specular_illumination + color_on;
fin_color = vec4(color, 1);
}

View File

@ -1,11 +1,11 @@
#version 450
layout(location = 0) in vec3 pos;
layout(location = 1) in vec3 normal;
layout(location = 1) in vec3 color;
layout(location = 2) in vec3 normal;
layout(location = 2) in mat4 model_t;
/* 2 <- 3, 4, 5 */
layout(location = 6) in vec3 color_off;
layout(location = 3) in mat4 model_t;
/* 3 <- 4, 5, 6 */
layout(location = 7) in vec3 color_on;
layout(location = 8) in mat3 normal_t;
/* 8 <- 9, 10 */
@ -21,7 +21,7 @@ layout(push_constant, std430) uniform pc {
void main(){
vsout_normal = normalize(normal_t * normal);
vsout_color_off = color_off;
vsout_color_off = color;
vsout_color_on = color_on;
vec4 real_pos = model_t * vec4(pos, 1);
vsout_pos = real_pos.xyz;

View File

@ -13,4 +13,5 @@ layout (binding=0) uniform sampler2D images[];
void main(){
float I = texture(images[nonuniformEXT(tex_ind)], tex_cord).r;
fin_color = vec4(color.rgb, color.a * I);
//fin_color = vec4(0, 0, 0, 1);
}

View File

@ -1,9 +1,11 @@
#version 450
layout(location = 0) in vec4 color;
layout(location = 1) in vec2 pos;
layout(location = 2) in vec2 tex_cord;
layout(location = 3) in uint tex_ind;
layout(location = 1) in vec2 lt_pos;
layout(location = 2) in vec2 br_pos;
layout(location = 3) in vec2 lt_tex;
layout(location = 4) in vec2 br_tex;
layout(location = 5) in uint tex_ind;
layout(push_constant, std430) uniform pc {
float width;
@ -23,8 +25,17 @@ float deng(float B1, float x){
}
void main(){
const vec2 all_v_pos[6] = vec2[](
vec2(br_pos.x, lt_pos.y), lt_pos, vec2(lt_pos.x, br_pos.y),
vec2(br_pos.x, lt_pos.y), vec2(lt_pos.x, br_pos.y), br_pos
);
const vec2 all_v_tex[6] = vec2[](
vec2(br_tex.x, lt_tex.y), lt_tex, vec2(lt_tex.x, br_tex.y),
vec2(br_tex.x, lt_tex.y), vec2(lt_tex.x, br_tex.y), br_tex
);
vsout_color = color;
vsout_tex_cord = tex_cord;
vsout_tex_cord = all_v_tex[gl_VertexIndex % 6];
vsout_tex_ind = tex_ind;
vec2 pos = all_v_pos[gl_VertexIndex % 6];
gl_Position = vec4(deng(width, pos.x), deng(height, pos.y), 0, 1);
}