/* ----------------------------------------------------------------------------- GSFramework Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. ----------------------------------------------------------------------------- */ #include "viewer_base/viewer_base.h" #include #include "io_archive/io_archive.h" #include "scene3d/scene.h" #include "core/engine.h" #include "filesystem/filesystem.h" #include "filesystem/io_cfile.h" #include "platform.h" using namespace GS; // [EJ] 4/4: Do not use Log to output the command line as it will be eaten by a release build. //------------------------------------------------------------------------------ void ViewerBase::PrintHeader() { std::cout << "GameStart stand-alone.\n"; std::cout << "http://www.gamestart3d.com\n"; std::cout << "Version: " << Core::Version << "\n"; std::cout << "Emmanuel Julien 2001-2013.\n\n"; } String ViewerBase::GetBaseCommandLineParm() const { String parm; parm << "Basic usage:\n\n"; parm << "-P : Execute a project (default: execute scene).\n"; parm << "-C : Configuration file path.\n"; parm << "\n"; parm << "Data source (default: -f ./):\n\n"; parm << "-f : Input data from the file system.\n"; parm << "-A : Input data from an archive.\n"; parm << "-version : Run a specific project version.\n"; parm << "\n"; parm << "Resource path:\n\n"; parm << "-CC : Mount a file system directory as core.\n"; parm << "-MD : Mount a file system directory.\n"; parm << "-S : Add search path.\n"; parm << "\n"; parm << "Data output (default: -r gl2 -m al):\n\n"; parm << "-r : Output renderer ('list' for details).\n"; parm << "-m : Output audio mixer ('nengine dummy -m list' for valid IDs).\n"; parm << "-w : Display width in pixels.\n"; parm << "-h : Display height in pixels.\n"; parm << "\n"; parm << "Script interface:\n\n"; parm << "-I : Include a script.\n"; parm << "-Ds : Define and initialize a variable.\n"; parm << "-Di : Define and initialize a variable.\n"; parm << "-Df : Define and initialize a variable.\n"; parm << "\n"; parm << "Raytracer interface (scene view only):\n\n"; parm << "-R : Raytrace each frame to a directory.\n"; parm << "-Rw : Specify the raytracer frame width.\n"; parm << "-Rh : Specify the raytracer frame height.\n"; parm << "-Raa : Specify the raytracer AA grid size (default: 4).\n"; parm << "\n"; parm << "Program flags:\n\n"; parm << "-remote : Start the viewer in remote mode (must be first argument).\n"; parm << "-remote_port : Set the remote mode listening port.\n"; parm << "\n"; parm << "-ignore_esc : Do not exit when escape is pressed.\n"; parm << "-ignore_missing : Do not exit on missing resource.\n"; parm << "-ignore_bootstrap : Ignore the bootstrap file.\n"; parm << "\n"; parm << "-tool_mode : Execute as if ran in the editor.\n"; parm << "-safe_mode : Enable renderer/mixer safe-mode.\n"; parm << "\n"; parm << "-enable_pause : Enable 'p' key to pause engine.\n"; parm << "\n"; parm << "-fallback_disk_fs : Enable disk file system fallback.\n"; parm << "\n"; parm << "-enable_profiler : Enable on-screen performance profiler.\n"; parm << "-memory_profiler : Enable on-screen memory profiler.\n"; parm << "\n"; parm << "-log_level : Set the engine log level mask (eg. -log_level !S*).\n"; parm << " n: None\n"; parm << " s: Standard\n"; parm << " H: Header\n"; parm << " *: Warning\n"; parm << " !: Error\n"; parm << " V: Verbose\n"; parm << " S: Script\n"; parm << " a: All (default)\n"; parm << "-time_live : Set runtime time-to-live in seconds.\n"; return parm; } void ViewerBase::PrintUsage() { std::cout << "Usage: gsviewer input(.nms|.ngp) <-P> <-f|-A> <-S>\n\n"; std::cout << GetBaseCommandLineParm() << "\n"; PrintAdditionalUsage(); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ bool ViewerBase::LocateAndParseBootstrap(Stack &_arg) { SharedPtr io; AutoPtr h; // Look for a naked bootstrap file. if ((h = Platform::Get().io->Open("bootstrap.txt")) != NULL) session_source = SessionSourceFilesystem; else { // Mount core to default archive. io = new IO::Archive("@root/native/000.gsa"); Platform::Get().io->Mount(io, "@core/"); // Look for an archived bootstrap. h = Platform::Get().io->Open("@core/bootstrap.txt"); if (h.IsNull()) { Platform::Get().io->Unmount("@core/"); // [EJ] unmount on fail to locate bootstrap return false; } // Set archive as the data source. session_source = SessionSourceArchiveBootstrap; Platform::Get().io->Mount(io); } // Parse bootstrap. String bootstrap; size_t s = h->GetSize(); Array s_buffer(s); h->Read(s_buffer, s); bootstrap.Set(s_buffer.c_ptr(), &s_buffer.c_ptr()[s]); bootstrap.Split(" ", _arg, '\"'); h = NULL; return true; } void ViewerBase::SetupVersion(const char *name) { using namespace NML; File file; if (!Parser::Load("@root/.reserved/versions.rls", file)) return; if (Tag *versions = file.GetTag("Versions;")) { NMLTagForeach(v, *versions) if (Tag *n = v->GetTypedTag("Name", Variant::VariantString)) if (String(n->GetString()) == name) if (Tag *s = v->GetTypedTag("BootstrapScript", Variant::VariantString)) { bootstrap_script = s->GetString(); return; } } } //------------------------------------------------------------------------------ //----------------------------------------------------------------------------- bool ViewerBase::ParseCommandLine(Stack &_arg) { if ((_arg.GetCount() < 1) && !LocateAndParseBootstrap(_arg)) __ERR__(PrintUsage(), false) session_type = SessionScene; // assume scene session // Remote is a special flag int n = 0; if (_arg[0] != "-remote") input_path = _arg[n++]; // Parse optional arguments. int narg = (int)_arg.GetCount(); for ( ; n < narg; ++n) { String arg(_arg[n]); if (arg == "-P") session_type = SessionProject; // Version. else if (arg == "-version") { if (++n == narg) __ERR__(__LOG_E__ << "-version: Missing version name.\n", false); SetupVersion(_arg[n]); } // Time to live. else if (arg == "-time_live") { if (++n == narg) __ERR__(__LOG_E__ << "-time_live: Missing mask.\n", false); time_live = String::atoi(_arg[n]); } // Log filter. else if (arg == "-log_level") { if (++n == narg) __ERR__(__LOG_E__ << "-log_level: Missing mask.\n", false); uint mask = 0; for (const char *p_flag = _arg[n]; p_flag[0]; ++p_flag) switch (p_flag[0]) { case 'n': mask = EngineLogNone; break; case 's': mask |= EngineLogStandard; break; case 'H': mask |= EngineLogHeader; break; case '*': mask |= EngineLogWarning; break; case '!': mask |= EngineLogError; break; case 'V': mask |= EngineLogVerbose; break; case 'S': mask |= EngineLogScript; break; case 'a': mask |= EngineLogAll; break; } LogSystem::Get().GetLog().SetLogLevel(mask); } else if (arg == "-debug") active_debug = true; else if (arg == "-ignore_bootstrap") ignore_bootstrap = true; else if (arg == "-ignore_esc") ignore_esc = true; else if (arg == "-ignore_missing") ignore_missing_resource = true; else if (arg == "-tool_mode") tool_mode = true; else if (arg == "-fallback_disk_fs") Platform::Get().io->Mount(new IO::CFile); else if (arg == "-safe_mode") safe_mode = true; else if (arg == "-enable_profiler") enable_profiler = true; else if (arg == "-memory_profiler") memory_profiler = true; else if (arg == "-enable_pause") enable_pause = true; // Config path. else if (arg == "-C") { if (++n == narg) __ERR__(__LOG_E__ << "-C: Missing configuration file path.\n", false); config_path = _arg[n]; } // File system source. else if (arg == "-f") { if (++n == narg) __ERR__(__LOG_E__ << "-f: Missing root path.\n", false); session_source_path = _arg[n]; session_source = SessionSourceFilesystem; } // Archive source. else if (arg == "-A") { if (++n == narg) __ERR__(__LOG_E__ << "-A: Missing archive path.\n", false); session_source_path = _arg[n]; session_source = SessionSourceArchive; } // Renderer. else if (arg == "-r") { if (++n == narg) __ERR__(__LOG_E__ << "-r: Missing renderer id.\n", false); s_render = _arg[n]; } else if (arg == "-w") { if (++n == narg) __ERR__(__LOG_E__ << "-w: Missing width value.\n", false); width = String::atoi(_arg[n]); } else if (arg == "-h") { if (++n == narg) __ERR__(__LOG_E__ << "-h: Missing height value.\n", false); height = String::atoi(_arg[n]); } // Mixer. else if (arg == "-m") { if (++n == narg) __ERR__(__LOG_E__ << "-m: Missing mixer id.\n", false); s_mixer = _arg[n]; } // Search path. else if (arg == "-S") { if (++n == narg) __ERR__(__LOG_E__ << "-S: Missing search path.\n", false); Platform::Get().io->Mount(new IO::CFile(_arg[n])); } // Mount core. else if (arg == "-CC") { if (++n == narg) __ERR__(__LOG_E__ << "-CC: Missing core path.\n", false); String c_path = _arg[n]; Platform::Get().io->Mount(new IO::CFile(c_path), "@core/"); Platform::Get().io->Mount(new IO::CFile(c_path)); // FIXME } // Mount point. else if (arg == "-MD") { if (++n == narg) __ERR__(__LOG_E__ << "-MD: Missing directory path.\n", false); String dir_path = _arg[n]; if (++n == narg) __ERR__(__LOG_E__ << "-MD: Missing mount point.\n", false); String mount_point = _arg[n]; Platform::Get().io->Mount(new IO::CFile(dir_path), mount_point); } // Raytrace path. else if (arg == "-R") { if (++n == narg) __ERR__(__LOG_E__ << "-R: Missing raytracer output path.\n", false); raytrace_path = _arg[n]; } // Raytrace width. else if (arg == "-Rw") { if (++n == narg) __ERR__(__LOG_E__ << "-Rw: Missing raytracer frame width.\n", false); raytrace_width = String::atoi(_arg[n]); } // Raytrace height. else if (arg == "-Rh") { if (++n == narg) __ERR__(__LOG_E__ << "-Rh: Missing raytracer frame height.\n", false); raytrace_height = String::atoi(_arg[n]); } // Raytrace AA. else if (arg == "-Raa") { if (++n == narg) __ERR__(__LOG_E__ << "-Raa: Missing raytracer AA grid size.\n", false); raytrace_aa = String::atoi(_arg[n]); } // Include. else if (arg == "-I") { if (++n == narg) __ERR__(__LOG_E__ << "-I: Missing include path.\n", false); if (!include_list.Add(_arg[n])) __ERR__(__LOG_E__ << "Failed to allocate include structure.\n", false); } // Variable. else if (arg == "-Ds") { n += 2; if (n == narg) __ERR__(__LOG_E__ << "-Ds: Incomplete key-value pair. (eg. -Ds my_var \"String Value\")\n", false); Variant *yo = new Variant(_arg[n - 1], _arg[n]); if (!define_list.Add(new Variant(_arg[n - 1], _arg[n]))) __ERR__(__LOG_E__ << "Failed to allocate define structure.\n", false); } // Variable. else if (arg == "-Di") { n += 2; if (n == narg) __ERR__(__LOG_E__ << "-Di: Incomplete key-value pair. (eg. -Di my_var 5)\n", false); if (!define_list.Add(new Variant(_arg[n - 1], String::atoi(_arg[n])))) __ERR__(__LOG_E__ << "Failed to allocate define structure.\n", false); } // Variable. else if (arg == "-Df") { n += 2; if (n == narg) __ERR__(__LOG_E__ << "-Df: Incomplete key-value pair. (eg. -Df my_var 5.5)\n", false); if (!define_list.Add(new Variant(_arg[n - 1], String::atof(_arg[n])))) __ERR__(__LOG_E__ << "Failed to allocate define structure.\n", false); } else if (!OnUnknownCommandLineParam(_arg, n)) __ERR__(__LOG_E__ << "Unknown command line parameter '" << arg << "'\n", false); } return true; } //-----------------------------------------------------------------------------