Meshes refer to exported images, image caching system (only load path

once)
main
parent f41680a597
commit c9b6ce0c3e

@ -80,6 +80,32 @@ with open(bpy.path.abspath(f"//{EXPORT_DIRECTORY}/shorttest.bin"), "wb") as f:
for i in range(4): for i in range(4):
write_u16(f, i) write_u16(f, i)
saved_images = set()
def ensure_tex_saved_and_get_name(o) -> str:
"""returns the path to the mesh's texture's png in the exported directory"""
mesh_name = o.to_mesh().name
img_obj = None
assert len(o.material_slots) == 1, f"Don't know which material slot to pick from in mesh {mesh_name} object {o.name}"
mat = o.material_slots[0]
for node in mat.material.node_tree.nodes:
if node.type == "TEX_IMAGE":
img_obj = node.image
break
assert img_obj, f"Mesh {mesh_name} in its material doesn't have an image object"
image_filename = f"{img_obj.name}.png"
if image_filename in saved_images:
pass
else:
save_to = f"//{EXPORT_DIRECTORY}/{image_filename}"
print(f"Saving image {image_filename} to {bpy.path.abspath((save_to))}...")
if img_obj.packed_file:
img_obj.save(filepath=bpy.path.abspath(save_to))
else:
assert img_obj.filepath != "", f"{img_obj.filepath} in mesh {mesh_name} Isn't there but should be, as it has no packed image"
shutil.copyfile(bpy.path.abspath(img_obj.filepath),bpy.path.abspath(save_to))
return image_filename
# meshes can either be Meshes, or Armatures. Armatures contain all mesh data to draw it, and any anims it has # meshes can either be Meshes, or Armatures. Armatures contain all mesh data to draw it, and any anims it has
for o in D.objects: for o in D.objects:
@ -235,13 +261,14 @@ for o in D.objects:
else: # if the parent type isn't an armature, i.e just a bog standard mesh else: # if the parent type isn't an armature, i.e just a bog standard mesh
mesh_name = o.to_mesh().name # use this over o.name so instanced objects which refer to the same mesh, both use the same serialized mesh. mesh_name = o.to_mesh().name # use this over o.name so instanced objects which refer to the same mesh, both use the same serialized mesh.
object_transform_info = (mesh_name, mapping @ o.location, o.rotation_euler, o.scale) object_transform_info = (mesh_name, mapping @ o.location, o.rotation_euler, o.scale)
if o.users_collection[0].name == 'Level' and mesh_name == "CollisionCube": if o.users_collection[0].name == 'Level' and mesh_name == "CollisionCube":
collision_cubes.append((o.location, o.dimensions)) collision_cubes.append((o.location, o.dimensions))
else: else:
if o.users_collection[0].name == 'Level': if o.users_collection[0].name == 'Level':
print(f"Object {o.name} has mesh name {o.to_mesh().name}") print(f"Object {o.name} has mesh name {o.to_mesh().name} and image file {image_filename}")
assert(o.rotation_euler.order == 'XYZ') assert(o.rotation_euler.order == 'XYZ')
level_object_data.append(object_transform_info) level_object_data.append(object_transform_info)
else: else:
@ -250,12 +277,15 @@ for o in D.objects:
if mesh_name in saved_meshes: if mesh_name in saved_meshes:
continue continue
saved_meshes.add(mesh_name) saved_meshes.add(mesh_name)
image_filename = ensure_tex_saved_and_get_name(o)
assert(mesh_name != LEVEL_EXPORT_NAME) assert(mesh_name != LEVEL_EXPORT_NAME)
output_filepath = bpy.path.abspath(f"//{EXPORT_DIRECTORY}/{mesh_name}.bin") output_filepath = bpy.path.abspath(f"//{EXPORT_DIRECTORY}/{mesh_name}.bin")
print(f"Exporting mesh to {output_filepath}") print(f"Exporting mesh to {output_filepath}")
with open(output_filepath, "wb") as f: with open(output_filepath, "wb") as f:
write_b8(f, False) write_b8(f, False) # if it's an armature or not, first byte of the file
write_string(f, image_filename) # the image filename!
bm = bmesh.new() bm = bmesh.new()
mesh = o.to_mesh() mesh = o.to_mesh()
bm.from_mesh(mesh) bm.from_mesh(mesh)

@ -194,7 +194,7 @@ int main(int argc, char **argv)
fclose(asset_file); fclose(asset_file);
MD_S8ListPush(cg_arena, &declarations_list, MD_S8Fmt(cg_arena, "sg_image %.*s = {0};\n", MD_S8VArg(variable_name))); MD_S8ListPush(cg_arena, &declarations_list, MD_S8Fmt(cg_arena, "sg_image %.*s = {0};\n", MD_S8VArg(variable_name)));
MD_S8ListPush(cg_arena, &load_list, MD_S8Fmt(cg_arena, "%.*s = load_image(\"%.*s\");\n", MD_S8VArg(variable_name), MD_S8VArg(filepath))); MD_S8ListPush(cg_arena, &load_list, MD_S8Fmt(cg_arena, "%.*s = load_image(MD_S8Lit(\"%.*s\"));\n", MD_S8VArg(variable_name), MD_S8VArg(filepath)));
} }
} }

