void Model::loaded(FS::IFile& file, bool success, FS::FileSystem& fs) { PROFILE_FUNCTION(); if (success) { FileHeader header; file.read(&header, sizeof(header)); if (header.m_magic == FILE_MAGIC && header.m_version <= (uint32_t)FileVersion::LATEST && parseMeshes(file) && parseGeometry(file) && parseBones(file) && parseLODs(file)) { m_size = file.size(); decrementDepCount(); } else { g_log_warning.log("renderer") << "Error loading model " << m_path.c_str(); onFailure(); return; } } else { g_log_warning.log("renderer") << "Error loading model " << m_path.c_str(); onFailure(); } }
JsonSerializer::JsonSerializer(FS::IFile& file, AccessMode access_mode, const Path& path, IAllocator& allocator) : m_file(file) , m_access_mode(access_mode) , m_allocator(allocator) { m_is_error = false; copyString(m_path, path.c_str()); m_is_first_in_block = true; m_data = nullptr; m_is_string_token = false; if (m_access_mode == READ) { m_data_size = (int)file.size(); if (file.getBuffer() != nullptr) { m_data = (const char*)file.getBuffer(); m_own_data = false; } else { int size = (int)m_file.size(); char* data = (char*)m_allocator.allocate(size); m_own_data = true; file.read(data, m_data_size); m_data = data; } m_token = m_data; m_token_size = 0; deserializeToken(); } }
bool Texture::loadRaw(FS::IFile& file) { PROFILE_FUNCTION(); size_t size = file.size(); m_BPP = 2; m_width = (int)sqrt(size / m_BPP); m_height = m_width; if (m_data_reference) { m_data.resize(size); file.read(&m_data[0], size); } const uint16_t* src_mem = (const uint16_t*)file.getBuffer(); const bgfx::Memory* mem = bgfx::alloc(m_width * m_height * sizeof(float)); float* dst_mem = (float*)mem->data; for (int i = 0; i < m_width * m_height; ++i) { dst_mem[i] = src_mem[i] / 65535.0f; } m_texture_handle = bgfx::createTexture2D( m_width, m_height, 1, bgfx::TextureFormat::R32F, 0, nullptr); bgfx::updateTexture2D( m_texture_handle, 0, 0, 0, m_width, m_height, mem); return bgfx::isValid(m_texture_handle); }
void Texture::save() { char ext[5]; ext[0] = 0; PathUtils::getExtension(ext, 5, getPath().c_str()); if (strcmp(ext, "raw") == 0 && m_BPP == 2) { FS::FileSystem& fs = m_resource_manager.getFileSystem(); FS::IFile* file = fs.open(fs.getDefaultDevice(), getPath().c_str(), FS::Mode::OPEN_OR_CREATE | FS::Mode::WRITE); file->write(&m_data[0], m_data.size() * sizeof(m_data[0])); fs.close(*file); } else if (strcmp(ext, "tga") == 0 && m_BPP == 4) { saveTGA(); } else { g_log_error.log("renderer") << "Texture " << getPath() << " can not be saved - unsupported format"; } }
bool Model::parseVertexDef(FS::IFile& file, bgfx::VertexDecl* vertex_definition) { vertex_definition->begin(); uint32 attribute_count; file.read(&attribute_count, sizeof(attribute_count)); for (uint32 i = 0; i < attribute_count; ++i) { char tmp[50]; uint32 len; file.read(&len, sizeof(len)); if (len > sizeof(tmp) - 1) { return false; } file.read(tmp, len); tmp[len] = '\0'; if (compareString(tmp, "in_position") == 0) { vertex_definition->add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float); } else if (compareString(tmp, "in_colors") == 0) { vertex_definition->add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true, false); } else if (compareString(tmp, "in_tex_coords") == 0) { vertex_definition->add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float); } else if (compareString(tmp, "in_normal") == 0) { vertex_definition->add(bgfx::Attrib::Normal, 4, bgfx::AttribType::Uint8, true, true); } else if (compareString(tmp, "in_tangents") == 0) { vertex_definition->add(bgfx::Attrib::Tangent, 4, bgfx::AttribType::Uint8, true, true); } else if (compareString(tmp, "in_weights") == 0) { vertex_definition->add(bgfx::Attrib::Weight, 4, bgfx::AttribType::Float); } else if (compareString(tmp, "in_indices") == 0) { vertex_definition->add(bgfx::Attrib::Indices, 4, bgfx::AttribType::Int16, false, true); } else { ASSERT(false); return false; } uint32 type; file.read(&type, sizeof(type)); } vertex_definition->end(); return true; }
bool Shader::load(FS::IFile& file) { lua_State* L = luaL_newstate(); luaL_openlibs(L); registerFunctions(this, &m_combintions, &getRenderer(), L); m_render_states = BGFX_STATE_DEPTH_TEST_LEQUAL; bool errors = luaL_loadbuffer(L, (const char*)file.getBuffer(), file.size(), "") != LUA_OK; errors = errors || lua_pcall(L, 0, 0, 0) != LUA_OK; if (errors) { g_log_error.log("Renderer") << getPath().c_str() << ": " << lua_tostring(L, -1); lua_pop(L, 1); return false; } if (!generateInstances()) { g_log_error.log("Renderer") << "Could not load instances of shader " << getPath().c_str(); return false; } m_size = file.size(); lua_close(L); return true; }
bool LuaScript::load(FS::IFile& file) { m_properties.clear(); m_source_code.set((const char*)file.getBuffer(), (int)file.size()); parseProperties(); m_size = file.size(); return true; }
bool ShaderBinary::load(FS::IFile& file) { auto* mem = bgfx::alloc((uint32)file.size() + 1); file.read(mem->data, file.size()); mem->data[file.size()] = '\0'; m_handle = bgfx::createShader(mem); m_size = file.size(); return bgfx::isValid(m_handle); }
bool Texture::loadDDS(FS::IFile& file) { bgfx::TextureInfo info; m_texture_handle = bgfx::createTexture( bgfx::copy(file.getBuffer(), file.size()), 0, 0, &info); m_BPP = -1; m_width = info.width; m_height = info.height; return bgfx::isValid(m_texture_handle); }
bool Clip::load(FS::IFile& file) { short* output = nullptr; auto res = stb_vorbis_decode_memory( (unsigned char*)file.getBuffer(), (int)file.size(), &m_channels, &m_sample_rate, &output); if (res <= 0) return false; m_data.resize(res * m_channels); copyMemory(&m_data[0], output, res * m_channels * sizeof(m_data[0])); free(output); return true; }
bool Model::parseVertexDeclEx(FS::IFile& file, bgfx::VertexDecl* vertex_decl) { vertex_decl->begin(); u32 attribute_count; file.read(&attribute_count, sizeof(attribute_count)); for (u32 i = 0; i < attribute_count; ++i) { i32 attr; file.read(&attr, sizeof(attr)); if (attr == (i32)Attrs::Position) { vertex_decl->add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float); } else if (attr == (i32)Attrs::Color0) { vertex_decl->add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true, false); } else if (attr == (i32)Attrs::TexCoord0) { vertex_decl->add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float); } else if (attr == (i32)Attrs::Normal) { vertex_decl->add(bgfx::Attrib::Normal, 4, bgfx::AttribType::Uint8, true, true); } else if (attr == (i32)Attrs::Tangent) { vertex_decl->add(bgfx::Attrib::Tangent, 4, bgfx::AttribType::Uint8, true, true); } else if (attr == (i32)Attrs::Weight) { vertex_decl->add(bgfx::Attrib::Weight, 4, bgfx::AttribType::Float); } else if (attr == (i32)Attrs::Indices) { vertex_decl->add(bgfx::Attrib::Indices, 4, bgfx::AttribType::Int16, false, true); } else { ASSERT(false); return false; } } vertex_decl->end(); return true; }
bool Texture::load(FS::IFile& file) { PROFILE_FUNCTION(); const char* path = getPath().c_str(); size_t len = getPath().length(); bool loaded = false; if (len > 3 && compareString(path + len - 4, ".dds") == 0) { loaded = loadDDS(file); } else if (len > 3 && compareString(path + len - 4, ".raw") == 0) { loaded = loadRaw(file); } else { loaded = loadTGA(file); } if (!loaded) { g_log_warning.log("Renderer") << "Error loading texture " << path; return false; } m_size = file.size(); return true; }
bool Model::parseLODs(FS::IFile& file) { i32 lod_count; file.read(&lod_count, sizeof(lod_count)); if (lod_count <= 0 || lod_count > lengthOf(m_lods)) { return false; } for (int i = 0; i < lod_count; ++i) { file.read(&m_lods[i].to_mesh, sizeof(m_lods[i].to_mesh)); file.read(&m_lods[i].distance, sizeof(m_lods[i].distance)); m_lods[i].from_mesh = i > 0 ? m_lods[i - 1].to_mesh + 1 : 0; } return true; }
void LuaScript::loaded(FS::IFile& file, bool success, FS::FileSystem& fs) { if (success) { m_source_code.set((const char*)file.getBuffer(), file.size()); parseProperties(); m_size = file.size(); decrementDepCount(); } else { g_log_error.log("lua_script") << "Could not load script " << m_path.c_str(); onFailure(); } }
bool Model::parseLODs(FS::IFile& file) { int32 lod_count; file.read(&lod_count, sizeof(lod_count)); if (lod_count <= 0) { return false; } m_lods.resize(lod_count); for (int i = 0; i < lod_count; ++i) { file.read(&m_lods[i].m_to_mesh, sizeof(m_lods[i].m_to_mesh)); file.read(&m_lods[i].m_distance, sizeof(m_lods[i].m_distance)); m_lods[i].m_from_mesh = i > 0 ? m_lods[i - 1].m_to_mesh + 1 : 0; } return true; }
bool Model::load(FS::IFile& file) { PROFILE_FUNCTION(); FileHeader header; file.read(&header, sizeof(header)); if (header.m_magic == FILE_MAGIC && header.m_version <= (uint32)FileVersion::LATEST && parseMeshes(file) && parseGeometry(file) && parseBones(file) && parseLODs(file)) { m_size = file.size(); return true; } g_log_warning.log("renderer") << "Error loading model " << getPath().c_str(); return false; }
bool Model::load(FS::IFile& file) { PROFILE_FUNCTION(); FileHeader header; file.read(&header, sizeof(header)); if (header.magic != FILE_MAGIC) { g_log_warning.log("Renderer") << "Corrupted model " << getPath().c_str(); return false; } if(header.version > (u32)FileVersion::LATEST) { g_log_warning.log("Renderer") << "Unsupported version of model " << getPath().c_str(); return false; } u32 global_flags = 0; // backward compatibility if(header.version > (u32)FileVersion::WITH_FLAGS) { file.read(&global_flags, sizeof(global_flags)); } bgfx::VertexDecl global_vertex_decl; if (header.version > (u32)FileVersion::SINGLE_VERTEX_DECL && header.version <= (u32)FileVersion::MULTIPLE_VERTEX_DECLS) { parseVertexDeclEx(file, &global_vertex_decl); } if (parseMeshes(global_vertex_decl, file, (FileVersion)header.version, global_flags) && parseBones(file) && parseLODs(file)) { m_size = file.size(); return true; } g_log_error.log("Renderer") << "Error loading model " << getPath().c_str(); return false; }
bool Model::parseGeometry(FS::IFile& file) { int32_t indices_count = 0; file.read(&indices_count, sizeof(indices_count)); if (indices_count <= 0) { return false; } m_indices.resize(indices_count); file.read(&m_indices[0], sizeof(m_indices[0]) * indices_count); int32_t vertices_size = 0; file.read(&vertices_size, sizeof(vertices_size)); if (vertices_size <= 0) { return false; } Array<uint8_t> vertices(m_allocator); vertices.resize(vertices_size); file.read(&vertices[0], sizeof(vertices[0]) * vertices.size()); m_geometry_buffer_object.setAttributesData( &vertices[0], vertices.size(), m_meshes[0].getVertexDefinition()); m_geometry_buffer_object.setIndicesData( &m_indices[0], m_indices.size() * sizeof(m_indices[0])); int vertex_count = 0; for (int i = 0; i < m_meshes.size(); ++i) { vertex_count += m_meshes[i].getAttributeArraySize() / m_meshes[i].getVertexDefinition().getStride(); } m_vertices.resize(vertex_count); computeRuntimeData(&vertices[0]); return true; }
bool Model::parseGeometry(FS::IFile& file) { int32 indices_count = 0; file.read(&indices_count, sizeof(indices_count)); if (indices_count <= 0) return false; m_indices.resize(indices_count); file.read(&m_indices[0], sizeof(m_indices[0]) * indices_count); int32 vertices_size = 0; file.read(&vertices_size, sizeof(vertices_size)); if (vertices_size <= 0) return false; ASSERT(!bgfx::isValid(m_vertices_handle)); const bgfx::Memory* vertices_mem = bgfx::alloc(vertices_size); file.read(vertices_mem->data, vertices_size); m_vertices_handle = bgfx::createVertexBuffer(vertices_mem, m_meshes[0].getVertexDefinition()); m_vertices_size = vertices_size; ASSERT(!bgfx::isValid(m_indices_handle)); m_indices_size = sizeof(m_indices[0]) * indices_count; const bgfx::Memory* mem = bgfx::copy(&m_indices[0], m_indices_size); m_indices_handle = bgfx::createIndexBuffer(mem, BGFX_BUFFER_INDEX32); int vertex_count = 0; for (int i = 0; i < m_meshes.size(); ++i) { vertex_count += m_meshes[i].getAttributeArraySize() / m_meshes[i].getVertexDefinition().getStride(); } m_vertices.resize(vertex_count); computeRuntimeData(vertices_mem->data); return true; }
void Texture::loaded(FS::IFile& file, bool success, FS::FileSystem& fs) { PROFILE_FUNCTION(); if (success) { const char* path = m_path.c_str(); size_t len = m_path.length(); bool loaded = false; if (len > 3 && strcmp(path + len - 4, ".dds") == 0) { loaded = loadDDS(file); } else if (len > 3 && strcmp(path + len - 4, ".raw") == 0) { loaded = loadRaw(file); } else { loaded = loadTGA(file); } if (!loaded) { g_log_warning.log("renderer") << "Error loading texture " << m_path.c_str(); onFailure(); } else { m_size = file.size(); decrementDepCount(); } } else { g_log_warning.log("renderer") << "Error loading texture " << m_path.c_str(); onFailure(); } }
void Animation::loaded(FS::IFile& file, bool success, FS::FileSystem& fs) { if (success) { IAllocator& allocator = getAllocator(); allocator.deallocate(m_positions); allocator.deallocate(m_rotations); allocator.deallocate(m_bones); m_positions = nullptr; m_rotations = nullptr; m_bones = 0; m_frame_count = m_bone_count = 0; Header header; file.read(&header, sizeof(header)); if (header.magic != HEADER_MAGIC) { onFailure(); g_log_error.log("animation") << m_path.c_str() << " is not an animation file"; return; } if (header.version > 1) { onFailure(); g_log_error.log("animation") << "Unsupported animation version " << header.version << " (" << m_path.c_str() << ")"; return; } m_fps = header.fps; file.read(&m_frame_count, sizeof(m_frame_count)); file.read(&m_bone_count, sizeof(m_bone_count)); m_positions = static_cast<Vec3*>(allocator.allocate(sizeof(Vec3) * m_frame_count * m_bone_count)); m_rotations = static_cast<Quat*>(allocator.allocate(sizeof(Quat) * m_frame_count * m_bone_count)); m_bones = static_cast<uint32_t*>(allocator.allocate(sizeof(uint32_t) * m_bone_count)); file.read(&m_positions[0], sizeof(Vec3)* m_bone_count * m_frame_count); file.read(&m_rotations[0], sizeof(Quat)* m_bone_count * m_frame_count); file.read(m_bones, sizeof(m_bones[0]) * m_bone_count); m_size = file.size(); decrementDepCount(); } else { onFailure(); } }
bool Animation::load(FS::IFile& file) { IAllocator& allocator = getAllocator(); allocator.deallocate(m_positions); allocator.deallocate(m_rotations); allocator.deallocate(m_bones); m_positions = nullptr; m_rotations = nullptr; m_bones = nullptr; m_frame_count = m_bone_count = 0; Header header; file.read(&header, sizeof(header)); if (header.magic != HEADER_MAGIC) { g_log_error.log("Animation") << getPath() << " is not an animation file"; return false; } if (header.version > 1) { g_log_error.log("Animation") << "Unsupported animation version " << header.version << " (" << getPath() << ")"; return false; } m_fps = header.fps; file.read(&m_frame_count, sizeof(m_frame_count)); file.read(&m_bone_count, sizeof(m_bone_count)); m_positions = static_cast<Vec3*>(allocator.allocate(sizeof(Vec3) * m_frame_count * m_bone_count)); m_rotations = static_cast<Quat*>(allocator.allocate(sizeof(Quat) * m_frame_count * m_bone_count)); m_bones = static_cast<uint32*>(allocator.allocate(sizeof(uint32) * m_bone_count)); file.read(&m_positions[0], sizeof(Vec3)* m_bone_count * m_frame_count); file.read(&m_rotations[0], sizeof(Quat)* m_bone_count * m_frame_count); file.read(m_bones, sizeof(m_bones[0]) * m_bone_count); m_size = file.size(); return true; }
bool Material::load(FS::IFile& file) { PROFILE_FUNCTION(); m_render_states = BGFX_STATE_DEPTH_TEST_LEQUAL | BGFX_STATE_CULL_CW; m_uniforms.clear(); JsonSerializer serializer(file, JsonSerializer::READ, getPath().c_str(), m_allocator); serializer.deserializeObjectBegin(); char path[MAX_PATH_LENGTH]; char label[256]; char material_dir[MAX_PATH_LENGTH]; PathUtils::getDir(material_dir, MAX_PATH_LENGTH, getPath().c_str()); bool b_value; while (!serializer.isObjectEnd()) { serializer.deserializeLabel(label, 255); if (compareString(label, "uniforms") == 0) { deserializeUniforms(serializer); } else if (compareString(label, "texture") == 0) { if (!deserializeTexture(serializer, material_dir)) { return false; } } else if (compareString(label, "alpha_cutout") == 0) { bool b; serializer.deserialize(b, false); enableAlphaCutout(b); } else if (compareString(label, "alpha_blending") == 0) { if (serializer.isNextBoolean()) { bool is_alpha_blending; serializer.deserialize(is_alpha_blending, false); if (is_alpha_blending) { m_render_states |= BGFX_STATE_BLEND_ADD; } else { m_render_states &= ~BGFX_STATE_BLEND_MASK; } } else { serializer.deserialize(label, 255, "alpha"); if (compareString(label, "alpha") == 0) { m_render_states |= BGFX_STATE_BLEND_ALPHA; } else if (compareString(label, "add") == 0) { m_render_states |= BGFX_STATE_BLEND_ADD; } else if (compareString(label, "disabled") == 0) { m_render_states &= ~BGFX_STATE_BLEND_MASK; } } } else if (compareString(label, "specular") == 0) { serializer.deserializeArrayBegin(); serializer.deserializeArrayItem(m_specular.x, 1.0f); serializer.deserializeArrayItem(m_specular.y, 1.0f); serializer.deserializeArrayItem(m_specular.z, 1.0f); serializer.deserializeArrayEnd(); } else if (compareString(label, "shininess") == 0) { serializer.deserialize(m_shininess, 4.0f); } else if (compareString(label, "shadow_receiver") == 0) { bool b; serializer.deserialize(b, true); enableShadowReceiving(b); } else if (compareString(label, "shader") == 0) { serializer.deserialize(path, MAX_PATH_LENGTH, ""); setShader(static_cast<Shader*>( m_resource_manager.get(ResourceManager::SHADER)->load(Path(path)))); } else if (compareString(label, "z_test") == 0) { serializer.deserialize(b_value, true); enableZTest(b_value); } else if (compareString(label, "backface_culling") == 0) { serializer.deserialize(b_value, true); enableBackfaceCulling(b_value); } else { g_log_warning.log("renderer") << "Unknown parameter " << label << " in material " << getPath().c_str(); } } serializer.deserializeObjectEnd(); if (!m_shader) { g_log_error.log("renderer") << "Material " << getPath().c_str() << " without a shader"; return false; } m_size = file.size(); return true; }
bool PhysicsGeometry::load(FS::IFile& file) { Header header; file.read(&header, sizeof(header)); if (header.m_magic != HEADER_MAGIC || header.m_version > (uint32)Versions::LAST) { return false; } auto* phy_manager = m_resource_manager.get(ResourceManager::PHYSICS); PhysicsSystem& system = static_cast<PhysicsGeometryManager*>(phy_manager)->getSystem(); uint32 num_verts; Array<Vec3> verts(getAllocator()); file.read(&num_verts, sizeof(num_verts)); verts.resize(num_verts); file.read(&verts[0], sizeof(verts[0]) * verts.size()); m_is_convex = header.m_convex != 0; if (!m_is_convex) { physx::PxTriangleMeshGeometry* geom = LUMIX_NEW(getAllocator(), physx::PxTriangleMeshGeometry)(); m_geometry = geom; uint32 num_indices; Array<uint32> tris(getAllocator()); file.read(&num_indices, sizeof(num_indices)); tris.resize(num_indices); file.read(&tris[0], sizeof(tris[0]) * tris.size()); physx::PxTriangleMeshDesc meshDesc; meshDesc.points.count = num_verts; meshDesc.points.stride = sizeof(physx::PxVec3); meshDesc.points.data = &verts[0]; meshDesc.triangles.count = num_indices / 3; meshDesc.triangles.stride = 3 * sizeof(physx::PxU32); meshDesc.triangles.data = &tris[0]; OutputStream writeBuffer(getAllocator()); system.getCooking()->cookTriangleMesh(meshDesc, writeBuffer); InputStream readBuffer(writeBuffer.data, writeBuffer.size); geom->triangleMesh = system.getPhysics()->createTriangleMesh(readBuffer); } else { physx::PxConvexMeshGeometry* geom = LUMIX_NEW(getAllocator(), physx::PxConvexMeshGeometry)(); m_geometry = geom; physx::PxConvexMeshDesc meshDesc; meshDesc.points.count = verts.size(); meshDesc.points.stride = sizeof(Vec3); meshDesc.points.data = &verts[0]; meshDesc.flags = physx::PxConvexFlag::eCOMPUTE_CONVEX; OutputStream writeBuffer(getAllocator()); bool status = system.getCooking()->cookConvexMesh(meshDesc, writeBuffer); if (!status) { LUMIX_DELETE(getAllocator(), geom); m_geometry = nullptr; return false; } InputStream readBuffer(writeBuffer.data, writeBuffer.size); physx::PxConvexMesh* mesh = system.getPhysics()->createConvexMesh(readBuffer); geom->convexMesh = mesh; } m_size = file.size(); return true; }
bool Model::parseBones(FS::IFile& file) { int bone_count; file.read(&bone_count, sizeof(bone_count)); if (bone_count < 0) return false; if (bone_count > Bone::MAX_COUNT) { g_log_warning.log("Renderer") << "Model " << getPath().c_str() << " has too many bones."; return false; } m_bones.reserve(bone_count); for (int i = 0; i < bone_count; ++i) { Model::Bone& b = m_bones.emplace(m_allocator); int len; file.read(&len, sizeof(len)); char tmp[MAX_PATH_LENGTH]; if (len >= MAX_PATH_LENGTH) { return false; } file.read(tmp, len); tmp[len] = 0; b.name = tmp; m_bone_map.insert(crc32(b.name.c_str()), m_bones.size() - 1); file.read(&len, sizeof(len)); if (len >= MAX_PATH_LENGTH) { return false; } if(len > 0) { file.read(tmp, len); tmp[len] = 0; b.parent = tmp; } else { b.parent = ""; } file.read(&b.transform.pos.x, sizeof(float) * 3); file.read(&b.transform.rot.x, sizeof(float) * 4); } m_first_nonroot_bone_index = -1; for (int i = 0; i < bone_count; ++i) { Model::Bone& b = m_bones[i]; if (b.parent.length() == 0) { if (m_first_nonroot_bone_index != -1) { g_log_error.log("Renderer") << "Invalid skeleton in " << getPath().c_str(); return false; } b.parent_idx = -1; } else { b.parent_idx = getBoneIdx(b.parent.c_str()); if (b.parent_idx > i || b.parent_idx < 0) { g_log_error.log("Renderer") << "Invalid skeleton in " << getPath().c_str(); return false; } if (m_first_nonroot_bone_index == -1) { m_first_nonroot_bone_index = i; } } } for (int i = 0; i < m_bones.size(); ++i) { m_bones[i].inv_bind_transform = m_bones[i].transform.inverted(); } for (int i = 0; i < m_bones.size(); ++i) { int p = m_bones[i].parent_idx; if (p >= 0) { m_bones[i].relative_transform = m_bones[p].inv_bind_transform * m_bones[i].transform; } else { m_bones[i].relative_transform = m_bones[i].transform; } } return true; }
bool Model::parseMeshes(const bgfx::VertexDecl& global_vertex_decl, FS::IFile& file, FileVersion version, u32 global_flags) { if (version <= FileVersion::MULTIPLE_VERTEX_DECLS) return parseMeshesOld(global_vertex_decl, file, version, global_flags); int object_count = 0; file.read(&object_count, sizeof(object_count)); if (object_count <= 0) return false; char model_dir[MAX_PATH_LENGTH]; PathUtils::getDir(model_dir, MAX_PATH_LENGTH, getPath().c_str()); m_meshes.reserve(object_count); for (int i = 0; i < object_count; ++i) { bgfx::VertexDecl vertex_decl; if (!parseVertexDeclEx(file, &vertex_decl)) return false; 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))); file.read(&str_size, sizeof(str_size)); char mesh_name[MAX_PATH_LENGTH]; mesh_name[str_size] = 0; file.read(mesh_name, str_size); m_meshes.emplace(material, vertex_decl, mesh_name, m_allocator); addDependency(*material); } for (int i = 0; i < object_count; ++i) { Mesh& mesh = m_meshes[i]; int index_size; int indices_count; file.read(&index_size, sizeof(index_size)); if (index_size != 2 && index_size != 4) return false; file.read(&indices_count, sizeof(indices_count)); if (indices_count <= 0) return false; mesh.indices.resize(index_size * indices_count); file.read(&mesh.indices[0], mesh.indices.size()); if (index_size == 2) mesh.flags.set(Mesh::Flags::INDICES_16_BIT); mesh.indices_count = indices_count; const bgfx::Memory* indices_mem = bgfx::copy(&mesh.indices[0], mesh.indices.size()); mesh.index_buffer_handle = bgfx::createIndexBuffer(indices_mem); } for (int i = 0; i < object_count; ++i) { Mesh& mesh = m_meshes[i]; int data_size; file.read(&data_size, sizeof(data_size)); const bgfx::Memory* vertices_mem = bgfx::alloc(data_size); file.read(vertices_mem->data, vertices_mem->size); const bgfx::VertexDecl& vertex_decl = mesh.vertex_decl; int position_attribute_offset = vertex_decl.getOffset(bgfx::Attrib::Position); int uv_attribute_offset = vertex_decl.getOffset(bgfx::Attrib::TexCoord0); int weights_attribute_offset = vertex_decl.getOffset(bgfx::Attrib::Weight); int bone_indices_attribute_offset = vertex_decl.getOffset(bgfx::Attrib::Indices); bool keep_skin = vertex_decl.has(bgfx::Attrib::Weight) && vertex_decl.has(bgfx::Attrib::Indices); int vertex_size = mesh.vertex_decl.getStride(); int mesh_vertex_count = vertices_mem->size / mesh.vertex_decl.getStride(); mesh.vertices.resize(mesh_vertex_count); mesh.uvs.resize(mesh_vertex_count); if (keep_skin) mesh.skin.resize(mesh_vertex_count); const u8* vertices = vertices_mem->data; for (int j = 0; j < mesh_vertex_count; ++j) { int 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]; } mesh.vertex_buffer_handle = bgfx::createVertexBuffer(vertices_mem, mesh.vertex_decl); } file.read(&m_bounding_radius, sizeof(m_bounding_radius)); file.read(&m_aabb, sizeof(m_aabb)); return true; }
bool Model::parseMeshes(FS::IFile& file) { 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()); for (int i = 0; i < object_count; ++i) { int32 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.get(ResourceManager::MATERIAL); Material* material = static_cast<Material*>(material_manager->load(Path(material_path))); int32 attribute_array_offset = 0; file.read(&attribute_array_offset, sizeof(attribute_array_offset)); int32 attribute_array_size = 0; file.read(&attribute_array_size, sizeof(attribute_array_size)); int32 indices_offset = 0; file.read(&indices_offset, sizeof(indices_offset)); int32 mesh_tri_count = 0; file.read(&mesh_tri_count, sizeof(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 def; parseVertexDef(file, &def); m_meshes.emplace(def, material, attribute_array_offset, attribute_array_size, indices_offset, mesh_tri_count * 3, mesh_name, m_allocator); addDependency(*material); } return true; }
bool Model::parseBones(FS::IFile& file) { int bone_count; file.read(&bone_count, sizeof(bone_count)); if (bone_count < 0) { return false; } m_bones.reserve(bone_count); for (int i = 0; i < bone_count; ++i) { Model::Bone& b = m_bones.emplace(m_allocator); int len; file.read(&len, sizeof(len)); char tmp[MAX_PATH_LENGTH]; if (len >= MAX_PATH_LENGTH) { return false; } file.read(tmp, len + 1); tmp[len] = 0; b.name = tmp; m_bone_map.insert(crc32(b.name.c_str()), m_bones.size() - 1); file.read(&len, sizeof(len)); if (len >= MAX_PATH_LENGTH) { return false; } if(len > 0) { file.read(tmp, len); tmp[len] = 0; b.parent = tmp; } else { b.parent = ""; } file.read(&b.position.x, sizeof(float) * 3); file.read(&b.rotation.x, sizeof(float) * 4); } m_first_nonroot_bone_index = -1; for (int i = 0; i < bone_count; ++i) { Model::Bone& b = m_bones[i]; if (b.parent.length() == 0) { b.parent_idx = -1; } else { b.parent_idx = getBoneIdx(b.parent.c_str()); if (b.parent_idx > i || b.parent_idx < 0) { g_log_error.log("renderer") << "Invalid skeleton in " << getPath().c_str(); return false; } if (m_first_nonroot_bone_index == -1) { m_first_nonroot_bone_index = i; } } } for (int i = 0; i < m_bones.size(); ++i) { m_bones[i].rotation.toMatrix(m_bones[i].inv_bind_matrix); m_bones[i].inv_bind_matrix.translate(m_bones[i].position); } for (int i = 0; i < m_bones.size(); ++i) { m_bones[i].inv_bind_matrix.fastInverse(); } return true; }
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; }
bool Texture::loadTGA(FS::IFile& file) { PROFILE_FUNCTION(); TGAHeader header; file.read(&header, sizeof(header)); int color_mode = header.bitsPerPixel / 8; int image_size = header.width * header.height * 4; if (header.dataType != 2) { g_log_error.log("renderer") << "Unsupported texture format " << m_path.c_str(); return false; } if (color_mode < 3) { g_log_error.log("renderer") << "Unsupported color mode " << m_path.c_str(); return false; } m_width = header.width; m_height = header.height; TextureManager* manager = static_cast<TextureManager*>( getResourceManager().get(ResourceManager::TEXTURE)); if (m_data_reference) { m_data.resize(image_size); } uint8_t* image_dest = m_data_reference ? &m_data[0] : (uint8_t*)manager->getBuffer(image_size); // Targa is BGR, swap to RGB, add alpha and flip Y axis for (long y = 0; y < header.height; y++) { long read_index = y * header.width * color_mode; long write_index = ((header.imageDescriptor & 32) != 0) ? read_index : y * header.width * 4; for (long x = 0; x < header.width; x++) { file.read(&image_dest[write_index + 2], sizeof(uint8_t)); file.read(&image_dest[write_index + 1], sizeof(uint8_t)); file.read(&image_dest[write_index + 0], sizeof(uint8_t)); if (color_mode == 4) file.read(&image_dest[write_index + 3], sizeof(uint8_t)); else image_dest[write_index + 3] = 255; write_index += 4; } } m_BPP = 4; m_texture_handle = bgfx::createTexture2D( header.width, header.height, 1, bgfx::TextureFormat::RGBA8, m_flags, 0); bgfx::updateTexture2D( m_texture_handle, 0, 0, 0, header.width, header.height, bgfx::copy(image_dest, header.width * header.height * 4)); m_depth = 1; return bgfx::isValid(m_texture_handle); }