I rendered a skeleton. It is broken. Someone broke the skeleton.

This commit is contained in:
Андреев Григорий 2026-01-09 16:46:15 +03:00
parent 8c07fd9681
commit 33df2e4e8e
10 changed files with 6027362 additions and 43 deletions

View File

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

View File

@ -252,4 +252,12 @@ U32 SpanU8_decode_as_utf8(SpanU8* rem){
return 0;
}
bool SpanU8_is_prefix(SpanU8 a, SpanU8 str){
return str.len >= a.len && SpanU8_cont_equal(a, SpanU8_span(str, 0, a.len));
}
bool SpanU8_is_postfix(SpanU8 a, SpanU8 str){
return str.len >= a.len && SpanU8_cont_equal(a, SpanU8_span(str, str.len - a.len, a.len));
}
#endif

View File

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

View File

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

View File

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

View File

@ -823,7 +823,14 @@ struct Alice {
};
ListNodeAliceGenericMeshHand* Alice_add_generic_mesh(Alice* alice, AliceGenericMeshPath paths){
GenericMeshTopology topology = alice_expect_read_generic_mesh_from_file(paths.topology_path);
GenericMeshTopology topology;
if (SpanU8_is_postfix(cstr(".AliceGenericMesh"), VecU8_to_span(&paths.topology_path) )) {
topology = alice_expect_read_generic_mesh_from_file(paths.topology_path);
} else if (SpanU8_is_postfix(cstr(".obj"), VecU8_to_span(&paths.topology_path) )) {
topology = alice_expect_read_generic_mesh_from_obj_file(paths.topology_path);
} else {
abortf("Иди своей дорогой\n");
}
ListNodeAliceGenericMeshHand* mm_node = safe_calloc(1, sizeof(ListNodeAliceGenericMeshHand));
AliceGenericMeshHand* mm = &mm_node->el;

View File

@ -693,6 +693,14 @@ void r4_generate_flat_normal_map(VecU8 save_path){
TextureDataR8G8B8A8_drop(normal);
}
void generate_single_pixel_gray_tex(VecU8 save_path, U8 clr){
TextureDataR8 tex = TextureDataR8_new(1, 1);
*TextureDataR8_mat(&tex, 0, 0) = clr;
TextureDataR8_write_to_png_nofail(&tex, VecU8_to_span(&save_path));
VecU8_drop(save_path);
TextureDataR8_drop(tex);
}
/* r is radius, w is length of cylinder. Will write everything into files for us */
void r4_asset_gen_generic_mesh_cylinder(float s_resol, float r, float w, U32 k,
VecU8 path_to_mesh, VecU8 path_to_template_tex, VecU8 path_to_normal_tex){
@ -895,8 +903,8 @@ int gen_assets_for_r4() {
r4_asset_gen_generic_mesh_cylinder(100, 0.04f, 1.5f, 4, vcstr("l2/models/stick.AliceGenericMesh"),
vcstr("l2/textures/stick_TEMPLATE.png"), vcstr("l2/textures/stick_NORMAL.png"));
r4_generate_flat_normal_map(vcstr("l2/textures/flat_NORMAL.png"));
generate_single_pixel_gray_tex(vcstr("l2/textures/no_SPECULAR.png"), 0);
return 0;
}
#endif
#endif

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 916 KiB

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

File diff suppressed because it is too large Load Diff

View File

@ -67,43 +67,55 @@ int main(){
LucyRenderer_add_simple_label(&st.alice->lucy_renderer, st.font_face_of_size_40, (vec4){0, 0, 0, 1}, 0,
cstr("Bebra budet\nотнюхана\n"), (ivec2){10, 10});
ListNodeAliceGenericMeshHand* model_gen = Alice_add_generic_mesh(st.alice, AliceGenericMeshPath_for_log(cstr("."), 10, 2, 6));
AliceGenericMeshHand_resize_instance_arr(st.alice, &model_gen->el, 1);
for (int X = 0; X < 1; X++) {
for (int Z = 0; Z < 1; Z++) {
AliceGenericMeshHand_set_inst(&model_gen->el, X * 10 + Z, (GenericMeshInstanceInc){
.model_t = marie_translation_mat4((vec3){11.f * (float)X, -6, 4.f * (float)Z}),
});
}
}
// ListNodeAliceShinyMeshHand *model_sh = Alice_add_shiny_mesh(st->alice, vcstr("./gen/l2/models/cube.AliceShinyMesh"));
// AliceShinyMeshHand_resize_instance_arr(st->alice, &model_sh->el, 100);
// for (int X = 0; X < 10; X++) {
// for (int Z = 0; Z < 10; Z++) {
// AliceShinyMeshHand_set_inst(&model_sh->el, X * 10 + Z, (ShinyMeshInstanceInc){
// .color_on = {0, 1, 0}, .color_off = {0.3f, 0.6f, 0.3f},
// .model_t = marie_translation_mat4((vec3){11.f * (float)X - 20, 10, 4.f * (float)Z - 10}),
// ListNodeAliceGenericMeshHand* model_gen = Alice_add_generic_mesh(st.alice, AliceGenericMeshPath_for_log(cstr("."), 10, 2, 6));
// AliceGenericMeshHand_resize_instance_arr(st.alice, &model_gen->el, 1);
//
// for (int X = 0; X < 1; X++) {
// for (int Z = 0; Z < 1; Z++) {
// AliceGenericMeshHand_set_inst(&model_gen->el, X * 10 + Z, (GenericMeshInstanceInc){
// .model_t = marie_translation_mat4((vec3){11.f * (float)X, -6, 4.f * (float)Z}),
// });
// }
// }
// Pipeline0UBO* ubo = (Pipeline0UBO*)MargaretSubbuf_get_mapped(&st->alice->pipeline0_ubo.staging);
// assert(pipeline_0_ubo_point_light_max_count >= 100);
// ubo->point_light_count = 100;
// ubo->spotlight_count = 0;
// for (int X = 0; X < 10; X++) {
// for (int Z = 0; Z < 10; Z++) {
// ubo->point_light_arr[X * 10 + Z] = (Pipeline0PointLight){
// .pos = (vec3){11.f * (float)X - 20, 10, 4.f * (float)Z - 10},
// .color = {5, 5, 5}
// };
// }
// }
// ubo->point_light_arr[0].color = (vec3){100, 100, 100};
ListNodeAliceShinyMeshHand *model_sh = Alice_add_shiny_mesh(st.alice, vcstr("./gen/l2/models/cube.AliceShinyMesh"));
AliceShinyMeshHand_resize_instance_arr(st.alice, &model_sh->el, 100);
for (int X = 0; X < 10; X++) {
for (int Z = 0; Z < 10; Z++) {
AliceShinyMeshHand_set_inst(&model_sh->el, X * 10 + Z, (ShinyMeshInstanceInc){
.color_on = {0, 1, 0},
.model_t = marie_translation_mat4((vec3){11.f * (float)X - 20, 10, 4.f * (float)Z - 10}),
});
}
}
Pipeline0UBO* ubo = (Pipeline0UBO*)MargaretSubbuf_get_mapped(&st.alice->pipeline0_ubo.staging);
assert(pipeline_0_ubo_point_light_max_count >= 100);
ubo->point_light_count = 100;
ubo->spotlight_count = 0;
for (int X = 0; X < 10; X++) {
for (int Z = 0; Z < 10; Z++) {
ubo->point_light_arr[X * 10 + Z] = (Pipeline0PointLight){
.pos = (vec3){11.f * (float)X - 20, 10, 4.f * (float)Z - 10},
.color = {5, 5, 5}
};
}
}
ubo->point_light_arr[0].color = (vec3){100, 100, 100};
ListNodeAliceGenericMeshHand* skeleton_mesh = Alice_add_generic_mesh(st.alice, (AliceGenericMeshPath){
.topology_path = vcstr("./src/l3/models/skeleton.obj"),
.diffuse_texture_path = vcstr("./src/l3/models/bone.png"),
.normal_texture_path = vcstr("./gen/l2/textures/flat_NORMAL.png"),
.specular_texture_path = vcstr("./gen/l2/textures/flat_NORMAL.png"),
});
AliceGenericMeshHand_resize_instance_arr(alice, &skeleton_mesh->el, 1);
AliceGenericMeshHand_set_inst(&skeleton_mesh->el, 0, (GenericMeshInstanceInc){
.model_t = marie_translation_mat4((vec3){5.f, -3, 12.f}),
});
// ListNodeAliceGenericMeshHand* model_puck = Alice_add_generic_mesh(st->alice, AliceGenericMeshPath_for_puck());
// AliceGenericMeshHand_resize_instance_arr(st->alice, &model_puck->el, 100);