bool Model::parseMeshesOld(bgfx::VertexDecl global_vertex_decl, FS::IFile& file, FileVersion version, u32 global_flags) { int object_count = 0; file.read(&object_count, sizeof(object_count)); if (object_count <= 0) return false; m_meshes.reserve(object_count); char model_dir[MAX_PATH_LENGTH]; PathUtils::getDir(model_dir, MAX_PATH_LENGTH, getPath().c_str()); struct Offsets { i32 attribute_array_offset; i32 attribute_array_size; i32 indices_offset; i32 mesh_tri_count; }; Array<Offsets> mesh_offsets(m_allocator); for (int i = 0; i < object_count; ++i) { i32 str_size; file.read(&str_size, sizeof(str_size)); char material_name[MAX_PATH_LENGTH]; file.read(material_name, str_size); if (str_size >= MAX_PATH_LENGTH) return false; material_name[str_size] = 0; char material_path[MAX_PATH_LENGTH]; copyString(material_path, model_dir); catString(material_path, material_name); catString(material_path, ".mat"); auto* material_manager = m_resource_manager.getOwner().get(Material::TYPE); Material* material = static_cast<Material*>(material_manager->load(Path(material_path))); Offsets& offsets = mesh_offsets.emplace(); file.read(&offsets.attribute_array_offset, sizeof(offsets.attribute_array_offset)); file.read(&offsets.attribute_array_size, sizeof(offsets.attribute_array_size)); file.read(&offsets.indices_offset, sizeof(offsets.indices_offset)); file.read(&offsets.mesh_tri_count, sizeof(offsets.mesh_tri_count)); file.read(&str_size, sizeof(str_size)); if (str_size >= MAX_PATH_LENGTH) { material_manager->unload(*material); return false; } char mesh_name[MAX_PATH_LENGTH]; mesh_name[str_size] = 0; file.read(mesh_name, str_size); bgfx::VertexDecl vertex_decl = global_vertex_decl; if (version <= FileVersion::SINGLE_VERTEX_DECL) { parseVertexDecl(file, &vertex_decl); if (i != 0 && global_vertex_decl.m_hash != vertex_decl.m_hash) { g_log_error.log("Renderer") << "Model " << getPath().c_str() << " contains meshes with different vertex declarations."; } if(i == 0) global_vertex_decl = vertex_decl; } m_meshes.emplace(material, vertex_decl, mesh_name, m_allocator); addDependency(*material); } i32 indices_count = 0; file.read(&indices_count, sizeof(indices_count)); if (indices_count <= 0) return false; u32 INDICES_16BIT_FLAG = 1; int index_size = global_flags & INDICES_16BIT_FLAG ? 2 : 4; Array<u8> indices(m_allocator); indices.resize(indices_count * index_size); file.read(&indices[0], indices.size()); i32 vertices_size = 0; file.read(&vertices_size, sizeof(vertices_size)); if (vertices_size <= 0) return false; Array<u8> vertices(m_allocator); vertices.resize(vertices_size); file.read(&vertices[0], vertices.size()); int vertex_count = 0; for (const Offsets& offsets : mesh_offsets) { vertex_count += offsets.attribute_array_size / global_vertex_decl.getStride(); } if (version > FileVersion::BOUNDING_SHAPES_PRECOMPUTED) { file.read(&m_bounding_radius, sizeof(m_bounding_radius)); file.read(&m_aabb, sizeof(m_aabb)); } float bounding_radius_squared = 0; Vec3 min_vertex(0, 0, 0); Vec3 max_vertex(0, 0, 0); int vertex_size = global_vertex_decl.getStride(); int position_attribute_offset = global_vertex_decl.getOffset(bgfx::Attrib::Position); int uv_attribute_offset = global_vertex_decl.getOffset(bgfx::Attrib::TexCoord0); int weights_attribute_offset = global_vertex_decl.getOffset(bgfx::Attrib::Weight); int bone_indices_attribute_offset = global_vertex_decl.getOffset(bgfx::Attrib::Indices); bool keep_skin = global_vertex_decl.has(bgfx::Attrib::Weight) && global_vertex_decl.has(bgfx::Attrib::Indices); for (int i = 0; i < m_meshes.size(); ++i) { Offsets& offsets = mesh_offsets[i]; Mesh& mesh = m_meshes[i]; mesh.indices_count = offsets.mesh_tri_count * 3; mesh.indices.resize(mesh.indices_count * index_size); copyMemory(&mesh.indices[0], &indices[offsets.indices_offset * index_size], mesh.indices_count * index_size); int mesh_vertex_count = offsets.attribute_array_size / global_vertex_decl.getStride(); int mesh_attributes_array_offset = offsets.attribute_array_offset; mesh.vertices.resize(mesh_vertex_count); mesh.uvs.resize(mesh_vertex_count); if (keep_skin) mesh.skin.resize(mesh_vertex_count); for (int j = 0; j < mesh_vertex_count; ++j) { int offset = mesh_attributes_array_offset + j * vertex_size; if (keep_skin) { mesh.skin[j].weights = *(const Vec4*)&vertices[offset + weights_attribute_offset]; copyMemory(mesh.skin[j].indices, &vertices[offset + bone_indices_attribute_offset], sizeof(mesh.skin[j].indices)); } mesh.vertices[j] = *(const Vec3*)&vertices[offset + position_attribute_offset]; mesh.uvs[j] = *(const Vec2*)&vertices[offset + uv_attribute_offset]; float sq_len = mesh.vertices[j].squaredLength(); bounding_radius_squared = Math::maximum(bounding_radius_squared, sq_len > 0 ? sq_len : 0); min_vertex.x = Math::minimum(min_vertex.x, mesh.vertices[j].x); min_vertex.y = Math::minimum(min_vertex.y, mesh.vertices[j].y); min_vertex.z = Math::minimum(min_vertex.z, mesh.vertices[j].z); max_vertex.x = Math::maximum(max_vertex.x, mesh.vertices[j].x); max_vertex.y = Math::maximum(max_vertex.y, mesh.vertices[j].y); max_vertex.z = Math::maximum(max_vertex.z, mesh.vertices[j].z); } } if (version <= FileVersion::BOUNDING_SHAPES_PRECOMPUTED) { m_bounding_radius = sqrt(bounding_radius_squared); m_aabb = AABB(min_vertex, max_vertex); } for (int i = 0; i < m_meshes.size(); ++i) { Mesh& mesh = m_meshes[i]; Offsets offsets = mesh_offsets[i]; ASSERT(!bgfx::isValid(mesh.index_buffer_handle)); if (global_flags & INDICES_16BIT_FLAG) { mesh.flags.set(Mesh::Flags::INDICES_16_BIT); } int indices_size = index_size * mesh.indices_count; const bgfx::Memory* mem = bgfx::copy(&indices[offsets.indices_offset * index_size], indices_size); mesh.index_buffer_handle = bgfx::createIndexBuffer(mem, index_size == 4 ? BGFX_BUFFER_INDEX32 : 0); if (!bgfx::isValid(mesh.index_buffer_handle)) return false; ASSERT(!bgfx::isValid(mesh.vertex_buffer_handle)); const bgfx::Memory* vertices_mem = bgfx::copy(&vertices[offsets.attribute_array_offset], offsets.attribute_array_size); mesh.vertex_buffer_handle = bgfx::createVertexBuffer(vertices_mem, mesh.vertex_decl); if (!bgfx::isValid(mesh.vertex_buffer_handle)) return false; } return true; }
ShapeParser::ShapeParseResult ShapeParser::serialized(const XMLNode& node, ParserState& S) { auto filename = S.map_asset_filepath(S.def_storage.prop_string(node, "filename")); int submesh_index = S.def_storage.prop_int(node, "shapeIndex"); bool flipNormals = S.def_storage.prop_bool(node, "flipNormals", false); bool faceNormals = S.def_storage.prop_bool(node, "faceNormals", false); float maxSmoothAngle = S.def_storage.prop_float(node, "maxSmoothAngle", 0.0f); auto name = boost::filesystem::path(filename).stem().string(); auto compiled_tar_folder = S.scene.getFileManager()->getCompiledMeshPath("") + name + "/"; auto get_compiled_submesh_filename = [&](size_t i) { return compiled_tar_folder + std::to_string(i) + ".xmsh"; }; if (!boost::filesystem::exists(compiled_tar_folder) || !boost::filesystem::exists(get_compiled_submesh_filename(0))) { boost::filesystem::create_directory(compiled_tar_folder); enum DataPresentFlag : uint32_t { VertexNormals = 0x0001, TextureCoords = 0x0002, VertexColors = 0x0008, UseFaceNormals = 0x0010, SinglePrecision = 0x1000, DoublePrecision = 0x2000, }; struct inflateStream { std::ifstream& m_childStream; size_t str_length; z_stream m_inflateStream; uint8_t m_inflateBuffer[32768]; inflateStream(std::ifstream& str) :m_childStream(str) { size_t pos = m_childStream.tellg(); m_childStream.seekg(0, m_childStream.end); str_length = m_childStream.tellg(); m_childStream.seekg(pos, m_childStream.beg); m_inflateStream.zalloc = Z_NULL; m_inflateStream.zfree = Z_NULL; m_inflateStream.opaque = Z_NULL; m_inflateStream.avail_in = 0; m_inflateStream.next_in = Z_NULL; int windowBits = 15; auto retval = inflateInit2(&m_inflateStream, windowBits); if (retval != Z_OK) std::cout << "erro, ret : " << retval << std::endl; } void read(void *ptr, size_t size) { uint8_t *targetPtr = (uint8_t *)ptr; while (size > 0) { if (m_inflateStream.avail_in == 0) { size_t remaining = str_length - m_childStream.tellg(); m_inflateStream.next_in = m_inflateBuffer; m_inflateStream.avail_in = (uInt)std::min(remaining, sizeof(m_inflateBuffer)); if (m_inflateStream.avail_in == 0) std::cout << "more bytes req : " << size << std::endl; m_childStream.read((char*)m_inflateBuffer, m_inflateStream.avail_in); } m_inflateStream.avail_out = (uInt)size; m_inflateStream.next_out = targetPtr; int retval = inflate(&m_inflateStream, Z_NO_FLUSH); switch (retval) { case Z_STREAM_ERROR: throw std::runtime_error("inflate(): stream error!"); case Z_NEED_DICT: throw std::runtime_error("inflate(): need dictionary!"); case Z_DATA_ERROR: throw std::runtime_error("inflate(): data error!"); case Z_MEM_ERROR: throw std::runtime_error("inflate(): memory error!"); }; size_t outputSize = size - (size_t)m_inflateStream.avail_out; targetPtr += outputSize; size -= outputSize; if (size > 0 && retval == Z_STREAM_END) throw std::runtime_error("inflate(): attempting to read past the end of the stream!"); } } }; std::ifstream ser_str(filename, std::ios::binary); uint16_t magic_maj, version_maj; ser_str.read((char*)&magic_maj, 2); if (magic_maj != 1052) throw std::runtime_error("corrupt file"); ser_str.read((char*)&version_maj, 2); ser_str.seekg(-4, ser_str.end); uint32_t n_meshes; ser_str.read((char*)&n_meshes, sizeof(n_meshes)); ser_str.seekg(-(sizeof(uint32_t) + (version_maj == 4 ? sizeof(uint64_t) : sizeof(uint32_t)) * n_meshes), ser_str.end); std::vector<uint64_t> mesh_offsets(n_meshes); if (version_maj == 4) ser_str.read((char*)mesh_offsets.data(), n_meshes * sizeof(uint64_t)); else { auto q = std::vector<uint32_t>(n_meshes); ser_str.read((char*)q.data(), n_meshes * sizeof(uint32_t)); for (size_t i = 0; i < n_meshes; i++) mesh_offsets[i] = q[i]; } for (size_t num_submesh = 0; num_submesh < n_meshes; num_submesh++) { ser_str.seekg(mesh_offsets[num_submesh], ser_str.beg); uint16_t magic, version; ser_str.read((char*)&magic, 2); if (magic == 0) break; ser_str.read((char*)&version, 2); if (version != 3 && version != 4) throw std::runtime_error("invalid version in serialized mesh file"); inflateStream comp_str(ser_str); DataPresentFlag flag; comp_str.read(&flag, sizeof(flag)); std::string name = "default"; if (version == 4) { name = ""; char last_read; do { comp_str.read(&last_read, sizeof(last_read)); name += last_read; } while (last_read != 0); } uint64_t nVertices, nTriangles; comp_str.read(&nVertices, sizeof(nVertices)); comp_str.read(&nTriangles, sizeof(nTriangles)); std::vector<Vec3f> positions(nVertices), normals(nVertices), colors(nVertices); std::vector<Vec2f> uvcoords(nVertices); std::vector<uint32_t> indices(nTriangles * 3); bool isSingle = true; auto read_n_vector = [&](int dim, float* buffer) { if (isSingle) comp_str.read((char*)buffer, sizeof(float) * dim * nVertices); else { double* double_storage = (double*)alloca(dim * sizeof(double)); for (size_t i = 0; i < nVertices; i++) { comp_str.read((char*)double_storage, dim * sizeof(double)); for (int j = 0; j < dim; j++) buffer[i * dim + j] = float(double_storage[j]); } } }; read_n_vector(3, (float*)positions.data()); if ((flag & DataPresentFlag::VertexNormals) == DataPresentFlag::VertexNormals) read_n_vector(3, (float*)normals.data()); if ((flag & DataPresentFlag::TextureCoords) == DataPresentFlag::TextureCoords) read_n_vector(2, (float*)uvcoords.data()); else std::fill(uvcoords.begin(), uvcoords.end(), Vec2f(0.0f)); if ((flag & DataPresentFlag::VertexColors) == DataPresentFlag::VertexColors) read_n_vector(3, (float*)colors.data()); comp_str.read((char*)indices.data(), sizeof(uint32_t) * nTriangles * 3); for (size_t i = 0; i < nTriangles * 3; i += 3) std::swap(indices[i + 0], indices[i + 2]); auto compiled_submesh_filename = get_compiled_submesh_filename(num_submesh); FileOutputStream fOut(compiled_submesh_filename); fOut << (unsigned int)MeshCompileType::Static; auto mat = Material(name.size() > 60 ? name.substr(0, 60) : name); mat.bsdf = CreateAggregate<BSDFALL>(diffuse()); Mesh::CompileMesh(positions.data(), (int)positions.size(), normals.data(), uvcoords.data(), indices.data(), (int)indices.size(), mat, 0.0f, fOut, flipNormals, faceNormals, maxSmoothAngle); fOut.Close(); } ser_str.close(); } auto obj = S.scene.CreateNode(get_compiled_submesh_filename(submesh_index)); parseGeneric(obj, node, S); return obj; }