PageRenderTime 24ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/CS/migrated/branches/R0_94/apps/walktest/command.cpp

#
C++ | 538 lines | 458 code | 25 blank | 55 comment | 155 complexity | c2b53a7c0e3664e2fdc3b8dd9880f5fc MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, LGPL-2.0
  1. /*
  2. Copyright (C) 1998-2001 by Jorrit Tyberghein
  3. This library is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU Library General Public
  5. License as published by the Free Software Foundation; either
  6. version 2 of the License, or (at your option) any later version.
  7. This library is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Library General Public License for more details.
  11. You should have received a copy of the GNU Library General Public
  12. License along with this library; if not, write to the Free
  13. Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14. */
  15. /*
  16. * Command processor. There are now several sources of commands:
  17. * the console and the keyboard. This class ignores the sources but
  18. * just executes the commands. The respective source handlers should
  19. * then do whatever they need to recognize the command and send the
  20. * command to this class.
  21. */
  22. #include <string.h>
  23. #include "cssysdef.h"
  24. #include "csver.h"
  25. #include "csengine/polytext.h"
  26. #include "command.h"
  27. #include "csutil/scanstr.h"
  28. #include "walktest.h"
  29. #include "qint.h"
  30. #include "ivideo/graph3d.h"
  31. #include "ivideo/graph2d.h"
  32. #include "ivaria/conout.h"
  33. #include "iutil/event.h"
  34. #include "iutil/eventq.h"
  35. #include "iutil/objreg.h"
  36. #include "iutil/eventh.h"
  37. #include "iutil/comp.h"
  38. #include "imesh/object.h"
  39. #include "iengine/mesh.h"
  40. #include "ivaria/reporter.h"
  41. #include "iutil/plugin.h"
  42. extern WalkTest* Sys;
  43. // Static csCommandProcessor variables
  44. iEngine* csCommandProcessor::engine = NULL;
  45. iCamera* csCommandProcessor::camera = NULL;
  46. iGraphics3D* csCommandProcessor::g3d = NULL;
  47. iConsoleOutput* csCommandProcessor::console = NULL;
  48. iObjectRegistry* csCommandProcessor::object_reg = NULL;
  49. iFile* csCommandProcessor::script = NULL;
  50. // Additional command handler
  51. csCommandProcessor::CmdHandler csCommandProcessor::ExtraHandler = NULL;
  52. SCF_IMPLEMENT_IBASE (csCommandProcessor::PerformCallback)
  53. SCF_IMPLEMENTS_INTERFACE (iConsoleExecCallback)
  54. SCF_IMPLEMENT_IBASE_END
  55. void csCommandProcessor::PerformCallback::Execute (const char* command)
  56. {
  57. csCommandProcessor::perform_line (command);
  58. }
  59. void csCommandProcessor::Initialize (iEngine* engine, iCamera* camera,
  60. iGraphics3D* g3d, iConsoleOutput* console, iObjectRegistry* objreg)
  61. {
  62. csCommandProcessor::engine = engine;
  63. csCommandProcessor::camera = camera;
  64. csCommandProcessor::g3d = g3d;
  65. csCommandProcessor::console = console;
  66. csCommandProcessor::object_reg = objreg;
  67. }
  68. bool csCommandProcessor::PerformLine (const char* line)
  69. {
  70. return perform_line (line);
  71. }
  72. static int value_choice (const char* arg, int old_value, const char* const* choices, int num)
  73. {
  74. if (!arg) return -1;
  75. int i = 0;
  76. if (!strcasecmp (arg, "next")) return (old_value+1)%num;
  77. if (!strcasecmp (arg, "prev")) return (old_value-1+num)%num;
  78. while (choices[i])
  79. {
  80. if (!strcasecmp (choices[i], arg)) return i;
  81. i++;
  82. }
  83. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY, "Expected one of the following:");
  84. i = 0;
  85. while (choices[i])
  86. {
  87. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY,
  88. " %s%s", choices[i], i == old_value ? " (current)" : "");
  89. i++;
  90. }
  91. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY, " or 'next' or 'prev'");
  92. return -1;
  93. }
  94. static bool yes_or_no (const char* arg, bool old_value)
  95. {
  96. if (!arg) return false;
  97. if (*arg == '0' && *(arg+1) == 0) return false;
  98. if (*arg == '1' && *(arg+1) == 0) return true;
  99. if (!strcasecmp (arg, "yes") || !strcasecmp (arg, "true") || !strcasecmp (arg, "on")) return true;
  100. if (!strcasecmp (arg, "no") || !strcasecmp (arg, "false") || !strcasecmp (arg, "off")) return false;
  101. if (!strcasecmp (arg, "toggle")) return !old_value;
  102. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY,
  103. "Expected: yes, true, on, 1, no, false, off, 0, or toggle!");
  104. return false;
  105. }
  106. static const char* say_on_or_off (int arg)
  107. {
  108. if (arg) return "on";
  109. return "off";
  110. }
  111. /*
  112. * Standard processing to change/display a boolean value setting.
  113. */
  114. void csCommandProcessor::change_boolean (const char* arg, bool* value, const char* what)
  115. {
  116. if (arg)
  117. {
  118. // Change value
  119. int v = yes_or_no (arg, *value);
  120. if (v != -1)
  121. {
  122. *value = v;
  123. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY,
  124. "Set %s %s", what, say_on_or_off (*value));
  125. }
  126. }
  127. else
  128. {
  129. // Show value
  130. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY,
  131. "Current %s is %s", what, say_on_or_off (*value));
  132. }
  133. }
  134. /*
  135. * Standard processing to change/display a multi-value setting.
  136. */
  137. void csCommandProcessor::change_choice (const char* arg, int* value, const char* what, const char* const* choices, int num)
  138. {
  139. if (arg)
  140. {
  141. // Change value
  142. int v = value_choice (arg, *value, choices, num);
  143. if (v != -1)
  144. {
  145. *value = v;
  146. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY,
  147. "Set %s %s", what, choices[*value]);
  148. }
  149. }
  150. else
  151. {
  152. // Show value
  153. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY,
  154. "Current %s is %s", what, choices[*value]);
  155. }
  156. }
  157. /*
  158. * Standard processing to change/display a floating point setting.
  159. * Return true if value changed.
  160. */
  161. bool csCommandProcessor::change_float (const char* arg, float* value, const char* what, float min, float max)
  162. {
  163. if (arg)
  164. {
  165. // Change value.
  166. float g;
  167. if ((*arg == '+' || *arg == '-') && *(arg+1) == *arg)
  168. {
  169. float dv;
  170. sscanf (arg+1, "%f", &dv);
  171. g = *value+dv;
  172. }
  173. else sscanf (arg, "%f", &g);
  174. if (g < min || g > max) Sys->Report (CS_REPORTER_SEVERITY_NOTIFY,
  175. "Bad value for %s (%f <= value <= %f)!", what, min, max);
  176. else
  177. {
  178. *value = g;
  179. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY,
  180. "Set %s to %f", what, *value);
  181. return true;
  182. }
  183. }
  184. else
  185. {
  186. // Show value.
  187. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY,
  188. "Current %s is %f", what, *value);
  189. }
  190. return false;
  191. }
  192. /*
  193. * Standard processing to change/display an integer setting.
  194. * Return true if value changed.
  195. */
  196. bool csCommandProcessor::change_int (const char* arg, int* value, const char* what, int min, int max)
  197. {
  198. if (arg)
  199. {
  200. // Change value.
  201. int g;
  202. if ((*arg == '+' || *arg == '-') && *(arg+1) == *arg)
  203. {
  204. int dv;
  205. sscanf (arg+1, "%d", &dv);
  206. g = *value+dv;
  207. }
  208. else sscanf (arg, "%d", &g);
  209. if (g < min || g > max)
  210. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY,
  211. "Bad value for %s (%d <= value <= %d)!", what, min, max);
  212. else
  213. {
  214. *value = g;
  215. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY,
  216. "Set %s to %d", what, *value);
  217. return true;
  218. }
  219. }
  220. else
  221. {
  222. // Show value.
  223. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY,
  224. "Current %s is %d", what, *value);
  225. }
  226. return false;
  227. }
  228. /*
  229. * Standard processing to change/display a long setting.
  230. * Return true if value changed.
  231. */
  232. bool csCommandProcessor::change_long (const char* arg, long* value, const char* what, long min, long max)
  233. {
  234. if (arg)
  235. {
  236. // Change value.
  237. long g;
  238. if ((*arg == '+' || *arg == '-') && *(arg+1) == *arg)
  239. {
  240. long dv;
  241. sscanf (arg+1, "%ld", &dv);
  242. g = *value+dv;
  243. }
  244. else sscanf (arg, "%ld", &g);
  245. if (g < min || g > max) Sys->Report (CS_REPORTER_SEVERITY_NOTIFY,
  246. "Bad value for %s (%ld <= value <= %ld)!", what, min, max);
  247. else
  248. {
  249. *value = g;
  250. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY,
  251. "Set %s to %ld", what, *value);
  252. return true;
  253. }
  254. }
  255. else
  256. {
  257. // Show value.
  258. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY,
  259. "Current %s is %ld", what, *value);
  260. }
  261. return false;
  262. }
  263. bool csCommandProcessor::perform_line (const char* line)
  264. {
  265. char cmd[512], arg[255];
  266. if (*line == ';') return true; // Comment
  267. if (*line == 0) return true; // Empty line
  268. strcpy (cmd, line);
  269. char* space = strchr (cmd, ' ');
  270. if (space) { *space = 0; strcpy (arg, space+1); }
  271. else *arg = 0;
  272. return perform (cmd, *arg ? arg : (char*)NULL);
  273. }
  274. extern bool GetConfigOption (iBase* plugin, const char* optName, csVariant& optValue);
  275. extern void SetConfigOption (iBase* plugin, const char* optName, const char* optValue);
  276. extern void SetConfigOption (iBase* plugin, const char* optName, csVariant& optValue);
  277. bool csCommandProcessor::perform (const char* cmd, const char* arg)
  278. {
  279. if (ExtraHandler)
  280. {
  281. static bool inside = false;
  282. if (!inside)
  283. {
  284. inside = true;
  285. bool ret = ExtraHandler (cmd, arg);
  286. inside = false;
  287. if (ret) return true;
  288. }
  289. }
  290. if (!strcasecmp (cmd, "quit"))
  291. {
  292. iEventQueue* q = CS_QUERY_REGISTRY (object_reg, iEventQueue);
  293. if (q)
  294. {
  295. q->GetEventOutlet()->Broadcast (cscmdQuit);
  296. q->DecRef ();
  297. }
  298. }
  299. else if (!strcasecmp (cmd, "help"))
  300. {
  301. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY, "-*- General commands -*-");
  302. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY, " about, version, quit, help");
  303. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY, " debug, db_maxpol, db_procpol");
  304. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY, " console, facenorth, facesouth, faceeast");
  305. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY, " facewest, faceup, facedown, turn, activate");
  306. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY, " cls, exec, dnl, cmessage, dmessage");
  307. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY, " portals, cosfact");
  308. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY, " extension, lod, sprlight, coordset");
  309. }
  310. else if (!strcasecmp (cmd, "about"))
  311. {
  312. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY, "Crystal Space version %s (%s).", CS_VERSION, CS_RELEASE_DATE);
  313. }
  314. else if (!strcasecmp (cmd, "version"))
  315. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY, "%s", CS_VERSION);
  316. else if (!strcasecmp (cmd, "extension"))
  317. {
  318. iGraphics2D* g2d = g3d->GetDriver2D ();
  319. if (!g2d->PerformExtension (arg))
  320. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY, "Extension '%s' not supported!", arg);
  321. }
  322. else if (!strcasecmp (cmd, "db_maxpol"))
  323. {
  324. long val = g3d->GetRenderState (G3DRENDERSTATE_MAXPOLYGONSTODRAW);
  325. int ival = (int)val;
  326. change_int (arg, &ival, "maximum polygons", 0, 2000000000);
  327. g3d->SetRenderState (G3DRENDERSTATE_MAXPOLYGONSTODRAW, (long)ival);
  328. }
  329. else if (!strcasecmp (cmd, "db_procpol"))
  330. {
  331. int val = csEngine::GetMaxProcessPolygons ();
  332. change_int (arg, &val, "maximum process polygons", 0, 2000000000);
  333. csEngine::SetMaxProcessPolygons (val);
  334. }
  335. else if (!strcasecmp (cmd, "cmessage"))
  336. {
  337. if (arg) Sys->Report (CS_REPORTER_SEVERITY_NOTIFY, "%s", arg);
  338. else Sys->Report (CS_REPORTER_SEVERITY_NOTIFY, "Argument expected!");
  339. }
  340. else if (!strcasecmp (cmd, "dmessage"))
  341. {
  342. if (arg) Sys->Report (CS_REPORTER_SEVERITY_DEBUG, "%s", arg);
  343. else Sys->Report (CS_REPORTER_SEVERITY_NOTIFY, "Argument expected!");
  344. }
  345. else if (!strcasecmp (cmd, "cosfact"))
  346. change_float (arg, &csPolyTexture::cfg_cosinus_factor, "cosinus factor", -1, 1);
  347. else if (!strcasecmp (cmd, "lod"))
  348. {
  349. iPluginManager* plugin_mgr = CS_QUERY_REGISTRY (object_reg, iPluginManager);
  350. iMeshObjectType* type = CS_QUERY_PLUGIN_CLASS (plugin_mgr,
  351. "crystalspace.mesh.object.sprite.3d", iMeshObjectType);
  352. csVariant lod_level;
  353. GetConfigOption (type, "sprlod", lod_level);
  354. float f = lod_level.GetFloat ();
  355. change_float (arg, &f, "LOD detail", -1, 1000000);
  356. lod_level.SetFloat (f);
  357. SetConfigOption (type, "sprlod", lod_level);
  358. plugin_mgr->DecRef ();
  359. }
  360. else if (!strcasecmp (cmd, "sprlight"))
  361. {
  362. iPluginManager* plugin_mgr = CS_QUERY_REGISTRY (object_reg, iPluginManager);
  363. iMeshObjectType* type = CS_QUERY_PLUGIN_CLASS (plugin_mgr,
  364. "crystalspace.mesh.object.sprite.3d", iMeshObjectType);
  365. csVariant lqual;
  366. GetConfigOption (type, "sprlq", lqual);
  367. long l = lqual.GetLong ();
  368. change_long (arg, &l, "sprite lighting quality", 0, 3);
  369. lqual.SetLong (l);
  370. SetConfigOption (type, "sprlq", lqual);
  371. plugin_mgr->DecRef ();
  372. }
  373. else if (!strcasecmp (cmd, "dnl"))
  374. Sys->Report (CS_REPORTER_SEVERITY_DEBUG, "");
  375. else if (!strcasecmp (cmd, "exec"))
  376. {
  377. if (arg)
  378. {
  379. if (start_script (arg) && console)
  380. console->SetVisible (true);
  381. }
  382. else Sys->Report (CS_REPORTER_SEVERITY_NOTIFY, "Please specify the name of the script!");
  383. }
  384. else if (!strcasecmp (cmd, "portals"))
  385. change_boolean (arg, &csSector::do_portals, "portals");
  386. else if (!strcasecmp (cmd, "cls"))
  387. {
  388. if (console)
  389. console->Clear ();
  390. }
  391. else if (!strcasecmp (cmd, "console"))
  392. {
  393. if (console)
  394. {
  395. bool active = console->GetVisible ();
  396. change_boolean (arg, &active, "console");
  397. if (active != console->GetVisible ())
  398. console->SetVisible (active);
  399. }
  400. }
  401. else if (!strcasecmp (cmd, "turn"))
  402. camera->GetTransform ().RotateThis (CS_VEC_ROT_RIGHT, PI);
  403. else if (!strcasecmp (cmd, "activate"))
  404. {
  405. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY, "OBSOLETE");
  406. }
  407. else if (!strcasecmp (cmd, "coordset"))
  408. {
  409. if (!arg)
  410. {
  411. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY, "Expected argument!");
  412. return false;
  413. }
  414. char sect[100];
  415. float x, y, z;
  416. if (csScanStr (arg, "%s,%f,%f,%f", sect, &x, &y, &z) != 4)
  417. {
  418. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY,
  419. "Expected sector,x,y,z. Got something else!");
  420. return false;
  421. }
  422. iSector* s = engine->GetSectors ()->FindByName (sect);
  423. if (!s)
  424. {
  425. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY, "Can't find this sector!");
  426. return false;
  427. }
  428. camera->SetSector (s);
  429. camera->GetTransform ().SetOrigin (csVector3(x,y,z));
  430. }
  431. else if (!strcasecmp (cmd, "facenorth"))
  432. camera->GetTransform ().SetO2T (csMatrix3() /* identity */ );
  433. else if (!strcasecmp (cmd, "facesouth"))
  434. camera->GetTransform ().SetO2T ( csMatrix3 ( -1, 0, 0,
  435. 0, 1, 0,
  436. 0, 0, -1 ) );
  437. else if (!strcasecmp (cmd, "facewest"))
  438. camera->GetTransform ().SetO2T ( csMatrix3 ( 0, 0, 1,
  439. 0, 1, 0,
  440. -1, 0, 0 ) );
  441. else if (!strcasecmp (cmd, "faceeast"))
  442. camera->GetTransform ().SetO2T ( csMatrix3 ( 0, 0, -1,
  443. 0, 1, 0,
  444. 1, 0, 0 ) );
  445. else if (!strcasecmp (cmd, "facedown"))
  446. camera->GetTransform ().SetO2T ( csMatrix3 ( 1, 0, 0,
  447. 0, 0, 1,
  448. 0, -1, 0 ) );
  449. else if (!strcasecmp (cmd, "faceup"))
  450. camera->GetTransform ().SetO2T ( csMatrix3 ( 1, 0, 0,
  451. 0, 0, -1,
  452. 0, 1, 0 ) );
  453. else
  454. {
  455. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY, "Unknown command: `%s'", cmd);
  456. return false;
  457. }
  458. return true;
  459. }
  460. bool csCommandProcessor::start_script (const char* scr)
  461. {
  462. bool ok = false;
  463. iVFS* v = CS_QUERY_REGISTRY (object_reg, iVFS);
  464. if (v)
  465. {
  466. v->DecRef ();
  467. if (v->Exists (scr))
  468. {
  469. iFile* f = v->Open (scr, VFS_FILE_READ);
  470. if (!f)
  471. Sys->Report (CS_REPORTER_SEVERITY_NOTIFY, "Could not open script file '%s'!", scr);
  472. else
  473. {
  474. // Replace possible running script with this one.
  475. if (script)
  476. script->DecRef();
  477. script = f;
  478. ok = true;
  479. }
  480. }
  481. }
  482. return ok;
  483. }
  484. bool csCommandProcessor::get_script_line (char* buf, int nbytes)
  485. {
  486. if (!script)
  487. return false;
  488. char c = '\n';
  489. while (c == '\n' || c == '\r')
  490. if (!script->Read(&c, 1))
  491. break;
  492. if (script->AtEOF())
  493. {
  494. script->DecRef();
  495. script = NULL;
  496. return false;
  497. }
  498. char* p = buf;
  499. const char* plim = p + nbytes - 1;
  500. while (p < plim)
  501. {
  502. if (c == '\n' || c == '\r')
  503. break;
  504. *p++ = c;
  505. if (!script->Read(&c, 1))
  506. break;
  507. }
  508. *p = '\0';
  509. return true;
  510. }