diff --git a/.gitignore b/.gitignore index 9b8c381..4306bd3 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,9 @@ cmake-build-debug/ .idea/ vgcore.* -gen/ -*.pdf \ No newline at end of file +/gen/ +*.pdf +*.r8g8b8a8 +*.r8b8g8 +*.r8 +*.xcf diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ea6104..fb83dc4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,9 @@ add_executable(1_test src/l1/tests/t1.c) add_executable(0_render_test src/l2/tests/r0.c) target_link_libraries(0_render_test -lvulkan -lX11 -lm) +add_executable(0_render_test_tex_init_prep src/l2/tests/r0_tex_init_prep.c) +target_link_libraries(0_render_test_tex_init_prep -lm) + add_executable(0_play_test src/l3/tests/p0.c) target_link_libraries(0_play_test -lncurses) diff --git a/src/l1/core/VecSpan_int_primitives.h b/src/l1/core/VecSpan_int_primitives.h index f04494a..0dc731e 100644 --- a/src/l1/core/VecSpan_int_primitives.h +++ b/src/l1/core/VecSpan_int_primitives.h @@ -21,9 +21,16 @@ ConstSpanU8 ConstSpanU8_from_cstr(const char* dc) { } #define cstr(dc) ConstSpanU8_from_cstr(dc) +/* Not thread safe (for stdout) !*/ void ConstSpanU8_print(ConstSpanU8 str) { for (size_t i = 0; i < str.len; i++) - putchar((int)*ConstSpanU8_at(str, i)); + putc((int)*ConstSpanU8_at(str, i), stdout); +} + +/* Not thread safe (for `stream`) ! */ +void ConstSpanU8_fprint( ConstSpanU8 str, FILE* stream) { + for (size_t i = 0; i < str.len; i++) + putc((int)*ConstSpanU8_at(str, i), stream); } SpanT_VecT_trivmove_COMPLETE_Definition(U16) diff --git a/src/l1/core/int_primitives.h b/src/l1/core/int_primitives.h index 3e4e7ca..c0cb9bd 100644 --- a/src/l1/core/int_primitives.h +++ b/src/l1/core/int_primitives.h @@ -57,5 +57,7 @@ T MAX_##T (T a, T b){ return a < b ? b : a; } int_minmax_function_Definition(U8) int_minmax_function_Definition(U32) int_minmax_function_Definition(U64) +int_minmax_function_Definition(float) +int_minmax_function_Definition(double) #endif diff --git a/src/l1/gen/geom_and_textures.h b/src/l1/gen/geom_and_textures.h new file mode 100644 index 0000000..5666c6f --- /dev/null +++ b/src/l1/gen/geom_and_textures.h @@ -0,0 +1,772 @@ +#ifndef PROTOTYPE_SRC_L1_GEN_GEOM_AND_TEXTURES_H +#define PROTOTYPE_SRC_L1_GEN_GEOM_AND_TEXTURES_H + +#include + +#include "../system/fileio.h" +#include "../core/VecU8_format.h" + +NODISCARD VecU8 begin_header(ConstSpanU8 guard) { + VecU8 res = VecU8_new(); + VecU8_append_span(&res, cstr("#ifndef ")); + VecU8_append_span(&res, guard); + VecU8_append_span(&res, cstr("\n#define ")); + VecU8_append_span(&res, guard); + VecU8_append_span(&res, cstr("\n/* Automatically generated file. Do not edit it. */\n\n")); + return res; +} + +/* Codegen script's working directory should be `gen` */ +void finish_header(VecU8 text_before_endif, const char* filename) { + VecU8_append_span(&text_before_endif, cstr("#endif\n")); + write_whole_file_or_abort(filename, VecU8_to_ConstSpanU8(&text_before_endif)); + VecU8_drop(text_before_endif); +} + +#define SPACE4 " " +#define SPACE8 " " +#define SPACE12 " " + +void string_append_vec_field_name(VecU8* str, int ci) { + assert(0 <= ci && ci < 4); + + VecU8_append(str, ci == 3 ? 'w' : 'x' + ci); +} + +void string_append_xvecy(VecU8* str, ConstSpanU8 xvec, int cc) { + VecU8_append_span(str, xvec); + VecU8_append(str, '0' + cc); +} + +NODISCARD VecU8 generate_xvecy_struct_definition(ConstSpanU8 xvec, ConstSpanU8 member, int cc) { + assert(2 <= cc && cc <= 4); + VecU8 res = VecU8_new(); + VecU8_append_span(&res, cstr("typedef struct {\n")); + + for (int ci = 0; ci < cc; ci++) { + VecU8_append_span(&res, cstr(SPACE4)); + VecU8_append_span(&res, member); + VecU8_append(&res, ' '); + string_append_vec_field_name(&res, ci); + VecU8_append_span(&res, cstr(";\n")); + } + + VecU8_append_span(&res, cstr("} ")); + string_append_xvecy(&res, xvec, cc); + VecU8_append_span(&res, cstr(";\n\n")); + return res; +} + +NODISCARD VecU8 generate_xvecy_method_add_xvecy(ConstSpanU8 xvec, ConstSpanU8 member, int cc) { + VecU8 res = VecU8_new(); + string_append_xvecy(&res, xvec, cc); + VecU8_append_span(&res, cstr(" ")); + string_append_xvecy(&res, xvec, cc); + VecU8_append_span(&res, cstr("_add_")); + string_append_xvecy(&res, xvec, cc); + VecU8_append_span(&res, cstr("(")); + string_append_xvecy(&res, xvec, cc); + VecU8_append_span(&res, cstr(" A, ")); + string_append_xvecy(&res, xvec, cc); + VecU8_append_span(&res, cstr(" B) {\n" SPACE4 "return (")); + string_append_xvecy(&res, xvec, cc); + VecU8_append_span(&res, cstr("){ ")); + for (int ci = 0; ci < cc; ci++) { + if (ci) + VecU8_append_span(&res, cstr(", ")); + VecU8_append_span(&res, cstr("A.")); + string_append_vec_field_name(&res, ci); + VecU8_append_span(&res, cstr(" + B.")); + string_append_vec_field_name(&res, ci); + } + VecU8_append_span(&res, cstr(" };\n}\n\n")); + return res; +} + +NODISCARD VecU8 generate_xvecy_method_minus_xvecy(ConstSpanU8 xvec, ConstSpanU8 member, int cc) { + VecU8 res = VecU8_new(); + string_append_xvecy(&res, xvec, cc); + VecU8_append_span(&res, cstr(" ")); + string_append_xvecy(&res, xvec, cc); + VecU8_append_span(&res, cstr("_minus_")); + string_append_xvecy(&res, xvec, cc); + VecU8_append_span(&res, cstr("(")); + string_append_xvecy(&res, xvec, cc); + VecU8_append_span(&res, cstr(" A, ")); + string_append_xvecy(&res, xvec, cc); + VecU8_append_span(&res, cstr(" B) {\n" SPACE4 "return (")); + string_append_xvecy(&res, xvec, cc); + VecU8_append_span(&res, cstr("){ ")); + for (int ci = 0; ci < cc; ci++) { + if (ci) + VecU8_append_span(&res, cstr(", ")); + VecU8_append_span(&res, cstr("A.")); + string_append_vec_field_name(&res, ci); + VecU8_append_span(&res, cstr(" - B.")); + string_append_vec_field_name(&res, ci); + } + VecU8_append_span(&res, cstr(" };\n}\n\n")); + return res; +} + + +NODISCARD VecU8 generate_xvecy_method_minus(ConstSpanU8 xvec, ConstSpanU8 member, int cc) { + VecU8 res = VecU8_new(); + string_append_xvecy(&res, xvec, cc); + VecU8_append_span(&res, cstr(" ")); + string_append_xvecy(&res, xvec, cc); + VecU8_append_span(&res, cstr("_minus(")); + string_append_xvecy(&res, xvec, cc); + VecU8_append_span(&res, cstr(" A) {\n" SPACE4 "return(")); + string_append_xvecy(&res, xvec, cc); + VecU8_append_span(&res, cstr("){ ")); + for (int ci = 0; ci < cc; ci++) { + if (ci) + VecU8_append_span(&res, cstr(", ")); + VecU8_append_span(&res, cstr("-A.")); + string_append_vec_field_name(&res, ci); + } + VecU8_append_span(&res, cstr(" };\n}\n\n")); + return res; +} + +NODISCARD VecU8 generate_xvecy_method_mul_scal(ConstSpanU8 xvec, ConstSpanU8 member, int cc) { + VecU8 res = VecU8_new(); + string_append_xvecy(&res, xvec, cc); + VecU8_append_span(&res, cstr(" ")); + string_append_xvecy(&res, xvec, cc); + VecU8_append_span(&res, cstr("_mul_scal(")); + string_append_xvecy(&res, xvec, cc); + VecU8_append_span(&res, cstr(" A, ")); + VecU8_append_span(&res, member); + VecU8_append_span(&res, cstr(" B) {\n" SPACE4 "return (")); + string_append_xvecy(&res, xvec, cc); + VecU8_append_span(&res, cstr("){ ")); + for (int ci = 0; ci < cc; ci++) { + if (ci) + VecU8_append_span(&res, cstr(", ")); + VecU8_append_span(&res, cstr("A.")); + string_append_vec_field_name(&res, ci); + VecU8_append_span(&res, cstr(" * B")); + } + VecU8_append_span(&res, cstr(" };\n}\n\n")); + return res; +} + +NODISCARD VecU8 generate_xvecy_method_div_by_scal(ConstSpanU8 xvec, ConstSpanU8 member, int cc) { + VecU8 res = VecU8_new(); + string_append_xvecy(&res, xvec, cc); + VecU8_append_span(&res, cstr(" ")); + string_append_xvecy(&res, xvec, cc); + VecU8_append_span(&res, cstr("_div_by_scal(")); + string_append_xvecy(&res, xvec, cc); + VecU8_append_span(&res, cstr(" A, ")); + VecU8_append_span(&res, member); + VecU8_append_span(&res, cstr(" B){\n" SPACE4 "return ")); + string_append_xvecy(&res, xvec, cc); + VecU8_append_span(&res, cstr("_mul_scal(A, 1/B);\n}\n\n")); + return res; +} + +void string_append_xmatnm(VecU8* str, ConstSpanU8 xmat, int cols, int rows) { + VecU8_append_span(str, xmat); + VecU8_append(str, '0' + cols); + if (rows != cols) { + VecU8_append(str, 'x'); + VecU8_append(str, '0' + rows); + } +} + +/* With columns padded to 16 bytes (for std140, std140 is our everything) */ +NODISCARD VecU8 generate_xmatnm_structure_definition(ConstSpanU8 xmat, ConstSpanU8 xvec, int cols, int rows, int sizeof_member) { + int sv = (rows * sizeof_member) % 16; + VecU8 res = VecU8_from_cstr("typedef struct {\n"); + for (int x = 0; x < cols; x++) { + VecU8_append_span(&res, cstr(SPACE4)); + string_append_xvecy(&res, xvec, rows); + VecU8_append_span(&res, cstr(" ")); + string_append_vec_field_name(&res, x); + VecU8_append_span(&res, cstr(";\n")); + if (sv) { + VecU8_append_vec(&res, VecU8_format(SPACE4 "char _padding_%d[%d];\n", x, 16 - sv)); + } + } + VecU8_append_span(&res, cstr("} ")); + string_append_xmatnm(&res, xmat, cols, rows); + VecU8_append_span(&res, cstr(";\n\n")); + return res; +} + +void string_append_mat_col_definition(VecU8* str, int ci) { + VecU8_append(str, '.'); + string_append_vec_field_name(str, ci); + VecU8_append_span(str, cstr(" = ")); +} + +void string_append_mat_el_access(VecU8* str, int x, int y) { + VecU8_append(str, '.'); + string_append_vec_field_name(str, x); + VecU8_append(str, '.'); + string_append_vec_field_name(str, y); +} + +NODISCARD VecU8 generate_xmatnm_method_new(ConstSpanU8 xmat, ConstSpanU8 xvec, ConstSpanU8 member, int cols, int rows) { + VecU8 res = VecU8_new(); + string_append_xmatnm(&res, xmat, cols, rows); + VecU8_append(&res, ' '); + string_append_xmatnm(&res, xmat, cols, rows); + VecU8_append_span(&res, cstr("_new(")); + for (int y = 0; y < rows; y++) { + for (int x = 0; x < cols; x++) { + if (x > 0 || y > 0) + VecU8_append_span(&res, cstr(", ")); + VecU8_append_span(&res, member); + VecU8_append(&res, ' '); + string_append_vec_field_name(&res, x); + string_append_vec_field_name(&res, y); + } + } + VecU8_append_span(&res, cstr(") {\n" SPACE4 "return (")); + string_append_xmatnm(&res, xmat, cols, rows); + VecU8_append_span(&res, cstr("){ ")); + for (int x = 0; x < cols; x++) { + if (x) + VecU8_append_span(&res, cstr(", ")); + string_append_mat_col_definition(&res, x); + VecU8_append_span(&res, cstr("{ ")); + for (int y = 0; y < rows; y++) { + if (y) + VecU8_append_span(&res, cstr(", ")); + string_append_vec_field_name(&res, x); + string_append_vec_field_name(&res, y); + } + VecU8_append_span(&res, cstr(" }")); + } + VecU8_append_span(&res, cstr(" };\n}\n\n")); + return res; +} + +NODISCARD VecU8 generate_square_xmatnn_E_definition(ConstSpanU8 xmat, int n) { + VecU8 res = VecU8_from_cstr("const "); + string_append_xmatnm(&res, xmat, n, n); + VecU8_append(&res, ' '); + string_append_xmatnm(&res, xmat, n, n); + VecU8_append_span(&res, cstr("_E = { ")); + for (int x = 0; x < n; x++) { + if (x) + VecU8_append_span(&res, cstr(", ")); + string_append_mat_col_definition(&res, x); + VecU8_append_span(&res, cstr("{ ")); + for (int y = 0; y < n; y++) { + if (y) + VecU8_append_span(&res, cstr(", ")); + VecU8_append(&res, '0' + (x == y)); + } + VecU8_append_span(&res, cstr(" }")); + } + VecU8_append_span(&res, cstr(" };\n\n")); + return res; +} + +NODISCARD VecU8 generate_xmatnm_method_add_xmatnm(ConstSpanU8 xmat, ConstSpanU8 xvec, ConstSpanU8 member, int cols, int rows) { + VecU8 res = VecU8_new(); + string_append_xmatnm(&res, xmat, cols, rows); + VecU8_append(&res, ' '); + string_append_xmatnm(&res, xmat, cols, rows); + VecU8_append_span(&res, cstr("_add_")); + string_append_xmatnm(&res, xmat, cols, rows); + VecU8_append_span(&res, cstr("(")); + string_append_xmatnm(&res, xmat, cols, rows); + VecU8_append_span(&res, cstr(" A, ")); + string_append_xmatnm(&res, xmat, cols, rows); + VecU8_append_span(&res, cstr(" B) {\n" SPACE4 "return (")); + string_append_xmatnm(&res, xmat, cols, rows); + VecU8_append_span(&res, cstr("){ ")); + for (int x = 0; x < cols; x++) { + if (x) + VecU8_append_span(&res, cstr(", ")); + string_append_mat_col_definition(&res, x); + string_append_xvecy(&res, xvec, rows); + VecU8_append_span(&res, cstr("_add_")); + string_append_xvecy(&res, xvec, rows); + VecU8_append_span(&res, cstr("(A.")); + string_append_vec_field_name(&res, x); + VecU8_append_span(&res, cstr(", B.")); + string_append_vec_field_name(&res, x); + VecU8_append_span(&res, cstr(")")); + } + VecU8_append_span(&res, cstr(" };\n}\n\n")); + return res; +} + +NODISCARD VecU8 generate_xmatnm_method_minus_xmatnm(ConstSpanU8 xmat, ConstSpanU8 xvec, ConstSpanU8 member, int cols, int rows) { + VecU8 res = VecU8_new(); + string_append_xmatnm(&res, xmat, cols, rows); + VecU8_append(&res, ' '); + string_append_xmatnm(&res, xmat, cols, rows); + VecU8_append_span(&res, cstr("_minus_")); + string_append_xmatnm(&res, xmat, cols, rows); + VecU8_append_span(&res, cstr("(")); + string_append_xmatnm(&res, xmat, cols, rows); + VecU8_append_span(&res, cstr(" A, ")); + string_append_xmatnm(&res, xmat, cols, rows); + VecU8_append_span(&res, cstr(" B) {\n" SPACE4 "return (")); + string_append_xmatnm(&res, xmat, cols, rows); + VecU8_append_span(&res, cstr("){ ")); + for (int x = 0; x < cols; x++) { + if (x) + VecU8_append_span(&res, cstr(", ")); + string_append_mat_col_definition(&res, x); + string_append_xvecy(&res, xvec, rows); + VecU8_append_span(&res, cstr("_minus_")); + string_append_xvecy(&res, xvec, rows); + VecU8_append_span(&res, cstr("(A.")); + string_append_vec_field_name(&res, x); + VecU8_append_span(&res, cstr(", B.")); + string_append_vec_field_name(&res, x); + VecU8_append_span(&res, cstr(")")); + } + VecU8_append_span(&res, cstr(" };\n}\n\n")); + return res; +} + +NODISCARD VecU8 generate_xmatnm_method_minus(ConstSpanU8 xmat, ConstSpanU8 xvec, ConstSpanU8 member, int cols, int rows) { + VecU8 res = VecU8_new(); + string_append_xmatnm(&res, xmat, cols, rows); + VecU8_append(&res, ' '); + string_append_xmatnm(&res, xmat, cols, rows); + VecU8_append_span(&res, cstr("_minus(")); + string_append_xmatnm(&res, xmat, cols, rows); + VecU8_append_span(&res, cstr(" A) {\n" SPACE4 "return (")); + string_append_xmatnm(&res, xmat, cols, rows); + VecU8_append_span(&res, cstr("){ ")); + for (int x = 0; x < cols; x++) { + if (x) + VecU8_append_span(&res, cstr(", ")); + string_append_mat_col_definition(&res, x); + string_append_xvecy(&res, xvec, rows); + VecU8_append_span(&res, cstr("_minus(A.")); + string_append_vec_field_name(&res, x); + VecU8_append_span(&res, cstr(")")); + } + VecU8_append_span(&res, cstr(" };\n}\n\n")); + return res; +} + +NODISCARD VecU8 generate_xmatnm_method_mul_scal(ConstSpanU8 xmat, ConstSpanU8 xvec, ConstSpanU8 member, int cols, int rows) { + VecU8 res = VecU8_new(); + string_append_xmatnm(&res, xmat, cols, rows); + VecU8_append(&res, ' '); + string_append_xmatnm(&res, xmat, cols, rows); + VecU8_append_span(&res, cstr("_mul_scal(")); + string_append_xmatnm(&res, xmat, cols, rows); + VecU8_append_span(&res, cstr(" A, ")); + VecU8_append_span(&res, member); + VecU8_append_span(&res, cstr(" B) {\n" SPACE4 "return (")); + string_append_xmatnm(&res, xmat, cols, rows); + VecU8_append_span(&res, cstr("){ ")); + for (int x = 0; x < cols; x++) { + if (x) + VecU8_append_span(&res, cstr(", ")); + string_append_mat_col_definition(&res, x); + string_append_xvecy(&res, xvec, rows); + VecU8_append_span(&res, cstr("_mul_scal(A.")); + string_append_vec_field_name(&res, x); + VecU8_append_span(&res, cstr(", B)")); + } + VecU8_append_span(&res, cstr(" };\n}\n\n")); + return res; +} + +NODISCARD VecU8 generate_xmatnm_method_div_by_scal(ConstSpanU8 xmat, ConstSpanU8 xvec, ConstSpanU8 member, int cols, int rows) { + VecU8 res = VecU8_new(); + string_append_xmatnm(&res, xmat, cols, rows); + VecU8_append(&res, ' '); + string_append_xmatnm(&res, xmat, cols, rows); + VecU8_append_span(&res, cstr("_div_by_scal(")); + string_append_xmatnm(&res, xmat, cols, rows); + VecU8_append_span(&res, cstr(" A, ")); + VecU8_append_span(&res, member); + VecU8_append_span(&res, cstr(" B) {\n" SPACE4 "return ")); + string_append_xmatnm(&res, xmat, cols, rows); + VecU8_append_span(&res, cstr("_mul_scal(A, 1/B);\n}\n\n")); + return res; +} + +NODISCARD VecU8 generate_xvecn_method_dot_xvecn(ConstSpanU8 xvec, ConstSpanU8 member, int n) { + VecU8 res = VecU8_from_span(member); + VecU8_append(&res, ' '); + string_append_xvecy(&res, xvec, n); + VecU8_append_span(&res, cstr("_dot_")); + string_append_xvecy(&res, xvec, n); + VecU8_append(&res, '('); + string_append_xvecy(&res, xvec, n); + VecU8_append_span(&res, cstr(" A, ")); + string_append_xvecy(&res, xvec, n); + VecU8_append_span(&res, cstr(" B) {\n" SPACE4 "return ")); + for (int i = 0; i < n; i++) { + if (i) + VecU8_append_span(&res, cstr(" + ")); + VecU8_append_span(&res, cstr("A.")); + string_append_vec_field_name(&res, i); + VecU8_append_span(&res, cstr(" * B.")); + string_append_vec_field_name(&res, i); + } + VecU8_append_span(&res, cstr(";\n}\n\n")); + return res; +} + +NODISCARD VecU8 generate_xmatnm_method_mul_xvecn(ConstSpanU8 xmat, ConstSpanU8 xvec, int n, int m) { + VecU8 res = VecU8_new(); + string_append_xvecy(&res, xvec, m); + VecU8_append(&res, ' '); + string_append_xmatnm(&res, xmat, n, m); + VecU8_append_span(&res, cstr("_mul_")); + string_append_xvecy(&res, xvec, n); + VecU8_append_span(&res, cstr("(")); + string_append_xmatnm(&res, xmat, n, m); + VecU8_append_span(&res, cstr(" A, ")); + string_append_xvecy(&res, xvec, n); + VecU8_append_span(&res, cstr(" B) {\n" SPACE4 "return (")); + string_append_xvecy(&res, xvec, m); + VecU8_append_span(&res, cstr("){")); + for (int ci = 0; ci < m; ci++) { + if (ci) + VecU8_append(&res, ','); + VecU8_append_span(&res, cstr("\n" SPACE8)); + for (int x = 0; x < n; x++) { + if (x) + VecU8_append_span(&res, cstr(" + ")); + VecU8_append_span(&res, cstr("A")); + string_append_mat_el_access(&res, x, ci); + VecU8_append_span(&res, cstr(" * B.")); + string_append_vec_field_name(&res, x); + } + } + VecU8_append_span(&res, cstr(" };\n}\n\n")); + return res; +} + +NODISCARD VecU8 generate_xmatnm_method_mul_xmatkn(ConstSpanU8 xmat, int n, int m, int k) { + VecU8 res = VecU8_new(); + string_append_xmatnm(&res, xmat, k, m); + VecU8_append(&res, ' '); + string_append_xmatnm(&res, xmat, n, m); + VecU8_append_span(&res, cstr("_mul_")); + string_append_xmatnm(&res, xmat, k, n); + VecU8_append_span(&res, cstr("(")); + string_append_xmatnm(&res, xmat, n, m); + VecU8_append_span(&res, cstr(" A, ")); + string_append_xmatnm(&res, xmat, k, n); + VecU8_append_span(&res, cstr(" B) {\n" SPACE4 "return (")); + string_append_xmatnm(&res, xmat, k, m); + VecU8_append_span(&res, cstr("){")); + for (int x = 0; x < k; x++) { + if (x) + VecU8_append_span(&res, cstr(",")); + VecU8_append_span(&res, cstr("\n" SPACE8)); + string_append_mat_col_definition(&res, x); + VecU8_append_span(&res, cstr("{ ")); + for (int y = 0; y < m; y++) { + if (y) + VecU8_append_span(&res, cstr(", ")); + for (int z = 0; z < n; z++) { + if (z) + VecU8_append_span(&res, cstr(" + ")); + VecU8_append_span(&res, cstr("A")); + string_append_mat_el_access(&res, z, y); + VecU8_append_span(&res, cstr(" * B")); + string_append_mat_el_access(&res, x, z); + } + } + VecU8_append_span(&res, cstr(" }")); + } + VecU8_append_span(&res, cstr(" };\n}\n\n")); + return res; +} + +VecU8 generate_xmatnm_method_transpose(ConstSpanU8 xmat, ConstSpanU8 xvec, ConstSpanU8 member, int n, int m) { + VecU8 res = VecU8_new(); + string_append_xmatnm(&res, xmat, m, n); + VecU8_append(&res, ' '); + string_append_xmatnm(&res, xmat, n, m); + VecU8_append_span(&res, cstr("_transpose(")); + string_append_xmatnm(&res, xmat, n, m); + VecU8_append_span(&res, cstr(" A) {\n" SPACE4 "return (")); + string_append_xmatnm(&res, xmat, m, n); + VecU8_append_span(&res, cstr("){ ")); + for (int bx = 0; bx < m; bx++) { + if (bx) + VecU8_append_span(&res, cstr(", ")); + string_append_mat_col_definition(&res, bx); + VecU8_append_span(&res, cstr("{ ")); + for (int by = 0; by < n; by++) { + if (by) + VecU8_append_span(&res, cstr(", ")); + VecU8_append_span(&res, cstr("A")); + string_append_mat_el_access(&res, by, bx); + } + VecU8_append_span(&res, cstr(" }")); + } + VecU8_append_span(&res, cstr(" };\n}\n\n")); + return res; +} + +NODISCARD VecU8 generate_xvec234_structs_and_methods(ConstSpanU8 xvec, ConstSpanU8 member) { + VecU8 res = VecU8_new(); + for (int cc = 2; cc <= 4; cc++) { + VecU8_append_vec(&res, generate_xvecy_struct_definition(xvec, member, cc)); + VecU8_append_vec(&res, generate_xvecy_method_add_xvecy(xvec, member, cc)); + VecU8_append_vec(&res, generate_xvecy_method_minus_xvecy(xvec, member, cc)); + VecU8_append_vec(&res, generate_xvecy_method_minus(xvec, member, cc)); + VecU8_append_vec(&res, generate_xvecy_method_mul_scal(xvec, member, cc)); + VecU8_append_vec(&res, generate_xvecy_method_div_by_scal(xvec, member, cc)); + } + return res; +} + +NODISCARD VecU8 generate_xmat234x234_structs_and_methods(ConstSpanU8 xmat, ConstSpanU8 xvec, ConstSpanU8 member, int sizeof_member) { + VecU8 res = VecU8_new(); + for (int cols = 2; cols <= 4; cols++) { + for (int rows = 2; rows <= 4; rows++) { + VecU8_append_vec(&res, generate_xmatnm_structure_definition(xmat, xvec, cols, rows, sizeof_member)); + } + } + for (int cols = 2; cols <= 4; cols++) { + for (int rows = 2; rows <= 4; rows++) { + VecU8_append_vec(&res, generate_xmatnm_method_new(xmat, xvec, member, cols, rows)); + VecU8_append_vec(&res, generate_xmatnm_method_add_xmatnm(xmat, xvec, member, cols, rows)); + VecU8_append_vec(&res, generate_xmatnm_method_minus_xmatnm(xmat, xvec, member, cols, rows)); + VecU8_append_vec(&res, generate_xmatnm_method_minus(xmat, xvec, member, cols, rows)); + VecU8_append_vec(&res, generate_xmatnm_method_mul_scal(xmat, xvec, member, cols, rows)); + VecU8_append_vec(&res, generate_xmatnm_method_div_by_scal(xmat, xvec, member, cols, rows)); + VecU8_append_vec(&res, generate_xmatnm_method_transpose(xmat, xvec, member, cols, rows)); + } + } + for (int n = 2; n <= 4; n++) { + VecU8_append_vec(&res, generate_square_xmatnn_E_definition(xmat, n)); + } + for (int n = 2; n <= 4; n++) { + for (int m = 2; m <= 4; m++) { + VecU8_append_vec(&res, generate_xmatnm_method_mul_xvecn(xmat, xvec, n, m)); + } + } + for (int n = 2; n <= 4; n++) { + for (int m = 2; m <= 4; m++) { + for (int k = 2; k <= 4; k++) { + VecU8_append_vec(&res, generate_xmatnm_method_mul_xmatkn(xmat, n, m, k)); + } + } + } + return res; +} + +void generate_geom_header() { + VecU8 res = begin_header(cstr("PROTOTYPE1_GEN_GEOM")); + VecU8_append_span(&res, cstr("#include \"../src/l1/core/int_primitives.h\"\n\n")); + VecU8_append_vec(&res, generate_xvec234_structs_and_methods(cstr("cvec"), cstr("U8"))); + VecU8_append_vec(&res, generate_xvec234_structs_and_methods(cstr("ivec"), cstr("S32"))); + + VecU8_append_vec(&res, generate_xvec234_structs_and_methods(cstr("vec"), cstr("float"))); + VecU8_append_vec(&res, generate_xvec234_structs_and_methods(cstr("dvec"), cstr("double"))); + VecU8_append_vec(&res, generate_xmat234x234_structs_and_methods(cstr("mat"), cstr("vec"), cstr("float"), sizeof(float))); + VecU8_append_vec(&res, generate_xmat234x234_structs_and_methods(cstr("dmat"), cstr("dvec"), cstr("double"), sizeof(double))); + finish_header(res, "geom.h"); +} + +VecU8 generate_type_triv_methods_and_vec(ConstSpanU8 member) { + VecU8 res = VecU8_from_cstr("#define "); + VecU8_append_span(&res, member); + VecU8_append_span(&res, cstr("_drop(x) {}\n#define ")); + VecU8_append_span(&res, member); + VecU8_append_span(&res, cstr("_clone(xp) (*(xp))\n\n")); + VecU8_append_span(&res, cstr("VecT_trivmove_struct_Definition(")); + VecU8_append_span(&res, member); + VecU8_append_span(&res, cstr(")\nVecT_trivmove_method_Definition(")); + VecU8_append_span(&res, member); + VecU8_append_span(&res, cstr(")\nVecT_primitive_zeroinit_method_Definition(")); + VecU8_append_span(&res, member); + VecU8_append_span(&res, cstr(")\n\n")); + return res; +} + +/* code generation function. We don't append vector data to vecu8, we append vector name to string in VecU8 */ +void VecU8_append_vecoft(VecU8* str, ConstSpanU8 t) { + VecU8_append_span(str, cstr("Vec")); + VecU8_append_span(str, t); +} + +void VecU8_append_resoftexdatat(VecU8* str, ConstSpanU8 texdatat) { + VecU8_append_span(str, cstr("Result")); + VecU8_append_span(str, texdatat); + VecU8_append_span(str, cstr("OrConstSpanU8")); +} + +/* Used to generate both _at() and _cat() methods */ +VecU8 generate_texture_data_method_at(ConstSpanU8 texdatat, ConstSpanU8 member, bool const_access) { + VecU8 res = VecU8_from_span(member); + VecU8_append_span(&res, cstr("* ")); + VecU8_append_span(&res, texdatat); + VecU8_append_span(&res, const_access ? cstr("_cat") : cstr("_at")); + VecU8_append_span(&res, cstr("(")); + VecU8_append_span(&res, texdatat); + VecU8_append_span(&res, cstr("* self, size_t x, size_t y) {\n" SPACE4 "assert(x < self->width);\n" + SPACE4 "return ")); + VecU8_append_vecoft(&res, member); + VecU8_append_span(&res, const_access ? cstr("_cat") : cstr("_at")); + VecU8_append_span(&res, cstr("(&self->pixels, x + y * self->width);\n}\n\n")); + return res; +} + +VecU8 generate_texture_data_struct_and_necc_methods(ConstSpanU8 texdatat, ConstSpanU8 member) { + VecU8 res = VecU8_from_cstr("typedef struct {\n" SPACE4); + VecU8_append_vecoft(&res, member); + VecU8_append_span(&res, cstr(" pixels;\n" SPACE4 "size_t width;\n} ")); + VecU8_append_span(&res, texdatat); + VecU8_append_span(&res, cstr(";\n\n")); + /* Method _new() */ + VecU8_append_span(&res, texdatat); + VecU8_append_span(&res, cstr(" ")); + VecU8_append_span(&res, texdatat); + VecU8_append_span(&res, cstr("_new(U32 width, U32 height) {\n" + SPACE4 "assert(!(SIZE_MAX / width / height < 100 || UINT32_MAX / width < 10 || UINT32_MAX / height < 10));\n" + SPACE4 "return (")); + VecU8_append_span(&res, texdatat); + VecU8_append_span(&res, cstr("){.pixels = ")); + VecU8_append_vecoft(&res, member); + VecU8_append_span(&res, cstr("_new_zeroinit((size_t)width * height), .width = width};\n}\n\n")); + /* Method _drop() */ + VecU8_append_span(&res, cstr("void ")); + VecU8_append_span(&res, texdatat); + VecU8_append_span(&res, cstr("_drop(")); + VecU8_append_span(&res, texdatat); + VecU8_append_span(&res, cstr(" self) {\n" SPACE4)); + VecU8_append_vecoft(&res, member); + VecU8_append_span(&res, cstr("_drop(self.pixels);\n}\n\n")); + /* Method _get_height() */ + VecU8_append_span(&res, cstr("size_t ")); + VecU8_append_span(&res, texdatat); + VecU8_append_span(&res, cstr("_get_height(const ")); + VecU8_append_span(&res, texdatat); + VecU8_append_span(&res, cstr("* self) {\n" SPACE4 "return self->pixels.len / self->width;\n}\n\n")); + /* Methods _at and _cat */ + VecU8_append_vec(&res, generate_texture_data_method_at(texdatat, member, false)); + VecU8_append_span(&res, cstr("const ")); + VecU8_append_vec(&res, generate_texture_data_method_at(texdatat, member, true)); + /* Method _get_size_in_bytes */ + VecU8_append_span(&res, cstr("size_t ")); + VecU8_append_span(&res, texdatat); + VecU8_append_span(&res, cstr("_get_size_in_bytes(const ")); + VecU8_append_span(&res, texdatat); + VecU8_append_span(&res, cstr("* self) {\n" SPACE4 "return self->pixels.len * sizeof(")); + VecU8_append_span(&res, member); + VecU8_append_span(&res, cstr(");\n}\n\n")); + /* Method _to_bitmap_text() + * We use the assumption that bytes in type member are tightly packed */ + VecU8_append_span(&res, cstr("VecU8 ")); + VecU8_append_span(&res, texdatat); + VecU8_append_span(&res, cstr("_to_bitmap_text(const ")); + VecU8_append_span(&res, texdatat); + VecU8_append_span(&res, cstr("* self) {\n" + SPACE4 "assert(SIZE_MAX / self->pixels.len >= 100);\n" + SPACE4 "size_t len = self->pixels.len * sizeof(")); + VecU8_append_span(&res, member); + VecU8_append_span(&res, cstr(");\n" + SPACE4 "VecU8 res = VecU8_new_zeroinit(8 + len);\n" + SPACE4 "size_t width = self->width;\n" + SPACE4 "size_t height = self->pixels.len / self->width;\n" + SPACE4 "assert(UINT32_MAX / width >= 10 && UINT32_MAX / height >= 10);\n" + SPACE4 "for (int i = 0; i < 4; i++)\n" + SPACE4 SPACE4 "*VecU8_at(&res, 0 + i) = (width >> (8 * i)) & 0xff;\n" + SPACE4 "for (int i = 0; i < 4; i++)\n" + SPACE4 SPACE4 "*VecU8_at(&res, 4 + i) = (height >> (8 * i)) & 0xff;\n" + SPACE4 "memcpy(res.buf + 8, self->pixels.buf, len);\n" + SPACE4 "return res;\n" + "}\n\n")); + /* Method _write_to_file + * Aborts on failure */ + VecU8_append_span(&res, cstr("void ")); + VecU8_append_span(&res, texdatat); + VecU8_append_span(&res, cstr("_write_to_file(const ")); + VecU8_append_span(&res, texdatat); + VecU8_append_span(&res, cstr("* self, const char* path) {\n" SPACE4 "VecU8 data = ")); + VecU8_append_span(&res, texdatat); + VecU8_append_span(&res, cstr("_to_bitmap_text(self);\n" + SPACE4 "write_whole_file_or_abort(path, VecU8_to_ConstSpanU8(&data));\n" + SPACE4 "VecU8_drop(data);\n" + "}\n\n")); + /* Result stucture */ + VecU8_append_span(&res, cstr("typedef struct {\n" SPACE4 "Result_variant variant;\n" SPACE4 "union {\n" SPACE8 )); + VecU8_append_span(&res, texdatat); + VecU8_append_span(&res, cstr(" ok;\n" SPACE4 SPACE4 "ConstSpanU8 err;\n" SPACE4 "};\n} ")); + VecU8_append_resoftexdatat(&res, texdatat); + VecU8_append_span(&res, cstr(";\n\n")); + /* Method _from_bitmap_text() + * We assume that bytes are tightly packed in member type + */ + VecU8_append_resoftexdatat(&res, texdatat); + VecU8_append(&res, ' '); + VecU8_append_span(&res, texdatat); + VecU8_append_span(&res, cstr("_from_bitmap_text(ConstSpanU8 text) {\n" + SPACE4 "if (text.len < 8)\n" + SPACE4 SPACE4 "return (")); + VecU8_append_resoftexdatat(&res, texdatat); + VecU8_append_span(&res, cstr("){.variant = Result_Err, " + ".err = cstr(\"No header *crying emoji*\")};\n" + SPACE4 "size_t width = 0, height = 0;\n" + SPACE4 "for (int i = 0; i < 4; i++)\n" + SPACE4 SPACE4 "width |= (((size_t)*ConstSpanU8_at(text, 0 + i)) << (8 * i));\n" + SPACE4 "for (int i = 0; i < 4; i++)\n" + SPACE4 SPACE4 "height |= (((size_t)*ConstSpanU8_at(text, 4 + i)) << (8 * i));\n" + SPACE4 "if (SIZE_MAX / width / height < 100 || UINT32_MAX / width < 10 || UINT32_MAX / height < 10)\n" + SPACE4 SPACE4 "return (")); + VecU8_append_resoftexdatat(&res, texdatat); + VecU8_append_span(&res, cstr("){.variant = Result_Err, " + ".err = cstr(\"Image is too big\")};\n" + SPACE4 "size_t len = width * height * sizeof(")); + VecU8_append_span(&res, member); + VecU8_append_span(&res, cstr(");\n" + SPACE4 "if (text.len < 8 + len)\n" + SPACE4 SPACE4 "return (")); + VecU8_append_resoftexdatat(&res, texdatat); + VecU8_append_span(&res, cstr("){.variant = Result_Err, " + ".err = cstr(\"Texture size and file size mismatch\")};\n" SPACE4)); + VecU8_append_span(&res, texdatat); + VecU8_append_span(&res, cstr(" res = ")); + VecU8_append_span(&res, texdatat); + VecU8_append_span(&res, cstr("_new(width, height);\n" + SPACE4 "memcpy(res.pixels.buf, text.data + 8, len);\n" + SPACE4 "return (")); + VecU8_append_resoftexdatat(&res, texdatat); + VecU8_append_span(&res, cstr("){.variant = Result_Ok, .ok = res};\n}\n\n")); + /* Method _read_from_file */ + VecU8_append_span(&res, texdatat); + VecU8_append(&res, ' '); + VecU8_append_span(&res, texdatat); + VecU8_append_span(&res, cstr("_read_from_file(const char* path) {\n" + SPACE4 "VecU8 data = read_whole_file_or_abort(path);\n" SPACE4)); + VecU8_append_resoftexdatat(&res, texdatat); + VecU8_append_span(&res, cstr(" res = ")); + VecU8_append_span(&res, texdatat); + VecU8_append_span(&res, cstr("_from_bitmap_text(VecU8_to_ConstSpanU8(&data));\n" + SPACE4 "if (res.variant != Result_Ok) {\n" + SPACE8 "fprintf(stderr, \"Tried loading bitmap texture from file, but encountered decoding error: \");\n" + SPACE8 "ConstSpanU8_fprint(res.err, stderr);\n" + SPACE8 "abortf(\"\\n\");\n" SPACE4 "}\n" SPACE4 "VecU8_drop(data);\n" SPACE4 "return res.ok;\n}\n\n")); + return res; +} + +void generate_pixel_masses_header() { + VecU8 res = begin_header(cstr("PROTOTYPE1_GEN_PIXEL_MASSES")); + VecU8_append_span(&res, cstr("#include \"geom.h\"\n\n")); + VecU8_append_span(&res, cstr("#include \"../src/l1/core/VecSpan_int_primitives.h\"\n\n")); + VecU8_append_span(&res, cstr("#include \"../src/l1/system/fileio.h\"\n\n")); + VecU8_append_vec(&res, generate_type_triv_methods_and_vec(cstr("cvec3"))); + VecU8_append_vec(&res, generate_type_triv_methods_and_vec(cstr("cvec4"))); + VecU8_append_vec(&res, generate_texture_data_struct_and_necc_methods(cstr("TextureDataR8"), cstr("U8"))); + VecU8_append_vec(&res, generate_texture_data_struct_and_necc_methods(cstr("TextureDataR8G8B8"), cstr("cvec3"))); + VecU8_append_vec(&res, generate_texture_data_struct_and_necc_methods(cstr("TextureDataR8G8B8A8"), cstr("cvec4"))); + finish_header(res, "pixel_masses.h"); +} + +#endif diff --git a/src/l1/main.c b/src/l1/main.c index e7e633c..ea6e3a5 100644 --- a/src/l1/main.c +++ b/src/l1/main.c @@ -1,573 +1,6 @@ -#include - -#include "system/fileio.h" -#include "core/VecU8_format.h" - -NODISCARD VecU8 begin_header(ConstSpanU8 guard) { - VecU8 res = VecU8_new(); - VecU8_append_span(&res, cstr("#ifndef ")); - VecU8_append_span(&res, guard); - VecU8_append_span(&res, cstr("\n#define ")); - VecU8_append_span(&res, guard); - VecU8_append_span(&res, cstr("\n/* Automatically generated file. Do not edit it. */\n\n" - "#include \"../src/l1/core/int_primitives.h\"\n\n")); - return res; -} - -void finish_header(VecU8 text_before_endif) { - VecU8_append_span(&text_before_endif, cstr("#endif\n")); - write_whole_file_or_abort("geom.h", VecU8_to_ConstSpanU8(&text_before_endif)); - VecU8_drop(text_before_endif); -} - -#define SPACE4 " " - -void string_append_vec_field_name(VecU8* str, int ci) { - assert(0 <= ci && ci < 4); - - VecU8_append(str, ci == 3 ? 'w' : 'x' + ci); -} - -void string_append_xvecy(VecU8* str, ConstSpanU8 xvec, int cc) { - VecU8_append_span(str, xvec); - VecU8_append(str, '0' + cc); -} - -NODISCARD VecU8 generate_xvecy_struct_definition(ConstSpanU8 xvec, ConstSpanU8 member, int cc) { - assert(2 <= cc && cc <= 4); - VecU8 res = VecU8_new(); - VecU8_append_span(&res, cstr("typedef struct {\n")); - - for (int ci = 0; ci < cc; ci++) { - VecU8_append_span(&res, cstr(SPACE4)); - VecU8_append_span(&res, member); - VecU8_append(&res, ' '); - string_append_vec_field_name(&res, ci); - VecU8_append_span(&res, cstr(";\n")); - } - - VecU8_append_span(&res, cstr("} ")); - string_append_xvecy(&res, xvec, cc); - VecU8_append_span(&res, cstr(";\n\n")); - return res; -} - -NODISCARD VecU8 generate_xvecy_method_add_xvecy(ConstSpanU8 xvec, ConstSpanU8 member, int cc) { - VecU8 res = VecU8_new(); - string_append_xvecy(&res, xvec, cc); - VecU8_append_span(&res, cstr(" ")); - string_append_xvecy(&res, xvec, cc); - VecU8_append_span(&res, cstr("_add_")); - string_append_xvecy(&res, xvec, cc); - VecU8_append_span(&res, cstr("(")); - string_append_xvecy(&res, xvec, cc); - VecU8_append_span(&res, cstr(" A, ")); - string_append_xvecy(&res, xvec, cc); - VecU8_append_span(&res, cstr(" B) {\n" SPACE4 "return (")); - string_append_xvecy(&res, xvec, cc); - VecU8_append_span(&res, cstr("){ ")); - for (int ci = 0; ci < cc; ci++) { - if (ci) - VecU8_append_span(&res, cstr(", ")); - VecU8_append_span(&res, cstr("A.")); - string_append_vec_field_name(&res, ci); - VecU8_append_span(&res, cstr(" + B.")); - string_append_vec_field_name(&res, ci); - } - VecU8_append_span(&res, cstr(" };\n}\n\n")); - return res; -} - -NODISCARD VecU8 generate_xvecy_method_minus_xvecy(ConstSpanU8 xvec, ConstSpanU8 member, int cc) { - VecU8 res = VecU8_new(); - string_append_xvecy(&res, xvec, cc); - VecU8_append_span(&res, cstr(" ")); - string_append_xvecy(&res, xvec, cc); - VecU8_append_span(&res, cstr("_minus_")); - string_append_xvecy(&res, xvec, cc); - VecU8_append_span(&res, cstr("(")); - string_append_xvecy(&res, xvec, cc); - VecU8_append_span(&res, cstr(" A, ")); - string_append_xvecy(&res, xvec, cc); - VecU8_append_span(&res, cstr(" B) {\n" SPACE4 "return (")); - string_append_xvecy(&res, xvec, cc); - VecU8_append_span(&res, cstr("){ ")); - for (int ci = 0; ci < cc; ci++) { - if (ci) - VecU8_append_span(&res, cstr(", ")); - VecU8_append_span(&res, cstr("A.")); - string_append_vec_field_name(&res, ci); - VecU8_append_span(&res, cstr(" - B.")); - string_append_vec_field_name(&res, ci); - } - VecU8_append_span(&res, cstr(" };\n}\n\n")); - return res; -} - - -NODISCARD VecU8 generate_xvecy_method_minus(ConstSpanU8 xvec, ConstSpanU8 member, int cc) { - VecU8 res = VecU8_new(); - string_append_xvecy(&res, xvec, cc); - VecU8_append_span(&res, cstr(" ")); - string_append_xvecy(&res, xvec, cc); - VecU8_append_span(&res, cstr("_minus(")); - string_append_xvecy(&res, xvec, cc); - VecU8_append_span(&res, cstr(" A) {\n" SPACE4 "return(")); - string_append_xvecy(&res, xvec, cc); - VecU8_append_span(&res, cstr("){ ")); - for (int ci = 0; ci < cc; ci++) { - if (ci) - VecU8_append_span(&res, cstr(", ")); - VecU8_append_span(&res, cstr("-A.")); - string_append_vec_field_name(&res, ci); - } - VecU8_append_span(&res, cstr(" };\n}\n\n")); - return res; -} - -NODISCARD VecU8 generate_xvecy_method_mul_scal(ConstSpanU8 xvec, ConstSpanU8 member, int cc) { - VecU8 res = VecU8_new(); - string_append_xvecy(&res, xvec, cc); - VecU8_append_span(&res, cstr(" ")); - string_append_xvecy(&res, xvec, cc); - VecU8_append_span(&res, cstr("_mul_scal(")); - string_append_xvecy(&res, xvec, cc); - VecU8_append_span(&res, cstr(" A, ")); - VecU8_append_span(&res, member); - VecU8_append_span(&res, cstr(" B) {\n" SPACE4 "return (")); - string_append_xvecy(&res, xvec, cc); - VecU8_append_span(&res, cstr("){ ")); - for (int ci = 0; ci < cc; ci++) { - if (ci) - VecU8_append_span(&res, cstr(", ")); - VecU8_append_span(&res, cstr("A.")); - string_append_vec_field_name(&res, ci); - VecU8_append_span(&res, cstr(" * B")); - } - VecU8_append_span(&res, cstr(" };\n}\n\n")); - return res; -} - -NODISCARD VecU8 generate_xvecy_method_div_by_scal(ConstSpanU8 xvec, ConstSpanU8 member, int cc) { - VecU8 res = VecU8_new(); - string_append_xvecy(&res, xvec, cc); - VecU8_append_span(&res, cstr(" ")); - string_append_xvecy(&res, xvec, cc); - VecU8_append_span(&res, cstr("_div_by_scal(")); - string_append_xvecy(&res, xvec, cc); - VecU8_append_span(&res, cstr(" A, ")); - VecU8_append_span(&res, member); - VecU8_append_span(&res, cstr(" B){\n" SPACE4 "return ")); - string_append_xvecy(&res, xvec, cc); - VecU8_append_span(&res, cstr("_mul_scal(A, 1/B);\n}\n\n")); - return res; -} - -void string_append_xmatnm(VecU8* str, ConstSpanU8 xmat, int cols, int rows) { - VecU8_append_span(str, xmat); - VecU8_append(str, '0' + cols); - if (rows != cols) { - VecU8_append(str, 'x'); - VecU8_append(str, '0' + rows); - } -} - -/* With columns padded to 16 bytes (for std140, std140 is our everything) */ -NODISCARD VecU8 generate_xmatnm_structure_definition(ConstSpanU8 xmat, ConstSpanU8 xvec, int cols, int rows, int sizeof_member) { - int sv = (rows * sizeof_member) % 16; - VecU8 res = VecU8_from_cstr("typedef struct {\n"); - for (int x = 0; x < cols; x++) { - VecU8_append_span(&res, cstr(SPACE4)); - string_append_xvecy(&res, xvec, rows); - VecU8_append_span(&res, cstr(" ")); - string_append_vec_field_name(&res, x); - VecU8_append_span(&res, cstr(";\n")); - if (sv) { - VecU8_append_vec(&res, VecU8_format(SPACE4 "char _padding_%d[%d];\n", x, 16 - sv)); - } - } - VecU8_append_span(&res, cstr("} ")); - string_append_xmatnm(&res, xmat, cols, rows); - VecU8_append_span(&res, cstr(";\n\n")); - return res; -} - -void string_append_mat_col_definition(VecU8* str, int ci) { - VecU8_append(str, '.'); - string_append_vec_field_name(str, ci); - VecU8_append_span(str, cstr(" = ")); -} - -void string_append_mat_el_access(VecU8* str, int x, int y) { - VecU8_append(str, '.'); - string_append_vec_field_name(str, x); - VecU8_append(str, '.'); - string_append_vec_field_name(str, y); -} - -NODISCARD VecU8 generate_xmatnm_method_new(ConstSpanU8 xmat, ConstSpanU8 xvec, ConstSpanU8 member, int cols, int rows) { - VecU8 res = VecU8_new(); - string_append_xmatnm(&res, xmat, cols, rows); - VecU8_append(&res, ' '); - string_append_xmatnm(&res, xmat, cols, rows); - VecU8_append_span(&res, cstr("_new(")); - for (int y = 0; y < rows; y++) { - for (int x = 0; x < cols; x++) { - if (x > 0 || y > 0) - VecU8_append_span(&res, cstr(", ")); - VecU8_append_span(&res, member); - VecU8_append(&res, ' '); - string_append_vec_field_name(&res, x); - string_append_vec_field_name(&res, y); - } - } - VecU8_append_span(&res, cstr(") {\n" SPACE4 "return (")); - string_append_xmatnm(&res, xmat, cols, rows); - VecU8_append_span(&res, cstr("){ ")); - for (int x = 0; x < cols; x++) { - if (x) - VecU8_append_span(&res, cstr(", ")); - string_append_mat_col_definition(&res, x); - VecU8_append_span(&res, cstr("{ ")); - for (int y = 0; y < rows; y++) { - if (y) - VecU8_append_span(&res, cstr(", ")); - string_append_vec_field_name(&res, x); - string_append_vec_field_name(&res, y); - } - VecU8_append_span(&res, cstr(" }")); - } - VecU8_append_span(&res, cstr(" };\n}\n\n")); - return res; -} - -NODISCARD VecU8 generate_square_xmatnn_E_definition(ConstSpanU8 xmat, int n) { - VecU8 res = VecU8_from_cstr("const "); - string_append_xmatnm(&res, xmat, n, n); - VecU8_append(&res, ' '); - string_append_xmatnm(&res, xmat, n, n); - VecU8_append_span(&res, cstr("_E = { ")); - for (int x = 0; x < n; x++) { - if (x) - VecU8_append_span(&res, cstr(", ")); - string_append_mat_col_definition(&res, x); - VecU8_append_span(&res, cstr("{ ")); - for (int y = 0; y < n; y++) { - if (y) - VecU8_append_span(&res, cstr(", ")); - VecU8_append(&res, '0' + (x == y)); - } - VecU8_append_span(&res, cstr(" }")); - } - VecU8_append_span(&res, cstr(" };\n\n")); - return res; -} - -NODISCARD VecU8 generate_xmatnm_method_add_xmatnm(ConstSpanU8 xmat, ConstSpanU8 xvec, ConstSpanU8 member, int cols, int rows) { - VecU8 res = VecU8_new(); - string_append_xmatnm(&res, xmat, cols, rows); - VecU8_append(&res, ' '); - string_append_xmatnm(&res, xmat, cols, rows); - VecU8_append_span(&res, cstr("_add_")); - string_append_xmatnm(&res, xmat, cols, rows); - VecU8_append_span(&res, cstr("(")); - string_append_xmatnm(&res, xmat, cols, rows); - VecU8_append_span(&res, cstr(" A, ")); - string_append_xmatnm(&res, xmat, cols, rows); - VecU8_append_span(&res, cstr(" B) {\n" SPACE4 "return (")); - string_append_xmatnm(&res, xmat, cols, rows); - VecU8_append_span(&res, cstr("){ ")); - for (int x = 0; x < cols; x++) { - if (x) - VecU8_append_span(&res, cstr(", ")); - string_append_mat_col_definition(&res, x); - string_append_xvecy(&res, xvec, rows); - VecU8_append_span(&res, cstr("_add_")); - string_append_xvecy(&res, xvec, rows); - VecU8_append_span(&res, cstr("(A.")); - string_append_vec_field_name(&res, x); - VecU8_append_span(&res, cstr(", B.")); - string_append_vec_field_name(&res, x); - VecU8_append_span(&res, cstr(")")); - } - VecU8_append_span(&res, cstr(" };\n}\n\n")); - return res; -} - -NODISCARD VecU8 generate_xmatnm_method_minus_xmatnm(ConstSpanU8 xmat, ConstSpanU8 xvec, ConstSpanU8 member, int cols, int rows) { - VecU8 res = VecU8_new(); - string_append_xmatnm(&res, xmat, cols, rows); - VecU8_append(&res, ' '); - string_append_xmatnm(&res, xmat, cols, rows); - VecU8_append_span(&res, cstr("_minus_")); - string_append_xmatnm(&res, xmat, cols, rows); - VecU8_append_span(&res, cstr("(")); - string_append_xmatnm(&res, xmat, cols, rows); - VecU8_append_span(&res, cstr(" A, ")); - string_append_xmatnm(&res, xmat, cols, rows); - VecU8_append_span(&res, cstr(" B) {\n" SPACE4 "return (")); - string_append_xmatnm(&res, xmat, cols, rows); - VecU8_append_span(&res, cstr("){ ")); - for (int x = 0; x < cols; x++) { - if (x) - VecU8_append_span(&res, cstr(", ")); - string_append_mat_col_definition(&res, x); - string_append_xvecy(&res, xvec, rows); - VecU8_append_span(&res, cstr("_minus_")); - string_append_xvecy(&res, xvec, rows); - VecU8_append_span(&res, cstr("(A.")); - string_append_vec_field_name(&res, x); - VecU8_append_span(&res, cstr(", B.")); - string_append_vec_field_name(&res, x); - VecU8_append_span(&res, cstr(")")); - } - VecU8_append_span(&res, cstr(" };\n}\n\n")); - return res; -} - -NODISCARD VecU8 generate_xmatnm_method_minus(ConstSpanU8 xmat, ConstSpanU8 xvec, ConstSpanU8 member, int cols, int rows) { - VecU8 res = VecU8_new(); - string_append_xmatnm(&res, xmat, cols, rows); - VecU8_append(&res, ' '); - string_append_xmatnm(&res, xmat, cols, rows); - VecU8_append_span(&res, cstr("_minus(")); - string_append_xmatnm(&res, xmat, cols, rows); - VecU8_append_span(&res, cstr(" A) {\n" SPACE4 "return (")); - string_append_xmatnm(&res, xmat, cols, rows); - VecU8_append_span(&res, cstr("){ ")); - for (int x = 0; x < cols; x++) { - if (x) - VecU8_append_span(&res, cstr(", ")); - string_append_mat_col_definition(&res, x); - string_append_xvecy(&res, xvec, rows); - VecU8_append_span(&res, cstr("_minus(A.")); - string_append_vec_field_name(&res, x); - VecU8_append_span(&res, cstr(")")); - } - VecU8_append_span(&res, cstr(" };\n}\n\n")); - return res; -} - -NODISCARD VecU8 generate_xmatnm_method_mul_scal(ConstSpanU8 xmat, ConstSpanU8 xvec, ConstSpanU8 member, int cols, int rows) { - VecU8 res = VecU8_new(); - string_append_xmatnm(&res, xmat, cols, rows); - VecU8_append(&res, ' '); - string_append_xmatnm(&res, xmat, cols, rows); - VecU8_append_span(&res, cstr("_mul_scal(")); - string_append_xmatnm(&res, xmat, cols, rows); - VecU8_append_span(&res, cstr(" A, ")); - VecU8_append_span(&res, member); - VecU8_append_span(&res, cstr(" B) {\n" SPACE4 "return (")); - string_append_xmatnm(&res, xmat, cols, rows); - VecU8_append_span(&res, cstr("){ ")); - for (int x = 0; x < cols; x++) { - if (x) - VecU8_append_span(&res, cstr(", ")); - string_append_mat_col_definition(&res, x); - string_append_xvecy(&res, xvec, rows); - VecU8_append_span(&res, cstr("_mul_scal(A.")); - string_append_vec_field_name(&res, x); - VecU8_append_span(&res, cstr(", B)")); - } - VecU8_append_span(&res, cstr(" };\n}\n\n")); - return res; -} - -NODISCARD VecU8 generate_xmatnm_method_div_by_scal(ConstSpanU8 xmat, ConstSpanU8 xvec, ConstSpanU8 member, int cols, int rows) { - VecU8 res = VecU8_new(); - string_append_xmatnm(&res, xmat, cols, rows); - VecU8_append(&res, ' '); - string_append_xmatnm(&res, xmat, cols, rows); - VecU8_append_span(&res, cstr("_div_by_scal(")); - string_append_xmatnm(&res, xmat, cols, rows); - VecU8_append_span(&res, cstr(" A, ")); - VecU8_append_span(&res, member); - VecU8_append_span(&res, cstr(" B) {\n" SPACE4 "return ")); - string_append_xmatnm(&res, xmat, cols, rows); - VecU8_append_span(&res, cstr("_mul_scal(A, 1/B);\n}\n\n")); - return res; -} - -NODISCARD VecU8 generate_xvecn_method_dot_xvecn(ConstSpanU8 xvec, ConstSpanU8 member, int n) { - VecU8 res = VecU8_from_span(member); - VecU8_append(&res, ' '); - string_append_xvecy(&res, xvec, n); - VecU8_append_span(&res, cstr("_dot_")); - string_append_xvecy(&res, xvec, n); - VecU8_append(&res, '('); - string_append_xvecy(&res, xvec, n); - VecU8_append_span(&res, cstr(" A, ")); - string_append_xvecy(&res, xvec, n); - VecU8_append_span(&res, cstr(" B) {\n" SPACE4 "return ")); - for (int i = 0; i < n; i++) { - if (i) - VecU8_append_span(&res, cstr(" + ")); - VecU8_append_span(&res, cstr("A.")); - string_append_vec_field_name(&res, i); - VecU8_append_span(&res, cstr(" * B.")); - string_append_vec_field_name(&res, i); - } - VecU8_append_span(&res, cstr(";\n}\n\n")); - return res; -} - -NODISCARD VecU8 generate_xmatnm_method_mul_xvecn(ConstSpanU8 xmat, ConstSpanU8 xvec, int n, int m) { - VecU8 res = VecU8_new(); - string_append_xvecy(&res, xvec, m); - VecU8_append(&res, ' '); - string_append_xmatnm(&res, xmat, n, m); - VecU8_append_span(&res, cstr("_mul_")); - string_append_xvecy(&res, xvec, n); - VecU8_append_span(&res, cstr("(")); - string_append_xmatnm(&res, xmat, n, m); - VecU8_append_span(&res, cstr(" A, ")); - string_append_xvecy(&res, xvec, n); - VecU8_append_span(&res, cstr(" B) {\n" SPACE4 "return (")); - string_append_xvecy(&res, xvec, m); - VecU8_append_span(&res, cstr("){")); - for (int ci = 0; ci < m; ci++) { - if (ci) - VecU8_append(&res, ','); - VecU8_append_span(&res, cstr("\n" SPACE4 SPACE4)); - for (int x = 0; x < n; x++) { - if (x) - VecU8_append_span(&res, cstr(" + ")); - VecU8_append_span(&res, cstr("A")); - string_append_mat_el_access(&res, x, ci); - VecU8_append_span(&res, cstr(" * B.")); - string_append_vec_field_name(&res, x); - } - } - VecU8_append_span(&res, cstr(" };\n}\n\n")); - return res; -} - -NODISCARD VecU8 generate_xmatnm_method_mul_xmatkn(ConstSpanU8 xmat, int n, int m, int k) { - VecU8 res = VecU8_new(); - string_append_xmatnm(&res, xmat, k, m); - VecU8_append(&res, ' '); - string_append_xmatnm(&res, xmat, n, m); - VecU8_append_span(&res, cstr("_mul_")); - string_append_xmatnm(&res, xmat, k, n); - VecU8_append_span(&res, cstr("(")); - string_append_xmatnm(&res, xmat, n, m); - VecU8_append_span(&res, cstr(" A, ")); - string_append_xmatnm(&res, xmat, k, n); - VecU8_append_span(&res, cstr(" B) {\n" SPACE4 "return (")); - string_append_xmatnm(&res, xmat, k, m); - VecU8_append_span(&res, cstr("){")); - for (int x = 0; x < k; x++) { - if (x) - VecU8_append_span(&res, cstr(",")); - VecU8_append_span(&res, cstr("\n" SPACE4 SPACE4)); - string_append_mat_col_definition(&res, x); - VecU8_append_span(&res, cstr("{ ")); - for (int y = 0; y < m; y++) { - if (y) - VecU8_append_span(&res, cstr(", ")); - for (int z = 0; z < n; z++) { - if (z) - VecU8_append_span(&res, cstr(" + ")); - VecU8_append_span(&res, cstr("A")); - string_append_mat_el_access(&res, z, y); - VecU8_append_span(&res, cstr(" * B")); - string_append_mat_el_access(&res, x, z); - } - } - VecU8_append_span(&res, cstr(" }")); - } - VecU8_append_span(&res, cstr(" };\n}\n\n")); - return res; -} - -VecU8 generate_xmatnm_method_transpose(ConstSpanU8 xmat, ConstSpanU8 xvec, ConstSpanU8 member, int n, int m) { - VecU8 res = VecU8_new(); - string_append_xmatnm(&res, xmat, m, n); - VecU8_append(&res, ' '); - string_append_xmatnm(&res, xmat, n, m); - VecU8_append_span(&res, cstr("_transpose(")); - string_append_xmatnm(&res, xmat, n, m); - VecU8_append_span(&res, cstr(" A) {\n" SPACE4 "return (")); - string_append_xmatnm(&res, xmat, m, n); - VecU8_append_span(&res, cstr("){ ")); - for (int bx = 0; bx < m; bx++) { - if (bx) - VecU8_append_span(&res, cstr(", ")); - string_append_mat_col_definition(&res, bx); - VecU8_append_span(&res, cstr("{ ")); - for (int by = 0; by < n; by++) { - if (by) - VecU8_append_span(&res, cstr(", ")); - VecU8_append_span(&res, cstr("A")); - string_append_mat_el_access(&res, by, bx); - } - VecU8_append_span(&res, cstr(" }")); - } - VecU8_append_span(&res, cstr(" };\n}\n\n")); - return res; -} - -NODISCARD VecU8 generate_xvec234_structs_and_methods(ConstSpanU8 xvec, ConstSpanU8 member) { - VecU8 res = VecU8_new(); - for (int cc = 2; cc <= 4; cc++) { - VecU8_append_vec(&res, generate_xvecy_struct_definition(xvec, member, cc)); - VecU8_append_vec(&res, generate_xvecy_method_add_xvecy(xvec, member, cc)); - VecU8_append_vec(&res, generate_xvecy_method_minus_xvecy(xvec, member, cc)); - VecU8_append_vec(&res, generate_xvecy_method_minus(xvec, member, cc)); - VecU8_append_vec(&res, generate_xvecy_method_mul_scal(xvec, member, cc)); - VecU8_append_vec(&res, generate_xvecy_method_div_by_scal(xvec, member, cc)); - } - return res; -} - -NODISCARD VecU8 generate_xmat234x234_structs_and_methods(ConstSpanU8 xmat, ConstSpanU8 xvec, ConstSpanU8 member, int sizeof_member) { - VecU8 res = VecU8_new(); - for (int cols = 2; cols <= 4; cols++) { - for (int rows = 2; rows <= 4; rows++) { - VecU8_append_vec(&res, generate_xmatnm_structure_definition(xmat, xvec, cols, rows, sizeof_member)); - } - } - for (int cols = 2; cols <= 4; cols++) { - for (int rows = 2; rows <= 4; rows++) { - VecU8_append_vec(&res, generate_xmatnm_method_new(xmat, xvec, member, cols, rows)); - VecU8_append_vec(&res, generate_xmatnm_method_add_xmatnm(xmat, xvec, member, cols, rows)); - VecU8_append_vec(&res, generate_xmatnm_method_minus_xmatnm(xmat, xvec, member, cols, rows)); - VecU8_append_vec(&res, generate_xmatnm_method_minus(xmat, xvec, member, cols, rows)); - VecU8_append_vec(&res, generate_xmatnm_method_mul_scal(xmat, xvec, member, cols, rows)); - VecU8_append_vec(&res, generate_xmatnm_method_div_by_scal(xmat, xvec, member, cols, rows)); - VecU8_append_vec(&res, generate_xmatnm_method_transpose(xmat, xvec, member, cols, rows)); - } - } - for (int n = 2; n <= 4; n++) { - VecU8_append_vec(&res, generate_square_xmatnn_E_definition(xmat, n)); - } - for (int n = 2; n <= 4; n++) { - for (int m = 2; m <= 4; m++) { - VecU8_append_vec(&res, generate_xmatnm_method_mul_xvecn(xmat, xvec, n, m)); - } - } - for (int n = 2; n <= 4; n++) { - for (int m = 2; m <= 4; m++) { - for (int k = 2; k <= 4; k++) { - VecU8_append_vec(&res, generate_xmatnm_method_mul_xmatkn(xmat, n, m, k)); - } - } - } - return res; -} - -void generate_geometry_header() { - VecU8 res = begin_header(cstr("PROTOTYPE1_GEN_GEOM")); - VecU8_append_vec(&res, generate_xvec234_structs_and_methods(cstr("cvec"), cstr("U8"))); - VecU8_append_vec(&res, generate_xvec234_structs_and_methods(cstr("ivec"), cstr("S32"))); - - VecU8_append_vec(&res, generate_xvec234_structs_and_methods(cstr("vec"), cstr("float"))); - VecU8_append_vec(&res, generate_xvec234_structs_and_methods(cstr("dvec"), cstr("double"))); - VecU8_append_vec(&res, generate_xmat234x234_structs_and_methods(cstr("mat"), cstr("vec"), cstr("float"), sizeof(float))); - VecU8_append_vec(&res, generate_xmat234x234_structs_and_methods(cstr("dmat"), cstr("dvec"), cstr("double"), sizeof(double))); - finish_header(res); -} +#include "gen/geom_and_textures.h" int main() { - generate_geometry_header(); + generate_geom_header(); + generate_pixel_masses_header(); } \ No newline at end of file diff --git a/src/l2/margaret/stringop.h b/src/l2/core/stringop.h similarity index 95% rename from src/l2/margaret/stringop.h rename to src/l2/core/stringop.h index ec40af6..6f42ca9 100644 --- a/src/l2/margaret/stringop.h +++ b/src/l2/core/stringop.h @@ -3,8 +3,6 @@ #include "../../l1/core/VecSpan_int_primitives.h" -// todo: move this out of margaret (may still keep it in l2) - U8 U8_to_lowercase(U8 ch) { if ('A' <= ch && ch <= 'Z') return ch - 'A' + 'a'; diff --git a/src/l2/margaret/graphics_geom.h b/src/l2/margaret/graphics_geom.h index 82b174f..d4481c9 100644 --- a/src/l2/margaret/graphics_geom.h +++ b/src/l2/margaret/graphics_geom.h @@ -74,5 +74,4 @@ mat3 margaret_simple_camera_rot_m_basis_in_cols(float yaw, float pitch, float ro }; } - #endif diff --git a/src/l2/margaret/margaret.h b/src/l2/margaret/margaret.h index 1c71f50..a274929 100644 --- a/src/l2/margaret/margaret.h +++ b/src/l2/margaret/margaret.h @@ -8,11 +8,12 @@ #include #include #include -#include "stringop.h" +#include "../core/stringop.h" // #include #include // #include #include +#include "../../l1/system/fileio.h" typedef struct timespec margaret_ns_time; @@ -478,6 +479,59 @@ ResultMargaretChosenSwapchainDetailsOrConstSpanU8 margaret_choose_swapchain_deta }; } +SpanT_struct_Definition(VkFormat) +SpanT_method_Definition(VkFormat) + +OptionT_struct_Definition(VkFormat) +OptionT_method_Definition(VkFormat) + +OptionVkFormat margaret_find_supported_format_for_linear_tiling( + VkPhysicalDevice physical_device, ConstSpanVkFormat candidates, VkFormatFeatureFlags required_features + ) { + for (size_t i = 0; i < candidates.len; i++) { + VkFormat format = *ConstSpanVkFormat_at(candidates, i); + VkFormatProperties properties; + vkGetPhysicalDeviceFormatProperties(physical_device, format, &properties); + if ((properties.linearTilingFeatures & required_features) == required_features) + return Some_VkFormat(format); + } + return None_VkFormat(); +} + +OptionVkFormat margaret_find_supported_format_for_optimal_tiling( + VkPhysicalDevice physical_device, ConstSpanVkFormat candidates, VkFormatFeatureFlags required_features + ) { + for (size_t i = 0; i < candidates.len; i++) { + VkFormat format = *ConstSpanVkFormat_at(candidates, i); + VkFormatProperties properties; + vkGetPhysicalDeviceFormatProperties(physical_device, format, &properties); + if ((properties.optimalTilingFeatures & required_features) == required_features) + return Some_VkFormat(format); + } + return None_VkFormat(); +} + +OptionVkFormat margaret_find_supported_zbuffer_format(VkPhysicalDevice physical_device) { + VkFormat candidates[3] = { VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT }; + return margaret_find_supported_format_for_optimal_tiling(physical_device, + (ConstSpanVkFormat){.data = candidates, .len = ARRAY_SIZE(candidates)}, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT); +} + +OptionVkFormat margaret_find_supported_hdr_buffer_format(VkPhysicalDevice physical_device) { + // todo: use format without alpha component (even though they are probably not supported) + VkFormat candidates[] = { /*VK_FORMAT_R16G16B16_SFLOAT, VK_FORMAT_R32G32B32_SFLOAT,*/ + VK_FORMAT_R16G16B16A16_SFLOAT, VK_FORMAT_R32G32B32A32_SFLOAT }; + return margaret_find_supported_format_for_optimal_tiling(physical_device, + (ConstSpanVkFormat){.data = candidates, .len = ARRAY_SIZE(candidates)}, + VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT ); +} + +bool margaret_is_format_supported_for_textures(VkPhysicalDevice physical_device, VkFormat format) { + VkFormatProperties props; + vkGetPhysicalDeviceFormatProperties(physical_device, format, &props); + return props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT; +} + typedef struct { VkPhysicalDevice physical_device; S64 score; @@ -532,6 +586,14 @@ MargaretScoredPhysicalDevice margaret_score_physical_device( if (swapchain_details.variant == Result_Err) { return (MargaretScoredPhysicalDevice){dev, -1, cstr("Physical device lacks nice swapchain support")}; } + if (!margaret_is_format_supported_for_textures(dev, VK_FORMAT_R8_UNORM)) + return (MargaretScoredPhysicalDevice){dev, -1, cstr("R8_UNORM format can't be used for optimal tiling of textures")}; + if (!margaret_is_format_supported_for_textures(dev, VK_FORMAT_R8G8B8A8_SRGB)) + return (MargaretScoredPhysicalDevice){dev, -1, cstr("R8G8B8A8_SRGB format can't be used for optimal tiling of textures")}; + if (!margaret_is_format_supported_for_textures(dev, VK_FORMAT_R8G8B8A8_UNORM)) + return (MargaretScoredPhysicalDevice){dev, -1, cstr("R8G8B8A8_UNORM format can't be used for optimal tiling of textures")}; + if (!margaret_is_format_supported_for_textures(dev, VK_FORMAT_R16G16B16A16_SFLOAT)) + return (MargaretScoredPhysicalDevice){dev, -1, cstr("VK_FORMAT_R16G16B16A16_SFLOAT format can't be used for optimal tiling of textures")}; return (MargaretScoredPhysicalDevice){dev, score, ""}; } @@ -1271,44 +1333,6 @@ VkSampler margaret_create_sampler(VkPhysicalDevice physical_device, VkDevice dev return sampler; } -SpanT_struct_Definition(VkFormat) -SpanT_method_Definition(VkFormat) - -OptionT_struct_Definition(VkFormat) -OptionT_method_Definition(VkFormat) - -OptionVkFormat margaret_find_supported_format_for_linear_tiling( - VkPhysicalDevice physical_device, ConstSpanVkFormat candidates, VkFormatFeatureFlags required_features - ) { - for (size_t i = 0; i < candidates.len; i++) { - VkFormat format = *ConstSpanVkFormat_at(candidates, i); - VkFormatProperties properties; - vkGetPhysicalDeviceFormatProperties(physical_device, format, &properties); - if ((properties.linearTilingFeatures & required_features) == required_features) - return Some_VkFormat(format); - } - return None_VkFormat(); -} - -OptionVkFormat margaret_find_supported_format_for_optimal_tiling( - VkPhysicalDevice physical_device, ConstSpanVkFormat candidates, VkFormatFeatureFlags required_features - ) { - for (size_t i = 0; i < candidates.len; i++) { - VkFormat format = *ConstSpanVkFormat_at(candidates, i); - VkFormatProperties properties; - vkGetPhysicalDeviceFormatProperties(physical_device, format, &properties); - if ((properties.optimalTilingFeatures & required_features) == required_features) - return Some_VkFormat(format); - } - return None_VkFormat(); -} - -OptionVkFormat margaret_find_supported_zbuffer_format(VkPhysicalDevice physical_device) { - VkFormat candidates[3] = { VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT }; - return margaret_find_supported_format_for_optimal_tiling(physical_device, - (ConstSpanVkFormat){.data = candidates, .len = ARRAY_SIZE(candidates)}, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT); -} - #define VkDescriptorPoolSize_drop(v) {} #define VkDescriptorPoolSize_clone(p) (*(p)) diff --git a/src/l2/tests/r0.c b/src/l2/tests/r0.c index 7773066..dca27fc 100644 --- a/src/l2/tests/r0.c +++ b/src/l2/tests/r0.c @@ -3,9 +3,8 @@ #include #include "../../l1/system/fileio.h" #include -#include "r0_assets.h" -// Only for linux -#include +#include "r0_scene.h" +#include // Only for linux // todo: generate this class in l2 typedef struct { @@ -22,39 +21,57 @@ void destroy_graphics_pipeline_hands(VkDevice device, PipelineHands hands) { } // todo: generate this function in l2 -VkRenderPass create_render_pass_0(VkDevice logical_device, VkFormat image_format) { - // Color attachments array for our render pass - VkAttachmentDescription all_attachments[1] = { (VkAttachmentDescription){ - .format = image_format, - .samples = VK_SAMPLE_COUNT_1_BIT, - .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, - .storeOp = VK_ATTACHMENT_STORE_OP_STORE, - .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, - .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, - .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, - .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, - } }; +VkRenderPass create_render_pass_0(VkDevice logical_device, VkFormat colorbuffer_format, VkFormat zbuffer_format) { + VkAttachmentDescription all_attachments[2] = { + { + .format = colorbuffer_format, + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + }, + { + .format = zbuffer_format, + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + } + }; // For our one single render subpass - VkAttachmentReference color_attachment_refs[1] = { (VkAttachmentReference){ - .attachment = 0, - .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VkAttachmentReference color_attachments_refs[1] = { + { + .attachment = 0, + .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, } }; + VkAttachmentReference depth_attachment_ref = { + .attachment = 1, + .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + }; + VkSubpassDescription subpasses_descr[1] = { (VkSubpassDescription){ .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, - .colorAttachmentCount = ARRAY_SIZE(color_attachment_refs), - .pColorAttachments = color_attachment_refs, + .colorAttachmentCount = ARRAY_SIZE(color_attachments_refs), + .pColorAttachments = color_attachments_refs, + .pDepthStencilAttachment = &depth_attachment_ref, } }; VkSubpassDependency subpass_dependencies[1] = { // subpass_0_external (VkSubpassDependency) { .srcSubpass = VK_SUBPASS_EXTERNAL, - .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - .srcAccessMask = 0, .dstSubpass = 0, - .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, + .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, + .srcAccessMask = 0, .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, }}; @@ -136,8 +153,8 @@ PipelineHands create_graphics_pipeline_0( .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, .depthClampEnable = VK_FALSE, .polygonMode = VK_POLYGON_MODE_FILL, - // .cullMode = VK_CULL_MODE_BACK_BIT, - .cullMode = VK_CULL_MODE_NONE, + .cullMode = VK_CULL_MODE_BACK_BIT, + // .cullMode = VK_CULL_MODE_NONE, .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE, .depthBiasEnable = VK_FALSE, .depthBiasConstantFactor = 0.0f, @@ -156,6 +173,13 @@ PipelineHands create_graphics_pipeline_0( .alphaToOneEnable = VK_FALSE, }; + VkPipelineDepthStencilStateCreateInfo depth_stencil_state_crinfo = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, + .depthTestEnable = VK_TRUE, + .depthWriteEnable = VK_TRUE, + .depthCompareOp = VK_COMPARE_OP_LESS + }; + // For one framebuffer VkPipelineColorBlendAttachmentState color_blend_attachments[1] = {(VkPipelineColorBlendAttachmentState){ .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, @@ -186,7 +210,7 @@ PipelineHands create_graphics_pipeline_0( .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, // our shader variable is not an array of descriptors, so this stays 1 .descriptorCount = 1, - .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, }, { .binding = 1, @@ -204,12 +228,18 @@ PipelineHands create_graphics_pipeline_0( if (vkCreateDescriptorSetLayout(device, &descriptor_set_layout_crinfo, NULL, &my_descriptor_set_layout) != VK_SUCCESS) abortf("vkCreateDescriptorSetLayout"); + VkPushConstantRange pc_ranges[] = { + { + .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, + .offset = 0, .size = sizeof(mat4) + }}; + VkPipelineLayoutCreateInfo layout_crinfo = { .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, .setLayoutCount = 1, .pSetLayouts = &my_descriptor_set_layout, - .pushConstantRangeCount = 0, - .pPushConstantRanges = NULL, + .pushConstantRangeCount = ARRAY_SIZE(pc_ranges), + .pPushConstantRanges = pc_ranges, }; VkPipelineLayout pipeline_layout; if (vkCreatePipelineLayout(device, &layout_crinfo, NULL, &pipeline_layout) != VK_SUCCESS) @@ -223,7 +253,7 @@ PipelineHands create_graphics_pipeline_0( .pViewportState = &viewport_state, .pRasterizationState = &rasterizer_crinfo, .pMultisampleState = &multisampling_crinfo, - .pDepthStencilState = NULL, + .pDepthStencilState = &depth_stencil_state_crinfo, .pColorBlendState = &color_blending_crinfo, .pDynamicState = &dynamic_state_crinfo, .layout = pipeline_layout, @@ -442,15 +472,16 @@ PipelineHands create_graphics_pipeline_1( } -VkFramebuffer create_IT1_framebuffer(VkDevice device, VkImageView IT1_view, VkRenderPass render_pass_0, VkExtent2D MAX_WIN_SIZE) { - VkImageView attachments[1] = {IT1_view}; +VkFramebuffer create_IT1_framebuffer(VkDevice device, VkImageView IT1_view, VkImageView zbuffer_view, VkRenderPass render_pass_0, + U32 MAX_WIN_WIDTH, U32 MAX_WIN_HEIGHT) { + VkImageView attachments[2] = {IT1_view, zbuffer_view}; VkFramebufferCreateInfo framebuffer_crinfo = { .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, .renderPass = render_pass_0, .attachmentCount = ARRAY_SIZE(attachments), .pAttachments = attachments, - .width = MAX_WIN_SIZE.width, - .height = MAX_WIN_SIZE.height, + .width = MAX_WIN_WIDTH, + .height = MAX_WIN_HEIGHT, .layers = 1 }; VkFramebuffer framebuffer; @@ -463,7 +494,7 @@ void reset_and_record_command_buffer_0( VkCommandBuffer command_buffer, VkRenderPass render_pass_0, const PipelineHands* pipeline_and_layout, VkFramebuffer swapchain_image_framebuffer, VkExtent2D image_extent, - const Scene* scene, VkDescriptorSet my_descriptor_set + const Scene* scene, VkDescriptorSet my_descriptor_set, mat4 t_mat ) { if (vkResetCommandBuffer(command_buffer, 0) != VK_SUCCESS) abortf("vkResetCommandBuffer"); @@ -471,15 +502,15 @@ void reset_and_record_command_buffer_0( if (vkBeginCommandBuffer(command_buffer, &info_begin) != VK_SUCCESS) abortf("vkBeginCommandBuffer"); - VkClearValue clear_color[1] = {{.color = scene->color}}; + VkClearValue clear_values[2] = {{.color = scene->color}, {.depthStencil = {.depth = 1, .stencil = 0}}}; VkRenderPassBeginInfo renderpass_begin = { .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, .renderPass = render_pass_0, .framebuffer = swapchain_image_framebuffer, .renderArea.offset = (VkOffset2D){0, 0}, .renderArea.extent = image_extent, - .clearValueCount = ARRAY_SIZE(clear_color), - .pClearValues = clear_color, + .clearValueCount = ARRAY_SIZE(clear_values), + .pClearValues = clear_values, }; vkCmdBeginRenderPass(command_buffer, &renderpass_begin, VK_SUBPASS_CONTENTS_INLINE); @@ -502,16 +533,19 @@ void reset_and_record_command_buffer_0( }; vkCmdSetScissor(command_buffer, 0, 1, &scissor); for (size_t i = 0; i < scene->models.len; i++) { - const ModelOnScene* models = VecModelOnScene_cat(&scene->models, i); - VkBuffer attached_buffers[1] = { models->vbo }; + const UsedModelOnScene* model = VecUsedModelOnScene_cat(&scene->models, i); + VkBuffer attached_buffers[1] = { model->model.vbo }; // We use our whole buffer, no need for offset VkDeviceSize offsets_in_buffers[1] = {0}; vkCmdBindVertexBuffers(command_buffer, 0, 1, attached_buffers, offsets_in_buffers); - vkCmdBindIndexBuffer(command_buffer, models->ebo, 0, VK_INDEX_TYPE_UINT32); + vkCmdBindIndexBuffer(command_buffer, model->model.ebo, 0, VK_INDEX_TYPE_UINT32); + mat4 tt = mat4_mul_mat4(t_mat, model->model_t); + vkCmdPushConstants(command_buffer, pipeline_and_layout->pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, + 0, sizeof(mat4), &tt); vkCmdBindDescriptorSets( command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_and_layout->pipeline_layout, 0, 1, &my_descriptor_set, 0, NULL); - vkCmdDrawIndexed(command_buffer, models->indexes, 1, 0, 0, 0); + vkCmdDrawIndexed(command_buffer, model->model.indexes, 1, 0, 0, 0); } vkCmdEndRenderPass(command_buffer); @@ -661,9 +695,15 @@ int main() { MargaretChosenSwapchainDetails swapchain_details = swapchain_details_res.ok; // We hope that the image format won't be changed even when window gets resized - // VkSurfaceFormatKHR image_format = choose_surface_format_i_want(swap_chain_support).value(); + // (swapchain_details.surface_format.format) + OptionVkFormat zbuffer_format = margaret_find_supported_zbuffer_format(physical_device); + if (zbuffer_format.variant != Option_Some) + abortf("Could not find supported zbuffer format\n"); + OptionVkFormat IT1_format = margaret_find_supported_hdr_buffer_format(physical_device); + if (IT1_format.variant != Option_Some) + abortf("Could not find supported hdr buffer format\n"); - VkRenderPass render_pass_0 = create_render_pass_0(device, swapchain_details.surface_format.format); + VkRenderPass render_pass_0 = create_render_pass_0(device, IT1_format.some, zbuffer_format.some); PipelineHands pipeline_hands_0 = create_graphics_pipeline_0(device, render_pass_0, 0); VkRenderPass render_pass_1 = create_render_pass_1(device, swapchain_details.surface_format.format); @@ -674,14 +714,15 @@ int main() { // Filling scene info ModelTopology cylinder_1 = generate_one_fourth_of_a_cylinder(10, 2, 6); ModelTopology cylinder_2 = generate_one_fourth_of_a_cylinder(5, 5, 10); - TextureDataR8G8B8A8 wood_texture_data = generate_wood_texture(); + // TextureDataR8G8B8A8 wood_texture_data = generate_texture_for_one_fourth_of_a_cylinder(20, 10, 2, 6); + TextureDataR8G8B8A8 wood_texture_data = TextureDataR8G8B8A8_read_from_file("test_textures/log_10_2_6.r8g8b8a8"); // We have only one staging buffer in host memory (because we don't really need more) MargaretBufferInMemoryInfo host_mem_buffer = (MargaretBufferInMemoryInfo){ .sz = MAX_U64(ModelTopology_get_space_needed_for_staging_buffer(&cylinder_1), MAX_U64(ModelTopology_get_space_needed_for_staging_buffer(&cylinder_2), MAX_U64(sizeof(Pipeline0UBO), - MAX_U64(TextureDataR8G8B8A8_get_space_needed_for_staging_buffer(&wood_texture_data), 0)))) + MAX_U64(TextureDataR8G8B8A8_get_size_in_bytes(&wood_texture_data), 0)))) , .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT }; VkDeviceMemory host_mem = margaret_initialize_buffers_and_images(physical_device, device, (SpanMargaretBufferInMemoryInfo){.data = &host_mem_buffer, .len = 1}, (SpanMargaretImageInMemoryInfo){ 0 }, @@ -697,7 +738,8 @@ int main() { MargaretImageInMemoryInfo device_mem_images[] = { margaret_prep_image_mem_info_of_gpu_texture_rgba(wood_texture_data.width, TextureDataR8G8B8A8_get_height(&wood_texture_data)), - margaret_prep_image_mem_info_of_colorbuffer(MAX_WIN_WIDTH, MAX_WIN_HEIGHT, swapchain_details.surface_format.format), + margaret_prep_image_mem_info_of_colorbuffer(MAX_WIN_WIDTH, MAX_WIN_HEIGHT, IT1_format.some), + margaret_prep_image_mem_info_of_zbuffer(MAX_WIN_WIDTH, MAX_WIN_HEIGHT, zbuffer_format.some), }; VkDeviceMemory device_mem = margaret_initialize_buffers_and_images(physical_device, device, (SpanMargaretBufferInMemoryInfo){ .data = device_mem_buffers, .len = ARRAY_SIZE(device_mem_buffers)}, @@ -710,6 +752,7 @@ int main() { MargaretBufferInMemoryInfo device_ubo_my_buffer = device_mem_buffers[4]; MargaretImageInMemoryInfo device_wood_texture = device_mem_images[0]; MargaretImageInMemoryInfo device_IT1_image = device_mem_images[1]; + MargaretImageInMemoryInfo device_zbuffer_image = device_mem_images[2]; VkCommandPool command_pool = margaret_create_resettable_command_pool(device, queue_fam.for_graphics); VkCommandBuffer rendering_command_buffer_0 = margaret_allocate_command_buffer(device, command_pool); @@ -748,25 +791,27 @@ int main() { device_ebo_2_buffer.buffer, host_mem_buffer.buffer, size); } memcpy(host_mem_buffer_mem, wood_texture_data.pixels.buf, - TextureDataR8G8B8A8_get_space_needed_for_staging_buffer(&wood_texture_data)); + TextureDataR8G8B8A8_get_size_in_bytes(&wood_texture_data)); margaret_copy_buffer_to_texture_for_frag_shader_imm(device, command_pool, graphics_queue, &device_wood_texture, host_mem_buffer.buffer); // We sent everything we needed. but host_mem_buffer_mem may be used later // My wood texture needs VkImageView VkImageView wood_texture_view = margaret_create_view_for_image(device, &device_wood_texture, VK_IMAGE_ASPECT_COLOR_BIT); - + // My zbuffer also needs a view + VkImageView zbuffer_view = margaret_create_view_for_image(device, &device_zbuffer_image, VK_IMAGE_ASPECT_DEPTH_BIT); /* Here we create an image view into a temporary IT1 texture and a framebuffer for scene rendering */ VkImageView IT1_view = margaret_create_view_for_image(device, &device_IT1_image, VK_IMAGE_ASPECT_COLOR_BIT); - VkFramebuffer IT1_framebuffer = create_IT1_framebuffer(device, IT1_view, render_pass_0, - (VkExtent2D){.width = MAX_WIN_WIDTH, .height = MAX_WIN_HEIGHT}); + VkFramebuffer IT1_framebuffer = create_IT1_framebuffer(device, IT1_view, zbuffer_view, render_pass_0, + MAX_WIN_WIDTH, MAX_WIN_HEIGHT); - Scene scene; - scene.models = VecModelOnScene_new_zeroinit(2); - *VecModelOnScene_at(&scene.models, 0) = (ModelOnScene){ - .vbo = device_vbo_1_buffer.buffer, .ebo = device_ebo_1_buffer.buffer, .indexes = cylinder_1.indexes.len }; - // *VecModelOnScene_at(&scene.models, 1) = (ModelOnScene){ - // .vbo = device_vbo_2_buffer.buffer, .ebo = device_ebo_2_buffer.buffer, .indexes = cylinder_2.indexes.len }; + Scene scene = Scene_new(); + VecUsedModelOnScene_append(&scene.models, (UsedModelOnScene){.model = { + .vbo = device_vbo_1_buffer.buffer, .ebo = device_ebo_1_buffer.buffer, .indexes = cylinder_1.indexes.len + }, .model_t = margaret_translation_mat4((vec3){1, -1, 5}) }); + VecUsedModelOnScene_append(&scene.models, (UsedModelOnScene){.model = { + .vbo = device_vbo_2_buffer.buffer, .ebo = device_ebo_2_buffer.buffer, .indexes = cylinder_2.indexes.len + }, .model_t = margaret_translation_mat4((vec3){6, -3, 7}) }); // Sampler is global for a lot of my future textures VkSampler my_texture_sampler = margaret_create_sampler(physical_device, device); @@ -902,9 +947,16 @@ int main() { mat4 camera_rotation_matrix = margaret_mat3_to_mat4_transposed(my_cam_control_info.cam_basis); mat4 camera_translation_matrix = margaret_translation_mat4(vec3_minus(my_cam_control_info.pos)); mat4 t_mat = mat4_mul_mat4(projection_matrix, mat4_mul_mat4(camera_rotation_matrix, camera_translation_matrix)); - // mat4 t_mat = mat4_mul_mat4(camera_rotation_matrix, camera_translation_matrix); + { - *(Pipeline0UBO*)host_mem_buffer_mem = (Pipeline0UBO){.t = t_mat}; + assert(scene.spotlights.len < pipeline_0_ubo_spotlight_max_count); + assert(scene.point_lights.len < pipeline_0_ubo_point_light_max_count); + Pipeline0UBO* subo = (Pipeline0UBO*)host_mem_buffer_mem; + // todo: speed it up a little + subo->spotlight_count = (int)scene.spotlights.len; + memcpy(&subo->spotlight_arr, scene.spotlights.buf, scene.spotlights.len * sizeof(Pipeline0Spotlight)); + subo->point_light_count = (int)scene.point_lights.len; + memcpy(&subo->point_light_arr, scene.point_lights.buf, scene.point_lights.len * sizeof(Pipeline0PointLight)); VkCommandBuffer command_buffers[1] = { uniform_transfer_command_buffer }; VkSemaphore signaling_semaphores[1] = { swfb.in_frame_transfer_complete }; VkSubmitInfo ubo_copying_cmd_buffer_submit = { @@ -918,7 +970,7 @@ int main() { } reset_and_record_command_buffer_0(rendering_command_buffer_0, render_pass_0, &pipeline_hands_0, - IT1_framebuffer, swfb.extent, &scene, descriptor_set_for_pipeline_0); + IT1_framebuffer, swfb.extent, &scene, descriptor_set_for_pipeline_0, t_mat); reset_and_record_command_buffer_1(rendering_command_buffer_1, render_pass_1, &pipeline_hands_1, *VecVkFramebuffer_cat(&swfb.framebuffers, ij), diff --git a/src/l2/tests/r0_assets.h b/src/l2/tests/r0_assets.h index 825010c..59524f2 100644 --- a/src/l2/tests/r0_assets.h +++ b/src/l2/tests/r0_assets.h @@ -3,27 +3,16 @@ #include "../margaret/graphics_geom.h" #include "../../l1/core/util.h" +#include "../../l1/core/VecSpan_int_primitives.h" +#include "../../l1/system/fileio.h" #include +#include "../../../gen/pixel_masses.h" typedef struct { vec3 pos; vec2 tex; } Vertex; -/* No offset yet */ -typedef struct { - VkBuffer vbo; - VkBuffer ebo; - size_t indexes; -} ModelOnScene; - -#define ModelOnScene_drop(vp) {} -#define ModelOnScene_clone(vp) (*(vp)) - -VecT_trivmove_struct_Definition(ModelOnScene) -VecT_trivmove_method_Definition(ModelOnScene) -VecT_primitive_zeroinit_method_Definition(ModelOnScene) - #define Vertex_drop(vp) {} #define Vertex_clone(vp) (*(vp)) @@ -44,62 +33,6 @@ void ModelTopology_drop(ModelTopology self) { VecU32_drop(self.indexes); } -ModelTopology generate_one_fourth_of_a_cylinder(float w, float r, U32 k) { - assert(k >= 1); - const float a = M_PI_2f / (float)k; - const float l = 2 * r * sin(M_PI_4f / (float)k); - const vec2 v0tex = {r / (2 * r + w), 1 / (2 + k * l)}; - const vec2 v1tex = {(r + w) / (2 * r + w), 1 / (2 + k * l)}; - const vec2 v2tex = {r / (2 * r + w), 2 / (2 + k * l)}; - const vec2 v3tex = {(r + w) / (2 * r + w), 2 / (2 + k * l)}; - VecVertex vertices = VecVertex_new(); // todo: reserve 4 * k + 6 - VecVertex_append(&vertices, (Vertex){.pos = {0, 0, 0}, .tex = v0tex}); - VecVertex_append(&vertices, (Vertex){.pos = {w, 0, 0}, .tex = v1tex}); - VecVertex_append(&vertices, (Vertex){.pos = {0, r, 0}, .tex = v2tex}); - VecVertex_append(&vertices, (Vertex){.pos = {w, r, 0}, .tex = v3tex}); - VecVertex_append(&vertices, (Vertex){.pos = {0, 0, r}, .tex = {r / (2 * r + w), 0}}); - VecVertex_append(&vertices, (Vertex){.pos = {w, 0, r}, .tex = {(r + w) / (2 * r + w), 0}}); - for (U32 i = 1; i <= k; i++) { - VecVertex_append(&vertices, (Vertex){ - .pos = {0, cosf(a * i) * r, sinf(a * i) * r}, - .tex = vec2_add_vec2(v0tex, (vec2){r / (2 * r + w) * -sinf(a * i), 1 / (2 + k * l) * cos(a * i)}) - }); - } - for (U32 i = 1; i <= k; i++) { - VecVertex_append(&vertices, (Vertex){ - .pos = {w, cosf(a * i) * r, sinf(a * i) * r}, - .tex = vec2_add_vec2(v1tex, (vec2){r / (2 * r + w) * sinf(a * i), 1 / (2 + k * l) * cos(a * i)}) - }); - } - for (U32 i = 1; i <= k; i++) { - VecVertex_append(&vertices, (Vertex){ - .pos = {0, cosf(a * i) * r, sinf(a * i) * r}, - .tex = {v2tex.x, v2tex.y + i * l / (2 + k * l)} - }); - } - for (U32 i = 1; i <= k; i++) { - VecVertex_append(&vertices, (Vertex){ - .pos = {w, cosf(a * i) * r, sinf(a * i) * r}, - .tex = {v3tex.x, v3tex.y + i * l / (2 + k * l)} - }); - } - VecU32 indexes = VecU32_new(); // todo: reserve 3 * (2+2+2*k+2*k)< - { - U32 _span_0[] = { 5, 0, 1, 5, 4, 0, 1, 0, 3, 3, 0, 2 }; - VecU32_append_span(&indexes, (ConstSpanU32){.data = _span_0, .len = ARRAY_SIZE(_span_0)}); - } - for (U32 i = 1; i <= k; i++) { - U32 _span_1[] = { - 0, 5 + i, i > 1 ? 5 + i - 1 : 2, - 1, i > 1 ? 5 + k + i - 1 : 3, 5 + k + i, - i > 1 ? 5 + 2 * k + i - 1 : 2, 5 + 2 * k + i, i > 1 ? 5 + 3 * k + i - 1 : 3, - 5 + 3 * k + i, i > 1 ? 5 + 3 * k + i - 1 : 3, 5 + 2 * k + i - }; - VecU32_append_span(&indexes, (ConstSpanU32){.data = _span_1, .len = ARRAY_SIZE(_span_1)}); - } - return (ModelTopology){.vertices = vertices, .indexes = indexes}; -} - typedef struct { vec2 win_scale; } Pipeline1PushRangeVertex; @@ -112,37 +45,163 @@ typedef struct { } Pipeline1PushRangeFragment; typedef struct { - mat4 t; -} Pipeline0UBO; + vec3 pos; + char _padding_0[4]; + vec3 dir; + char _padding_1[4]; + vec3 color; + char _padding_2[4]; + float d; + char _padding_3[12]; +} Pipeline0Spotlight; -#define cvec4_drop(vp) {} -#define cvec4_clone(vp) (*(vp)) +#define Pipeline0Spotlight_drop(x) {} +#define Pipeline0Spotlight_clone(x) (*(x)) -VecT_trivmove_struct_Definition(cvec4) -VecT_trivmove_method_Definition(cvec4) -VecT_primitive_zeroinit_method_Definition(cvec4) +VecT_trivmove_struct_Definition(Pipeline0Spotlight) +VecT_trivmove_method_Definition(Pipeline0Spotlight) +VecT_primitive_zeroinit_method_Definition(Pipeline0Spotlight) typedef struct { - // I hate this so much uuuh. Capacity is not actually useful here... - Veccvec4 pixels; - size_t width; -} TextureDataR8G8B8A8; + vec3 pos; + char _padding_0[4]; + vec3 color; + char _padding_1[4]; +} Pipeline0PointLight; -TextureDataR8G8B8A8 TextureDataR8G8B8A8_new(size_t width, size_t height) { - return (TextureDataR8G8B8A8){.pixels = Veccvec4_new_zeroinit(width * height), .width = width}; +#define Pipeline0PointLight_drop(x) {} +#define Pipeline0PointLight_clone(x) (*(x)) + +VecT_trivmove_struct_Definition(Pipeline0PointLight) +VecT_trivmove_method_Definition(Pipeline0PointLight) +VecT_primitive_zeroinit_method_Definition(Pipeline0PointLight) + +const size_t pipeline_0_ubo_point_light_max_count = 20; +const size_t pipeline_0_ubo_spotlight_max_count = 20; + +typedef struct { + int spotlight_count; + int point_light_count; + char _padding_1[8]; + Pipeline0PointLight point_light_arr[20]; + Pipeline0Spotlight spotlight_arr[120]; +} Pipeline0UBO; + +size_t ModelTopology_get_space_needed_for_staging_buffer(const ModelTopology* self) { + return MAX_U64(self->vertices.len * sizeof(Vertex), self->indexes.len * sizeof(U32)); } -size_t TextureDataR8G8B8A8_get_height(const TextureDataR8G8B8A8* self) { - return self->pixels.len / self->width; +void TextureDataR8_pixel_maxing(TextureDataR8* self, S32 x, S32 y, U8 val) { + if (x < 0 || y < 0 || x >= self->width) + return; + size_t p = (size_t)x + (size_t)y * self->width; + if (p >= self->pixels.len) + return; + U8 b = *TextureDataR8_at(self, x, y); + *TextureDataR8_at(self, x, y) = MAX_U8(b, val); } -void TextureDataR8G8B8A8_drop(TextureDataR8G8B8A8 self) { - Veccvec4_drop(self.pixels); +U8 a_small_cute_gradient(float r_cut, float r_decay, float dist) { + return dist > r_cut ? 0 : (dist < r_decay) ? 255 : (U8)roundf( 255.f * (r_cut - dist) / (r_cut - r_decay) ); } -cvec4* TextureDataR8G8B8A8_at(TextureDataR8G8B8A8* self, size_t x, size_t y) { - assert(x < self->width); - return Veccvec4_at(&self->pixels, x + y * self->width); +void TextureDataR8_seg_vertical_strip_maxing(TextureDataR8* self, S32 x, float y_real, float vert_r_cut, float vert_r_decay) { + S32 y = (S32)roundf(y_real - 0.5f); + S32 k = (S32)ceilf(vert_r_cut); + for (S32 j = -k+y; j <= y+k; j++) { + float dist = fabsf(.5f + (float)j - y_real); + TextureDataR8_pixel_maxing(self, x, j, a_small_cute_gradient(vert_r_cut, vert_r_decay, dist)); + } +} + +void TextureDataR8_seg_horizontal_strip_maxing(TextureDataR8* self, float x_real, S32 y, float hor_r_cut, float hor_r_decay) { + S32 x = (S32)roundf(x_real - 0.5f); + S32 k = (S32)ceilf(hor_r_cut); + for (S32 i = -k+x; i < x+k; i++) { + float dist = fabsf(.5f + (float)i - x_real); + TextureDataR8_pixel_maxing(self, i, y, a_small_cute_gradient(hor_r_cut, hor_r_decay, dist)); + } +} + +// todo: complete rewrite +/* abs(y2 - y1) < abs(x2 - x1) x1 <= x2 */ +void TextureDataR8_draw_horizontal_inner_line_maxing(TextureDataR8* self, + float x1, float y1, float x2, float y2, float r_cut, float r_decay) { + S32 sx1 = (S32)roundf(x1 - 0.5f); + S32 sx2 = (S32)roundf(x2 - 0.5f); + if (sx1 + 1 >= sx2) + return; + float dx = x2 - x1; + float dy = y2 - y1; + float xdds = 1 / dx; + float inv_sin_a = sqrtf(dx*dx + dy*dy) / dx; + float vert_r_cut = r_cut * inv_sin_a; + float vert_r_decay = r_decay * inv_sin_a; + for (S32 x = sx1 + 1; x < sx2; x++) { + float real_x = (float)x + 0.5f; + float real_y = y1 + dy * (real_x - x1) * xdds; + TextureDataR8_seg_vertical_strip_maxing(self, x, real_y, vert_r_cut, vert_r_decay); + } +} + +/* abs(x2 - x1) < abs(y2 - y1) y1 <= y2 */ +void TextureDataR8_draw_vertical_inner_line_maxing(TextureDataR8* self, + float x1, float y1, float x2, float y2, float r_cut, float r_decay) { + S32 sy1 = (S32)roundf(y1 - 0.5f); + S32 sy2 = (S32)roundf(y2 - 0.5f); + if (sy1 + 1 >= sy2) + return; + float dx = x2 - x1; + float dy = y2 - y1; + float ydds = 1 / dy; + float inv_sin_a = sqrtf(dx*dx + dy*dy) / dy; + float hor_r_cut = r_cut * inv_sin_a; + float hor_r_decay = r_decay * inv_sin_a; + for (S32 y = sy1 + 1; y < sy2; y++) { + float real_y = (float)y + 0.5f; + float real_x = x1 + dx * (real_y - y1) * ydds; + TextureDataR8_seg_horizontal_strip_maxing(self, real_x, y, hor_r_cut, hor_r_decay); + } +} + +void TextureDataR8_draw_inner_line_maxing(TextureDataR8* self, + float x1, float y1, float x2, float y2, float r_cut, float r_decay) { + float dx = fabsf(x2 - x1); + float dy = fabsf(y2 - y1); + if (dx > dy) { + if (x1 < x2) { + TextureDataR8_draw_horizontal_inner_line_maxing(self, x1, y1, x2, y2, r_cut, r_decay); + } else { + TextureDataR8_draw_horizontal_inner_line_maxing(self, x2, y2, x1, y1, r_cut, r_decay); + } + } else { + if (y1 < y2) { + TextureDataR8_draw_vertical_inner_line_maxing(self, x1, y1, x2, y2, r_cut, r_decay); + } else { + TextureDataR8_draw_vertical_inner_line_maxing(self, x2, y2, x1, y1, r_cut, r_decay); + } + } +} + +void TextureDataR8_draw_spot_maxing(TextureDataR8* self, float x, float y, float r_cut, float r_decay) { + S32 sx = (S32)roundf(x - .5f); + S32 sy = (S32)roundf(y - .5f); + S32 k = (S32)ceilf(r_cut); + for (S32 i = sx-k; i <= sx+k; i++) { + for (S32 j = sy-k; j <= sy+k; j++) { + float dx = 0.5f + (float)i - x; + float dy = 0.5f + (float)j - y; + float dist = sqrtf(dx*dx + dy*dy); + TextureDataR8_pixel_maxing(self, i, j, a_small_cute_gradient(r_cut, r_decay, dist)); + } + } +} + +void TextureDataR8G8B8A8_draw_one_segment_maxing_alpha(TextureDataR8* self, + float x1, float y1, float x2, float y2, float r_cut, float r_decay) { + TextureDataR8_draw_spot_maxing(self, x1, y1, r_cut, r_decay); + TextureDataR8_draw_spot_maxing(self, x2, y2, r_cut, r_decay); + TextureDataR8_draw_inner_line_maxing(self, x1, y1, x2, y2, r_cut, r_decay); } TextureDataR8G8B8A8 generate_wood_texture() { @@ -172,85 +231,114 @@ TextureDataR8G8B8A8 generate_wood_texture() { return res; } -size_t ModelTopology_get_space_needed_for_staging_buffer(const ModelTopology* self) { - return MAX_U64(self->vertices.len * sizeof(Vertex), self->indexes.len * sizeof(U32)); +ModelTopology generate_one_fourth_of_a_cylinder(float w, float r, U32 k) { + assert(k >= 1); + const float a = M_PI_2f / (float)k; + const float l = 2 * r * sin(M_PI_4f / (float)k); + const vec2 v0tex = {r / (2 * r + w), r / (2 * r + k * l)}; + const vec2 v1tex = {(r + w) / (2 * r + w), r / (2 * r + k * l)}; + const vec2 v2tex = {r / (2 * r + w), 2 * r / (2 * r + k * l)}; + const vec2 v3tex = {(r + w) / (2 * r + w), 2 * r / (2 * r + k * l)}; + VecVertex vertices = VecVertex_new(); // todo: reserve 4 * k + 6 + VecVertex_append(&vertices, (Vertex){.pos = {0, 0, 0}, .tex = v0tex}); + VecVertex_append(&vertices, (Vertex){.pos = {w, 0, 0}, .tex = v1tex}); + VecVertex_append(&vertices, (Vertex){.pos = {0, r, 0}, .tex = v2tex}); + VecVertex_append(&vertices, (Vertex){.pos = {w, r, 0}, .tex = v3tex}); + VecVertex_append(&vertices, (Vertex){.pos = {0, 0, r}, .tex = {r / (2 * r + w), 0}}); + VecVertex_append(&vertices, (Vertex){.pos = {w, 0, r}, .tex = {(r + w) / (2 * r + w), 0}}); + for (U32 i = 1; i <= k; i++) { + VecVertex_append(&vertices, (Vertex){ + .pos = {0, cosf(a * i) * r, sinf(a * i) * r}, + .tex = vec2_add_vec2(v0tex, (vec2){r / (2 * r + w) * -sinf(a * i), r / (2 * r + k * l) * cos(a * i)}) + }); + } + for (U32 i = 1; i <= k; i++) { + VecVertex_append(&vertices, (Vertex){ + .pos = {w, cosf(a * i) * r, sinf(a * i) * r}, + .tex = vec2_add_vec2(v1tex, (vec2){r / (2 * r + w) * sinf(a * i), r / (2*r + k * l) * cos(a * i)}) + }); + } + for (U32 i = 1; i <= k; i++) { + VecVertex_append(&vertices, (Vertex){ + .pos = {0, cosf(a * i) * r, sinf(a * i) * r}, + .tex = {v2tex.x, v2tex.y + i * l / (2*r + k * l)} + }); + } + for (U32 i = 1; i <= k; i++) { + VecVertex_append(&vertices, (Vertex){ + .pos = {w, cosf(a * i) * r, sinf(a * i) * r}, + .tex = {v3tex.x, v3tex.y + i * l / (2*r + k * l)} + }); + } + VecU32 indexes = VecU32_new(); // todo: reserve 3 * (2+2+2*k+2*k)< + { + U32 _span_0[] = { 5, 0, 1, 5, 4, 0, 1, 0, 3, 3, 0, 2 }; + VecU32_append_span(&indexes, (ConstSpanU32){.data = _span_0, .len = ARRAY_SIZE(_span_0)}); + } + for (U32 i = 1; i <= k; i++) { + U32 _span_1[] = { + 0, 5 + i, i > 1 ? 5 + i - 1 : 2, + 1, i > 1 ? 5 + k + i - 1 : 3, 5 + k + i, + i > 1 ? 5 + 2 * k + i - 1 : 2, 5 + 2 * k + i, i > 1 ? 5 + 3 * k + i - 1 : 3, + 5 + 3 * k + i, i > 1 ? 5 + 3 * k + i - 1 : 3, 5 + 2 * k + i + }; + VecU32_append_span(&indexes, (ConstSpanU32){.data = _span_1, .len = ARRAY_SIZE(_span_1)}); + } + return (ModelTopology){.vertices = vertices, .indexes = indexes}; } -size_t TextureDataR8G8B8A8_get_space_needed_for_staging_buffer(const TextureDataR8G8B8A8* self) { - return self->pixels.len * sizeof(cvec4); +#define vec2_drop(x) {} +#define vec2_clone(x) (*(x)) + +VecT_trivmove_struct_Definition(vec2) +VecT_trivmove_method_Definition(vec2) +VecT_primitive_zeroinit_method_Definition(vec2) + +TextureDataR8 generate_tex_template_for_one_fourth_of_a_cylinder(float s_resol, float w, float r, U32 k) { + assert(k >= 1); + assert(k >= 1); + const float a = M_PI_2f / (float)k; + const float l = 2 * r * sin(M_PI_4f / (float)k); + // We will multiply everything by s_resol at the end + const vec2 v0tex = {r, r}; + const vec2 v1tex = {r + w, r}; + const vec2 v2tex = {r, 2 * r}; + const vec2 v3tex = {r + w, 2 * r}; + TextureDataR8 res = TextureDataR8_new((size_t)ceilf((float)s_resol * (2 * r + w)), + (size_t)ceilf((float)s_resol * (2 * r + k * l))); + Vecvec2 P = Vecvec2_new(); // todo: reserve 6 + k * 4 + Vecvec2_append(&P, v0tex); + Vecvec2_append(&P, (vec2){r, 0}); // 4 + Vecvec2_append(&P, (vec2){r + w, 0}); // 5 + Vecvec2_append(&P, v1tex); + for (size_t i = k; i > 0; i--) { + Vecvec2_append(&P, (vec2){r + w + r * sinf(a * i), r + r * cos(a * i)}); + } + Vecvec2_append(&P, v3tex); + for (size_t i = 1; i <= k; i++) { + Vecvec2_append(&P, (vec2){r + w, 2 * r + i * l}); + } + for (size_t i = k; i > 0; i--) { + Vecvec2_append(&P, (vec2){r, 2 * r + i * l}); + } + Vecvec2_append(&P, v2tex); + for (size_t i = 1; i <= k; i++) { + Vecvec2_append(&P, (vec2){r - r * sinf(a * i), r + r * cos(a * i)}); + } + size_t S = 6 + 4 * k; + assert(P.len == S); + float r_cut = 2; + float r_decay = 1; + for (size_t i = 0; i < S; i++) { + vec2 p = vec2_mul_scal(*Vecvec2_at(&P, i), s_resol); + TextureDataR8_draw_spot_maxing(&res, p.x, p.y, r_cut, r_decay); + } + for (size_t i = 0; i < S; i++) { + vec2 pp = vec2_mul_scal(*Vecvec2_at(&P, i ? i - 1 : S - 1), s_resol); + vec2 p = vec2_mul_scal(*Vecvec2_at(&P, i), s_resol); + TextureDataR8_draw_inner_line_maxing(&res, pp.x, pp.y, p.x, p.y, r_cut, r_decay); + } + return res; } -typedef struct { - float fov; - mat3 cam_basis; - vec3 pos; - - float speed; - float sensitivity; - float pitch_cap; -} CamControlInfo; - -void CamControlInfo_forward(CamControlInfo* self, float fl) { - self->pos = vec3_add_vec3(self->pos, vec3_mul_scal(self->cam_basis.z, -self->speed * fl)); -} - -void CamControlInfo_backward(CamControlInfo* self, float fl) { - self->pos = vec3_add_vec3(self->pos, vec3_mul_scal(self->cam_basis.z, self->speed * fl)); -} - -void CamControlInfo_left(CamControlInfo* self, float fl) { - self->pos = vec3_add_vec3(self->pos, vec3_mul_scal(self->cam_basis.x, -self->speed * fl)); -} - -void CamControlInfo_right(CamControlInfo* self, float fl) { - self->pos = vec3_add_vec3(self->pos, vec3_mul_scal(self->cam_basis.x, self->speed * fl)); -} - -void CamControlInfo_down(CamControlInfo* self, float fl) { - self->pos = vec3_add_vec3(self->pos, vec3_mul_scal((vec3){0, -1, 0}, self->speed * fl)); -} - -void CamControlInfo_up(CamControlInfo* self, float fl) { - self->pos = vec3_add_vec3(self->pos, vec3_mul_scal((vec3){0, 1, 0}, self->speed * fl)); -} - -CamControlInfo CamControlInfo_new() { - return (CamControlInfo){ - .fov = 1.5, .cam_basis = margaret_simple_camera_rot_m_basis_in_cols(0, 0, 0), .pos = {0, 0, 0}, - .speed = 2.7, .sensitivity = 0.5f * M_PIf / 180, .pitch_cap = M_PI * 0.49 - }; -} - -float clamp_float(float a, float l, float r) { - return (a < l) ? l : ((a <= r) ? a : r); -} - -void CamControlInfo_update_direction(CamControlInfo* self, int win_width, int win_height, int pointer_x, int pointer_y) { - float yaw = (float)(win_width / 2 - pointer_x) * self->sensitivity; - float pitch = clamp_float( - (float)(win_height / 2 - pointer_y) * self->sensitivity, - -self->pitch_cap, self->pitch_cap - ); - self->cam_basis = margaret_simple_camera_rot_m_basis_in_cols(yaw, pitch, 0); -} - -typedef struct { - VecModelOnScene models; - VkClearColorValue color; - float gamma_correction_factor; - float hdr_factor; - float lsd_factor; - float anim_time; // A timer, passed to functions that push push constants -} Scene; - -Scene Scene_new() { - return (Scene){.models = VecModelOnScene_new(), .color = {.float32 = {1, 0.5, 0.7}}, - .gamma_correction_factor = 2.2, .hdr_factor = 1, .lsd_factor = 0, .anim_time = 0}; -} - -void Scene_drop(Scene self) { - VecModelOnScene_drop(self.models); -} - - #endif diff --git a/src/l2/tests/r0_scene.h b/src/l2/tests/r0_scene.h new file mode 100644 index 0000000..511fc94 --- /dev/null +++ b/src/l2/tests/r0_scene.h @@ -0,0 +1,109 @@ +#ifndef PROTOTYPE1_SRC_L2_TESTS_R0_SCENE_H +#define PROTOTYPE1_SRC_L2_TESTS_R0_SCENE_H + +#include "r0_assets.h" + +/* No offset yet */ +typedef struct { + VkBuffer vbo; + VkBuffer ebo; + size_t indexes; +} ModelOnScene; + +#define ModelOnScene_drop(vp) {} +#define ModelOnScene_clone(vp) (*(vp)) + +VecT_trivmove_struct_Definition(ModelOnScene) +VecT_trivmove_method_Definition(ModelOnScene) +VecT_primitive_zeroinit_method_Definition(ModelOnScene) + +typedef struct { + ModelOnScene model; + mat4 model_t; +} UsedModelOnScene; + +#define UsedModelOnScene_drop(vp) {} +#define UsedModelOnScene_clone(vp) (*(vp)) + +VecT_trivmove_struct_Definition(UsedModelOnScene) +VecT_trivmove_method_Definition(UsedModelOnScene) +VecT_primitive_zeroinit_method_Definition(UsedModelOnScene) + + +typedef struct { + float fov; + mat3 cam_basis; + vec3 pos; + + float speed; + float sensitivity; + float pitch_cap; +} CamControlInfo; + +void CamControlInfo_forward(CamControlInfo* self, float fl) { + self->pos = vec3_add_vec3(self->pos, vec3_mul_scal(self->cam_basis.z, -self->speed * fl)); +} + +void CamControlInfo_backward(CamControlInfo* self, float fl) { + self->pos = vec3_add_vec3(self->pos, vec3_mul_scal(self->cam_basis.z, self->speed * fl)); +} + +void CamControlInfo_left(CamControlInfo* self, float fl) { + self->pos = vec3_add_vec3(self->pos, vec3_mul_scal(self->cam_basis.x, -self->speed * fl)); +} + +void CamControlInfo_right(CamControlInfo* self, float fl) { + self->pos = vec3_add_vec3(self->pos, vec3_mul_scal(self->cam_basis.x, self->speed * fl)); +} + +void CamControlInfo_down(CamControlInfo* self, float fl) { + self->pos = vec3_add_vec3(self->pos, vec3_mul_scal((vec3){0, -1, 0}, self->speed * fl)); +} + +void CamControlInfo_up(CamControlInfo* self, float fl) { + self->pos = vec3_add_vec3(self->pos, vec3_mul_scal((vec3){0, 1, 0}, self->speed * fl)); +} + +CamControlInfo CamControlInfo_new() { + return (CamControlInfo){ + .fov = 1.5, .cam_basis = margaret_simple_camera_rot_m_basis_in_cols(0, 0, 0), .pos = {0, 0, 0}, + .speed = 2.7, .sensitivity = 0.5f * M_PIf / 180, .pitch_cap = M_PI * 0.49 + }; +} + +float clamp_float(float a, float l, float r) { + return (a < l) ? l : ((a <= r) ? a : r); +} + +void CamControlInfo_update_direction(CamControlInfo* self, int win_width, int win_height, int pointer_x, int pointer_y) { + float yaw = (float)(win_width / 2 - pointer_x) * self->sensitivity; + float pitch = clamp_float( + (float)(win_height / 2 - pointer_y) * self->sensitivity, + -self->pitch_cap, self->pitch_cap + ); + self->cam_basis = margaret_simple_camera_rot_m_basis_in_cols(yaw, pitch, 0); +} + +typedef struct { + VecUsedModelOnScene models; + VkClearColorValue color; + float gamma_correction_factor; + float hdr_factor; + float lsd_factor; + float anim_time; // A timer, passed to functions that push push constants + VecPipeline0Spotlight spotlights; + VecPipeline0PointLight point_lights; +} Scene; + +Scene Scene_new() { + return (Scene){.models = VecUsedModelOnScene_new(), .color = {.float32 = {1, 0.5, 0.7}}, + .gamma_correction_factor = 2.2, .hdr_factor = 1, .lsd_factor = 0, .anim_time = 0, + .spotlights = VecPipeline0Spotlight_new(), .point_lights = VecPipeline0PointLight_new()}; +} + +void Scene_drop(Scene self) { + VecUsedModelOnScene_drop(self.models); +} + + +#endif diff --git a/src/l2/tests/r0_tex_init_prep.c b/src/l2/tests/r0_tex_init_prep.c new file mode 100644 index 0000000..0189340 --- /dev/null +++ b/src/l2/tests/r0_tex_init_prep.c @@ -0,0 +1,9 @@ +#include "r0_assets.h" +#include "../../l1/system/fileio.h" + +int main() { + TextureDataR8 tex_1 = generate_tex_template_for_one_fourth_of_a_cylinder(20, 10, 2, 6); + TextureDataR8_write_to_file(&tex_1, "log_10_2_6_TEMPLATE.r8"); + TextureDataR8_drop(tex_1); + return 0; +} diff --git a/src/l2/tests/test_shader_compile.sh b/src/l2/tests/test_shader_compile.sh index 916e835..65e2eb2 100755 --- a/src/l2/tests/test_shader_compile.sh +++ b/src/l2/tests/test_shader_compile.sh @@ -1,4 +1,6 @@ #!/usr/bin/env bash + +set +x cd test_shaders function compile(){ @@ -9,3 +11,11 @@ function compile(){ compile 0 compile 1 + +#cd ../test_textures +# +#function png_to_r8g8b8a8 { +# python bitmap_convert.py to_bmp "$1.png" "$1.r8g8b8" +#} +# +#png_to_r8g8b8a8 log_10_2_6 diff --git a/src/l2/tests/test_shaders/glsl/0/0.frag b/src/l2/tests/test_shaders/glsl/0/0.frag index d75e8d2..1ce099b 100644 --- a/src/l2/tests/test_shaders/glsl/0/0.frag +++ b/src/l2/tests/test_shaders/glsl/0/0.frag @@ -6,6 +6,30 @@ layout(location = 0) out vec4 fin_color; layout(binding = 1) uniform sampler2D color_tex; + +struct Pipeline0Spotlight +{ + vec3 pos; + vec3 dir; + vec3 colour; + float range; +}; + +struct Pipeline0PointLight +{ + vec3 pos; + vec3 colour; +}; + +layout(std140, binding = 0) uniform Pipeline0UBO +{ + int spotlight_count; + int point_light_count; + + Pipeline0PointLight point_light_arr[20]; + Pipeline0Spotlight spotlight_arr [120]; +}; + void main(){ fin_color = texture(color_tex, fsin_tex); -} \ No newline at end of file +} diff --git a/src/l2/tests/test_shaders/glsl/0/0.vert b/src/l2/tests/test_shaders/glsl/0/0.vert index 5f93605..d28b556 100644 --- a/src/l2/tests/test_shaders/glsl/0/0.vert +++ b/src/l2/tests/test_shaders/glsl/0/0.vert @@ -5,12 +5,14 @@ layout(location = 1) in vec2 tex; layout(location = 0) out vec2 vsout_tex; -layout(binding = 0) uniform ubo { +layout(push_constant, std430) uniform pc { + /* Individual transformation for a model. Fits in push constant range + Includes global perspective matrix and camera matrix, but for each model there is a distinct + transformation matrix. Right now I only have one instance for each model, + otherwise I would use per-instance vertex attribute */ mat4 t; }; -// todo: add my ubo (location = 0) into the mix -// todo: add my woiod_texture (location = 1) into the mix void main(){ vsout_tex = tex; gl_Position = t * vec4(pos, 1); diff --git a/src/l2/tests/test_shaders/glsl/0b/0b.frag b/src/l2/tests/test_shaders/glsl/0b/0b.frag new file mode 100644 index 0000000..e69de29 diff --git a/src/l2/tests/test_shaders/glsl/0b/0b.vert b/src/l2/tests/test_shaders/glsl/0b/0b.vert new file mode 100644 index 0000000..e69de29 diff --git a/src/l2/tests/test_textures/bitmap_converter.py b/src/l2/tests/test_textures/bitmap_converter.py new file mode 100755 index 0000000..b7dae80 --- /dev/null +++ b/src/l2/tests/test_textures/bitmap_converter.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python3 +""" +raw_png_conv.py +=============== + +Convert between custom bottom‑up raw files (.r8g8b8a8 / .r8b8g8 / .r8) +and normal PNG using Pillow. + +Format +------ +uint32 width (little‑endian) +uint32 height (little‑endian) +pixel data rows bottom‑first: + * .r8g8b8a8 : R G B A (4× uint8) + * .r8b8g8 : R G B (3× uint8) + * .r8 : R (1× uint8 <- grayscale) + +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"}, + ".r8b8g8": {"pix_size": 3, "mode": "RGB"}, + ".r8": {"pix_size": 1, "mode": "L"}, +} + + +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_raw(path: Path) -> Image.Image: + """Load any supported raw file -> Pillow Image.""" + spec = get_fmt(path) + 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(" top‑down + return Image.frombytes(spec["mode"], (w, h), img_bytes) + + +def write_raw(img: Image.Image, path: Path) -> None: + """Write Pillow Image -> raw file chosen by path suffix.""" + spec = get_fmt(path) + # Convert to required mode + if img.mode != spec["mode"]: + if spec["mode"] == "L": + img = img.convert("L") + elif spec["mode"] == "RGB": + img = img.convert("RGB") + else: # RGBA + img = img.convert("RGBA") + + 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)) # top‑down -> bottom‑up + + with path.open("wb") as f: + f.write(struct.pack(" 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() diff --git a/src/l2/tests/test_textures/log_10_2_6.png b/src/l2/tests/test_textures/log_10_2_6.png new file mode 100644 index 0000000..7c307a2 Binary files /dev/null and b/src/l2/tests/test_textures/log_10_2_6.png differ diff --git a/src/l2/tests/test_textures/log_10_2_6_TEMPLATE.png b/src/l2/tests/test_textures/log_10_2_6_TEMPLATE.png new file mode 100644 index 0000000..fed645a Binary files /dev/null and b/src/l2/tests/test_textures/log_10_2_6_TEMPLATE.png differ diff --git a/src/l2/tests/test_textures/log_10_2_6_v2.png b/src/l2/tests/test_textures/log_10_2_6_v2.png new file mode 100644 index 0000000..615b820 Binary files /dev/null and b/src/l2/tests/test_textures/log_10_2_6_v2.png differ