@ -750,18 +750,39 @@ AABB entity_aabb(Entity *e)
return entity_aabb_at(e, at); return entity_aabb_at(e, at);
} }
sg_image load_image(const char *path) typedef struct LoadedImage
{ {
struct LoadedImage *next;
MD_String8 name;
sg_image image;
} LoadedImage;
LoadedImage *loaded_images = 0;
sg_image load_image(MD_String8 path)
{
for(LoadedImage *cur = loaded_images; cur; cur = cur->next)
{
if(MD_S8Match(cur->name, path, 0))
{
return cur->image;
}
}
LoadedImage *loaded = MD_PushArray(persistent_arena, LoadedImage, 1);
loaded->name = MD_S8Copy(persistent_arena, path);
MD_StackPush(loaded_images, loaded);
sg_image to_return = { 0 }; sg_image to_return = { 0 };
int png_width, png_height, num_channels; int png_width, png_height, num_channels;
const int desired_channels = 4; const int desired_channels = 4;
stbi_uc* pixels = stbi_load( stbi_uc* pixels = stbi_load(
path, (const char*)nullterm(frame_arena, path).str,
&png_width, &png_height, &png_width, &png_height,
&num_channels, 0); &num_channels, 0);
assert(pixels); assert(pixels);
Log("Pah %s | Loading image with dimensions %d %d\n", path, png_width, png_height); Log("Path %.*s | Loading image with dimensions %d %d\n", MD_S8VArg(path), png_width, png_height);
to_return = sg_make_image(&(sg_image_desc) to_return = sg_make_image(&(sg_image_desc)
{ {
.width = png_width, .width = png_width,
@ -779,6 +800,7 @@ sg_image load_image(const char *path)
} }
}); });
stbi_image_free(pixels); stbi_image_free(pixels);
loaded->image = to_return;
return to_return; return to_return;
} }
@ -839,6 +861,7 @@ typedef struct Mesh
MD_u64 num_vertices; MD_u64 num_vertices;
sg_buffer loaded_buffer; sg_buffer loaded_buffer;
sg_image mesh_image;
MD_String8 name; MD_String8 name;
} Mesh; } Mesh;
@ -910,8 +933,12 @@ Mesh load_mesh(MD_Arena *arena, MD_String8 binary_file, MD_String8 mesh_name)
ser_bool(&ser, &is_armature); ser_bool(&ser, &is_armature);
assert(!is_armature); assert(!is_armature);
MD_String8 image_filename;
ser_MD_String8(&ser, &image_filename, scratch.arena);
out.mesh_image = load_image(MD_S8Fmt(scratch.arena, "assets/exported_3d/%.*s", MD_S8VArg(image_filename)));
ser_MD_u64(&ser, &out.num_vertices); ser_MD_u64(&ser, &out.num_vertices);
Log("Mesh %.*s has %llu vertices\n", MD_S8VArg(mesh_name), out.num_vertices); Log("Mesh %.*s has %llu vertices and image filename '%.*s'\n", MD_S8VArg(mesh_name), out.num_vertices, MD_S8VArg(image_filename));
out.vertices = MD_ArenaPush(arena, sizeof(*out.vertices) * out.num_vertices); out.vertices = MD_ArenaPush(arena, sizeof(*out.vertices) * out.num_vertices);
for(MD_u64 i = 0; i < out.num_vertices; i++) for(MD_u64 i = 0; i < out.num_vertices; i++)
@ -2767,7 +2794,7 @@ void draw_placed(Mat4 view, Mat4 projection, Mat4 light_matrix, PlacedMesh *cur)
{ {
*it = (sg_image){0}; *it = (sg_image){0};
} }
state.threedee_bind.fs_images[SLOT_threedee_tex] = image_gigatexture; state.threedee_bind.fs_images[SLOT_threedee_tex] = drawing->mesh_image;
state.threedee_bind.fs_images[SLOT_threedee_shadow_map] = state.shadows.color_img; state.threedee_bind.fs_images[SLOT_threedee_shadow_map] = state.shadows.color_img;
state.threedee_bind.vertex_buffers[0] = drawing->loaded_buffer; state.threedee_bind.vertex_buffers[0] = drawing->loaded_buffer;
sg_apply_bindings(&state.threedee_bind); sg_apply_bindings(&state.threedee_bind);

Loading…
Cancel
Save