diff options
-rw-r--r-- | o3d/converter/cross/converter.cc | 6 | ||||
-rw-r--r-- | o3d/converter/cross/converter.h | 5 | ||||
-rw-r--r-- | o3d/converter/cross/converter_main.cc | 12 | ||||
-rw-r--r-- | o3d/import/cross/collada.cc | 77 | ||||
-rw-r--r-- | o3d/import/cross/collada.h | 49 | ||||
-rw-r--r-- | o3d/utils/cross/file_path_utils.cc | 53 | ||||
-rw-r--r-- | o3d/utils/cross/file_path_utils.h | 21 | ||||
-rw-r--r-- | o3d/utils/cross/file_path_utils_test.cc | 52 |
8 files changed, 233 insertions, 42 deletions
diff --git a/o3d/converter/cross/converter.cc b/o3d/converter/cross/converter.cc index 497b8cd..9abde79 100644 --- a/o3d/converter/cross/converter.cc +++ b/o3d/converter/cross/converter.cc @@ -66,11 +66,12 @@ namespace o3d { namespace { void AddBinaryElements(const Collada& collada, TarGzGenerator* archive_generator) { - std::vector<FilePath> paths = collada.GetOriginalDataFilenames(); + const ColladaDataMap& data_map(collada.original_data_map()); + std::vector<FilePath> paths = data_map.GetOriginalDataFilenames(); for (std::vector<FilePath>::const_iterator iter = paths.begin(); iter != paths.end(); ++iter) { - const std::string& data = collada.GetOriginalData(*iter); + const std::string& data = data_map.GetOriginalData(*iter); archive_generator->AddFile(FilePathToUTF8(*iter), data.size()); archive_generator->AddFileBytes( @@ -120,6 +121,7 @@ bool Convert(const FilePath& in_filename, collada_options.condition_document = options.condition; collada_options.keep_original_data = true; collada_options.base_path = options.base_path; + collada_options.file_paths = options.file_paths; collada_options.up_axis = options.up_axis; Collada collada(pack.Get(), collada_options); bool result = collada.ImportFile(in_filename, root, param_float); diff --git a/o3d/converter/cross/converter.h b/o3d/converter/cross/converter.h index dd0141c..d613564 100644 --- a/o3d/converter/cross/converter.h +++ b/o3d/converter/cross/converter.h @@ -38,8 +38,10 @@ #ifndef O3D_CONVERTER_CROSS_CONVERTER_H_ #define O3D_CONVERTER_CROSS_CONVERTER_H_ +#include <vector> #include "base/file_path.h" #include "core/cross/types.h" +#include "utils/cross/file_path_utils.h" namespace o3d { namespace converter { @@ -55,6 +57,9 @@ struct Options { keep_materials(false) { } + // A list of paths to search for assets.. + std::vector<FilePath> file_paths; + // The path to the "base" of the model path, from which all paths // are made relative. Defaults to the current directory. FilePath base_path; diff --git a/o3d/converter/cross/converter_main.cc b/o3d/converter/cross/converter_main.cc index 650e0b7..e332db4 100644 --- a/o3d/converter/cross/converter_main.cc +++ b/o3d/converter/cross/converter_main.cc @@ -40,6 +40,7 @@ #include "base/at_exit.h" #include "base/command_line.h" #include "base/file_path.h" +#include "base/string_util.h" #include "converter/cross/converter.h" #include "utils/cross/file_path_utils.h" @@ -86,7 +87,9 @@ int CrossMain(int argc, char**argv) { << "--no-condition\n" << " Stops the converter from conditioning shaders.\n" << "--base-path=<path>\n" - << " Sets the base path for finding textures and other external\n" + << " Sets the path to remove from URIs of external files\n" + << "--asset-paths=<comma separted list of paths>\n" + << " Sets the paths for finding textures and other external\n" << " files.\n" << "--up-axis=x,y,z\n" << " Converts the file to have this up axis.\n" @@ -108,6 +111,13 @@ int CrossMain(int argc, char**argv) { options.base_path = o3d::WideToFilePath( command_line->GetSwitchValue(L"base-path")); } + if (command_line->HasSwitch(L"asset-paths")) { + std::vector<std::wstring> paths; + SplitString(command_line->GetSwitchValue(L"asset-paths"), ',', &paths); + for (size_t ii = 0; ii < paths.size(); ++ii) { + options.file_paths.push_back(o3d::WideToFilePath(paths[ii])); + } + } if (command_line->HasSwitch(L"up-axis")) { wstring up_axis_string = command_line->GetSwitchValue(L"up-axis"); int x, y, z; diff --git a/o3d/import/cross/collada.cc b/o3d/import/cross/collada.cc index fa06c70..0e88ae2 100644 --- a/o3d/import/cross/collada.cc +++ b/o3d/import/cross/collada.cc @@ -126,6 +126,44 @@ Matrix4 FMMatrix44ToMatrix4(const FMMatrix44& fmmatrix44) { } } // anonymous namespace +void ColladaDataMap::Clear() { + original_data_.clear(); +} + +bool ColladaDataMap::AddData(const FilePath& file_path, + const std::string& data, + ServiceLocator* service_locator) { + std::pair<OriginalDataMap::iterator, bool> result = + original_data_.insert(std::pair<FilePath, std::string>(file_path, data)); + if (!result.second) { + O3D_ERROR(service_locator) + << "Attempt to map 2 resources to the same file path:" + << FilePathToUTF8(file_path).c_str(); + } + return result.second; +} + +std::vector<FilePath> ColladaDataMap::GetOriginalDataFilenames() const { + std::vector<FilePath> result; + for (OriginalDataMap::const_iterator iter = original_data_.begin(); + iter != original_data_.end(); + ++iter) { + result.push_back(iter->first); + } + return result; +} + +const std::string& ColladaDataMap::GetOriginalData( + const FilePath& filename) const { + static const std::string empty; + OriginalDataMap::const_iterator entry = original_data_.find(filename); + if (entry != original_data_.end()) { + return entry->second; + } else { + return empty; + } +} + // Import the given COLLADA file or ZIP file into the given scene. // This is the external interface to o3d. bool Collada::Import(Pack* pack, @@ -178,7 +216,7 @@ Collada::~Collada() { void Collada::ClearData() { textures_.clear(); - original_data_.clear(); + original_data_map_.Clear(); effects_.clear(); shapes_.clear(); skinned_shapes_.clear(); @@ -194,26 +232,6 @@ void Collada::ClearData() { unique_filename_counter_ = 0; } -std::vector<FilePath> Collada::GetOriginalDataFilenames() const { - std::vector<FilePath> result; - for (OriginalDataMap::const_iterator iter = original_data_.begin(); - iter != original_data_.end(); - ++iter) { - result.push_back(iter->first); - } - return result; -} - -const std::string& Collada::GetOriginalData(const FilePath& filename) const { - static const std::string empty; - OriginalDataMap::const_iterator entry = original_data_.find(filename); - if (entry != original_data_.end()) { - return entry->second; - } else { - return empty; - } -} - // Import the given COLLADA file or ZIP file under the given parent node. // Parameters: // filename: The COLLADA or ZIPped COLLADA file to import. @@ -1660,6 +1678,11 @@ Texture* Collada::BuildTextureFromImage(FCDImage* image) { GetRelativePathIfPossible(base_path_, uri, &uri); } + if (!FindFile(options_.file_paths, file_path, &file_path)) { + O3D_ERROR(service_locator_) << "Could not find file: " << filename; + return NULL; + } + tex = Texture::Ref( pack_->CreateTextureFromFile(FilePathToUTF8(uri), file_path, @@ -1674,7 +1697,7 @@ Texture* Collada::BuildTextureFromImage(FCDImage* image) { // Cache the original data by URI so we can recover it later. std::string contents; file_util::ReadFileToString(file_path, &contents); - original_data_[uri] = contents; + original_data_map_.AddData(uri, contents, service_locator_); } if (tempfile.size() > 0) ZipArchive::DeleteFile(tempfile); @@ -1984,7 +2007,10 @@ Effect* Collada::BuildEffect(FCDocument* doc, FCDEffect* collada_effect) { } } else { FilePath temp_path = file_path; - GetRelativePathIfPossible(base_path_, temp_path, &temp_path); + if (!FindFile(options_.file_paths, temp_path, &temp_path)) { + O3D_ERROR(service_locator_) << "Could not find file: " << path; + return NULL; + } file_util::ReadFileToString(temp_path, &effect_string); } } @@ -2007,7 +2033,7 @@ Effect* Collada::BuildEffect(FCDocument* doc, FCDEffect* collada_effect) { } if (options_.keep_original_data) { // Cache the original data by URI so we can recover it later. - original_data_[file_path] = effect_string; + original_data_map_.AddData(file_path, effect_string, service_locator_); } } } else { @@ -2076,7 +2102,8 @@ Effect* Collada::BuildEffect(FCDocument* doc, FCDEffect* collada_effect) { } if (options_.keep_original_data) { // Cache the original data by URI so we can recover it later. - original_data_[file_path] = effect_string; + original_data_map_.AddData(file_path, effect_string, + service_locator_); } } } diff --git a/o3d/import/cross/collada.h b/o3d/import/cross/collada.h index a102e08..c2f659f 100644 --- a/o3d/import/cross/collada.h +++ b/o3d/import/cross/collada.h @@ -41,6 +41,7 @@ #include "base/file_path.h" #include "core/cross/param.h" #include "core/cross/types.h" +#include "utils/cross/file_path_utils.h" class FCDocument; class FCDAnimated; @@ -127,6 +128,31 @@ class NodeInstance { std::vector<NodeInstance *> children_; }; +class ColladaDataMap { + public: + // Adds a data to a filepath. Note, it is an error to associate more than one + // data to the same filepath. + bool AddData(const FilePath& file_path, + const std::string& data, + ServiceLocator* service_locator); + + // Access to the filenames of the original data for texture and + // sound assets imported when ImportFile was called. These will + // only return results after an import if the keep_original_data + // option was set to true when the Collada object was created. + std::vector<FilePath> GetOriginalDataFilenames() const; + const std::string& GetOriginalData(const FilePath& filename) const; + + // Clears the map. + void Clear(); + + private: + // A map containing the original data (still in original format) + // used to create the textures, sounds, etc., indexed by filename. + typedef std::map<FilePath, std::string> OriginalDataMap; + OriginalDataMap original_data_; +}; + class Collada { public: struct Options { @@ -153,6 +179,9 @@ class Collada { // The base path to use for determining the relative paths for // asset URIs. FilePath base_path; + + // A List of paths to search for files in. + std::vector<FilePath> file_paths; }; // Collada Param Names. @@ -215,16 +244,13 @@ class Collada { bool ImportFile(const FilePath& filename, Transform* parent, ParamFloat* animation_input); - // Access to the filenames of the original data for texture and - // sound assets imported when ImportFile was called. These will - // only return results after an import if the keep_original_data - // option was set to true when the Collada object was created. - std::vector<FilePath> GetOriginalDataFilenames() const; - const std::string& GetOriginalData(const FilePath& filename) const; - // Init the Collada Importer. static void Init(ServiceLocator* service_locator); + const ColladaDataMap& original_data_map() const { + return original_data_map_; + } + private: // Imports the given ZIP file into the given pack. bool ImportZIP(const FilePath& filename, Transform* parent, @@ -429,11 +455,6 @@ class Collada { // A map of the Textures created by the importer, indexed by filename. std::map<const std::wstring, Texture*> textures_; - // A map containing the original data (still in original format) - // used to create the textures, sounds, etc., indexed by filename. - typedef std::map<FilePath, std::string> OriginalDataMap; - OriginalDataMap original_data_; - // A map of the Effects created by the importer, indexed by DAE id. std::map<const std::string, Effect*> effects_; @@ -453,7 +474,11 @@ class Collada { // determining the relative paths to other files. FilePath base_path_; + // Original data by FilePath + ColladaDataMap original_data_map_; + ColladaZipArchive *collada_zip_archive_; + // Some temporaries used by the state importer bool cull_enabled_; bool cull_front_; diff --git a/o3d/utils/cross/file_path_utils.cc b/o3d/utils/cross/file_path_utils.cc index db4216e..910c3a6 100644 --- a/o3d/utils/cross/file_path_utils.cc +++ b/o3d/utils/cross/file_path_utils.cc @@ -158,4 +158,57 @@ bool GetRelativePathIfPossible(const FilePath& base_dir, } } +namespace { // anonymous namespace. + +// Tries to find a file path_to_find in path_to_search. Will start with +// base name and progressively try each higher path. Example: +// +// FindFile('this/that', 'foo/bar/baf.txt'); +// +// Looks for: +// this/that/foo/bar/baf.txt +// this/that/bar/baf.txt +// this/that/baf.txt +bool FindFileHelper(const FilePath& path_to_search, + const FilePath& path_to_find, + FilePath* found_path) { + std::vector<FilePath::StringType> parts; + file_util::PathComponents(path_to_find, &parts); + + for (size_t ii = 0; ii < parts.size(); ++ii) { + // build a path from parts. + FilePath path(path_to_search); + for (size_t jj = ii; jj < parts.size(); ++jj) { + path = path.Append(parts[jj]); + } + if (file_util::PathExists(path)) { + *found_path = path; + return true; + } + } + + return false; +} + +} // anonymous namespace + +bool FindFile(const std::vector<FilePath>& paths_to_search, + const FilePath& path_to_find, + FilePath* found_path) { + if (file_util::PathExists(path_to_find)) { + *found_path = path_to_find; + return true; + } + + for (size_t ii = 0; ii < paths_to_search.size(); ++ii) { + FilePath absolute_path(paths_to_search[ii]); + o3d::AbsolutePath(&absolute_path); + + if (FindFileHelper(absolute_path, path_to_find, found_path)) { + return true; + } + } + return false; +} + } // end namespace o3d diff --git a/o3d/utils/cross/file_path_utils.h b/o3d/utils/cross/file_path_utils.h index 30de903..7398e8b 100644 --- a/o3d/utils/cross/file_path_utils.h +++ b/o3d/utils/cross/file_path_utils.h @@ -37,10 +37,10 @@ #define O3D_UTILS_CROSS_FILE_PATH_UTILS_H_ #include <string> +#include <vector> +#include "base/file_path.h" #include "core/cross/types.h" -class FilePath; - namespace o3d { // TODO: Go through the process to add these to FilePath // itself in the Chromium depot. @@ -67,6 +67,23 @@ bool GetRelativePathIfPossible(const FilePath& base_dir, const FilePath& candidate, FilePath *result); +// Tries to find a file path_to_find in paths_to_search. Will start with +// base name and progressively try each higher path. Example: +// +// FindFile(['this/that', 'there'], 'foo/bar/baf.txt'); +// +// Looks for: +// foo/bar/baf.txt +// this/that/foo/bar/baf.txt +// this/that/bar/baf.txt +// this/that/baf.txt +// there/foo/bar/baf.txt +// there/bar/baf.txt +// there/baf.txt +bool FindFile(const std::vector<FilePath>& paths_to_search, + const FilePath& path_to_find, + FilePath* found_path); + } // namespace o3d #endif // O3D_UTILS_CROSS_FILE_PATH_UTILS_H_ diff --git a/o3d/utils/cross/file_path_utils_test.cc b/o3d/utils/cross/file_path_utils_test.cc index e1447fc..e5b9ede 100644 --- a/o3d/utils/cross/file_path_utils_test.cc +++ b/o3d/utils/cross/file_path_utils_test.cc @@ -40,6 +40,26 @@ namespace o3d { +namespace { // anonymous namespace + +bool FilePathsEqual(const FilePath& path_1, const FilePath path_2) { + const FilePath::StringType& p1(path_1.value()); + const FilePath::StringType& p2(path_2.value()); + if (p1.size() == p2.size()) { + for (size_t ii = 0; ii < p1.size(); ++ii) { + if (p1[ii] != p2[ii]) { + if (!FilePath::IsSeparator(p1[ii]) || !FilePath::IsSeparator(p2[ii])) { + return false; + } + } + } + return true; + } + return false; +} + +} // anonymous namespace + class FilePathUtilsTest : public testing::Test { }; @@ -180,4 +200,36 @@ TEST_F(FilePathUtilsTest, RelativePathsRelativeInputs) { EXPECT_STREQ(expected_result.value().c_str(), result.value().c_str()); EXPECT_TRUE(is_relative); } + +TEST_F(FilePathUtilsTest, FindFile) { + String folder_name_1(*g_program_path + "/unittest_data"); + String folder_name_2(*g_program_path + "/bitmap_test"); + FilePath folder_path_1 = UTF8ToFilePath(folder_name_1); + FilePath folder_path_2 = UTF8ToFilePath(folder_name_2); + String file_name_1("fur.fx"); + String file_name_2("someplace/somewhere/tga-256x256-32bit.tga"); + FilePath file_path_1 = UTF8ToFilePath(file_name_1); + FilePath file_path_2 = UTF8ToFilePath(file_name_2); + FilePath out_path; + + FilePath expected_path_1(folder_path_1); + expected_path_1 = expected_path_1.Append(file_path_1); + FilePath expected_path_2(folder_path_2); + expected_path_2 = + expected_path_2.Append(UTF8ToFilePath("tga-256x256-32bit.tga")); + + std::vector<FilePath> paths; + EXPECT_FALSE(FindFile(paths, file_path_1, &out_path)); + EXPECT_FALSE(FindFile(paths, file_path_2, &out_path)); + paths.push_back(folder_path_1); + EXPECT_TRUE(FindFile(paths, file_path_1, &out_path)); + EXPECT_FALSE(FindFile(paths, file_path_2, &out_path)); + EXPECT_TRUE(FilePathsEqual(out_path, expected_path_1)); + paths.push_back(folder_path_2); + EXPECT_TRUE(FindFile(paths, file_path_1, &out_path)); + EXPECT_TRUE(FilePathsEqual(out_path, expected_path_1)); + EXPECT_TRUE(FindFile(paths, file_path_2, &out_path)); + EXPECT_TRUE(FilePathsEqual(out_path, expected_path_2)); +} + } // namespace o3d |