432 lines
12 KiB
C++
432 lines
12 KiB
C++
/* -----------------------------------------------------------------------------
|
|
GSFramework
|
|
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
|
----------------------------------------------------------------------------- */
|
|
|
|
|
|
#include "viewer_base/viewer_base.h"
|
|
#include <iostream>
|
|
#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 <config path> : Configuration file path.\n";
|
|
parm << "\n";
|
|
|
|
parm << "Data source (default: -f ./):\n\n";
|
|
parm << "-f <base path> : Input data from the file system.\n";
|
|
parm << "-A <archive path> : Input data from an archive.\n";
|
|
parm << "-version <name> : Run a specific project version.\n";
|
|
parm << "\n";
|
|
|
|
parm << "Resource path:\n\n";
|
|
parm << "-CC <path> : Mount a file system directory as core.\n";
|
|
parm << "-MD <path> <mount> : Mount a file system directory.\n";
|
|
parm << "-S <path> : Add search path.\n";
|
|
parm << "\n";
|
|
|
|
parm << "Data output (default: -r gl2 -m al):\n\n";
|
|
parm << "-r <ID> : Output renderer ('list' for details).\n";
|
|
parm << "-m <ID> : Output audio mixer ('nengine dummy -m list' for valid IDs).\n";
|
|
parm << "-w <Width> : Display width in pixels.\n";
|
|
parm << "-h <Height> : Display height in pixels.\n";
|
|
parm << "\n";
|
|
|
|
parm << "Script interface:\n\n";
|
|
parm << "-I <include> : Include a script.\n";
|
|
parm << "-Ds <var> <string> : Define and initialize a variable.\n";
|
|
parm << "-Di <var> <int> : Define and initialize a variable.\n";
|
|
parm << "-Df <var> <float> : Define and initialize a variable.\n";
|
|
parm << "\n";
|
|
|
|
parm << "Raytracer interface (scene view only):\n\n";
|
|
parm << "-R <path> : Raytrace each frame to a directory.\n";
|
|
parm << "-Rw <int> : Specify the raytracer frame width.\n";
|
|
parm << "-Rh <int> : Specify the raytracer frame height.\n";
|
|
parm << "-Raa <int> : 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 <int> : 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 <mask> : 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 <sec> : 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 <String> &_arg)
|
|
{
|
|
SharedPtr <IO::Base> io;
|
|
AutoPtr <IO::Handle> 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 <char> 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 <String> &_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;
|
|
}
|
|
//-----------------------------------------------------------------------------
|