PageRenderTime 41ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/brlcad/branches/bullet/src/libged/rt.c

https://bitbucket.org/vrrm/brl-cad-copy-for-fast-history-browsing-in-git
C | 624 lines | 428 code | 113 blank | 83 comment | 77 complexity | f26afa2e960d487952056305ec8c7cf0 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, LGPL-2.1, Apache-2.0, AGPL-3.0, LGPL-3.0, GPL-3.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, 0BSD, BSD-3-Clause
  1. /* R T . C
  2. * BRL-CAD
  3. *
  4. * Copyright (c) 2008-2012 United States Government as represented by
  5. * the U.S. Army Research Laboratory.
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public License
  9. * version 2.1 as published by the Free Software Foundation.
  10. *
  11. * This library is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this file; see the file named COPYING for more
  18. * information.
  19. */
  20. /** @file libged/rt.c
  21. *
  22. * The rt command.
  23. *
  24. */
  25. #include "common.h"
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #ifdef HAVE_SYS_TYPES_H
  29. # include <sys/types.h>
  30. #endif
  31. #ifdef HAVE_SYS_WAIT_H
  32. # include <sys/wait.h>
  33. #endif
  34. #include "bio.h"
  35. #include "tcl.h"
  36. #include "cmd.h"
  37. #include "solid.h"
  38. #include "./ged_private.h"
  39. struct _ged_rt_client_data {
  40. struct ged_run_rt *rrtp;
  41. struct ged *gedp;
  42. };
  43. void
  44. _ged_rt_write(struct ged *gedp,
  45. FILE *fp,
  46. vect_t eye_model)
  47. {
  48. struct ged_display_list *gdlp;
  49. struct ged_display_list *next_gdlp;
  50. size_t i;
  51. quat_t quat;
  52. struct solid *sp;
  53. /* Double-precision IEEE floating point only guarantees 15-17
  54. * digits of precision; single-precision only 6-9 significant
  55. * decimal digits. Using a %.15e precision specifier makes our
  56. * printed value dip into unreliable territory (1+15 digits).
  57. * Looking through our history, %.14e seems to be safe as the
  58. * value prior to printing quaternions was %.9e, although anything
  59. * from 9->14 "should" be safe as it's above our calculation
  60. * tolerance and above single-precision capability.
  61. */
  62. fprintf(fp, "viewsize %.14e;\n", gedp->ged_gvp->gv_size);
  63. quat_mat2quat(quat, gedp->ged_gvp->gv_rotation);
  64. fprintf(fp, "orientation %.14e %.14e %.14e %.14e;\n", V4ARGS(quat));
  65. fprintf(fp, "eye_pt %.14e %.14e %.14e;\n",
  66. eye_model[X], eye_model[Y], eye_model[Z]);
  67. fprintf(fp, "start 0; clean;\n");
  68. gdlp = BU_LIST_NEXT(ged_display_list, &gedp->ged_gdp->gd_headDisplay);
  69. while (BU_LIST_NOT_HEAD(gdlp, &gedp->ged_gdp->gd_headDisplay)) {
  70. next_gdlp = BU_LIST_PNEXT(ged_display_list, gdlp);
  71. FOR_ALL_SOLIDS(sp, &gdlp->gdl_headSolid) {
  72. for (i = 0; i < sp->s_fullpath.fp_len; i++) {
  73. DB_FULL_PATH_GET(&sp->s_fullpath, i)->d_flags &= ~RT_DIR_USED;
  74. }
  75. }
  76. gdlp = next_gdlp;
  77. }
  78. gdlp = BU_LIST_NEXT(ged_display_list, &gedp->ged_gdp->gd_headDisplay);
  79. while (BU_LIST_NOT_HEAD(gdlp, &gedp->ged_gdp->gd_headDisplay)) {
  80. next_gdlp = BU_LIST_PNEXT(ged_display_list, gdlp);
  81. FOR_ALL_SOLIDS(sp, &gdlp->gdl_headSolid) {
  82. for (i = 0; i < sp->s_fullpath.fp_len; i++) {
  83. if (!(DB_FULL_PATH_GET(&sp->s_fullpath, i)->d_flags & RT_DIR_USED)) {
  84. struct animate *anp;
  85. for (anp = DB_FULL_PATH_GET(&sp->s_fullpath, i)->d_animate; anp;
  86. anp=anp->an_forw) {
  87. db_write_anim(fp, anp);
  88. }
  89. DB_FULL_PATH_GET(&sp->s_fullpath, i)->d_flags |= RT_DIR_USED;
  90. }
  91. }
  92. }
  93. gdlp = next_gdlp;
  94. }
  95. gdlp = BU_LIST_NEXT(ged_display_list, &gedp->ged_gdp->gd_headDisplay);
  96. while (BU_LIST_NOT_HEAD(gdlp, &gedp->ged_gdp->gd_headDisplay)) {
  97. next_gdlp = BU_LIST_PNEXT(ged_display_list, gdlp);
  98. FOR_ALL_SOLIDS(sp, &gdlp->gdl_headSolid) {
  99. for (i = 0; i < sp->s_fullpath.fp_len; i++) {
  100. DB_FULL_PATH_GET(&sp->s_fullpath, i)->d_flags &= ~RT_DIR_USED;
  101. }
  102. }
  103. gdlp = next_gdlp;
  104. }
  105. fprintf(fp, "end;\n");
  106. }
  107. void
  108. _ged_rt_set_eye_model(struct ged *gedp,
  109. vect_t eye_model)
  110. {
  111. if (gedp->ged_gvp->gv_zclip || gedp->ged_gvp->gv_perspective > 0) {
  112. vect_t temp;
  113. VSET(temp, 0.0, 0.0, 1.0);
  114. MAT4X3PNT(eye_model, gedp->ged_gvp->gv_view2model, temp);
  115. } else {
  116. /* not doing zclipping, so back out of geometry */
  117. struct ged_display_list *gdlp;
  118. struct ged_display_list *next_gdlp;
  119. struct solid *sp;
  120. int i;
  121. vect_t direction;
  122. vect_t extremum[2];
  123. vect_t minus, plus; /* vers of this solid's bounding box */
  124. double t_in;
  125. vect_t diag1;
  126. vect_t diag2;
  127. point_t ecenter;
  128. VSET(eye_model, -gedp->ged_gvp->gv_center[MDX],
  129. -gedp->ged_gvp->gv_center[MDY], -gedp->ged_gvp->gv_center[MDZ]);
  130. for (i = 0; i < 3; ++i) {
  131. extremum[0][i] = INFINITY;
  132. extremum[1][i] = -INFINITY;
  133. }
  134. gdlp = BU_LIST_NEXT(ged_display_list, &gedp->ged_gdp->gd_headDisplay);
  135. while (BU_LIST_NOT_HEAD(gdlp, &gedp->ged_gdp->gd_headDisplay)) {
  136. next_gdlp = BU_LIST_PNEXT(ged_display_list, gdlp);
  137. FOR_ALL_SOLIDS(sp, &gdlp->gdl_headSolid) {
  138. minus[X] = sp->s_center[X] - sp->s_size;
  139. minus[Y] = sp->s_center[Y] - sp->s_size;
  140. minus[Z] = sp->s_center[Z] - sp->s_size;
  141. VMIN(extremum[0], minus);
  142. plus[X] = sp->s_center[X] + sp->s_size;
  143. plus[Y] = sp->s_center[Y] + sp->s_size;
  144. plus[Z] = sp->s_center[Z] + sp->s_size;
  145. VMAX(extremum[1], plus);
  146. }
  147. gdlp = next_gdlp;
  148. }
  149. VMOVEN(direction, gedp->ged_gvp->gv_rotation + 8, 3);
  150. for (i = 0; i < 3; ++i)
  151. if (NEAR_ZERO(direction[i], 1e-10))
  152. direction[i] = 0.0;
  153. VSUB2(diag1, extremum[1], extremum[0]);
  154. VADD2(ecenter, extremum[1], extremum[0]);
  155. VSCALE(ecenter, ecenter, 0.5);
  156. VSUB2(diag2, ecenter, eye_model);
  157. t_in = MAGNITUDE(diag1) + MAGNITUDE(diag2);
  158. VJOIN1(eye_model, eye_model, t_in, direction);
  159. }
  160. }
  161. void
  162. _ged_rt_output_handler(ClientData clientData, int UNUSED(mask))
  163. {
  164. struct _ged_rt_client_data *drcdp = (struct _ged_rt_client_data *)clientData;
  165. struct ged_run_rt *run_rtp;
  166. #ifndef _WIN32
  167. int count = 0;
  168. #else
  169. DWORD count = 0;
  170. #endif
  171. int read_failed = 0;
  172. char line[RT_MAXLINE+1] = {0};
  173. if (drcdp == (struct _ged_rt_client_data *)NULL ||
  174. drcdp->gedp == (struct ged *)NULL ||
  175. drcdp->rrtp == (struct ged_run_rt *)NULL ||
  176. brlcad_interp == (Tcl_Interp *)NULL)
  177. return;
  178. run_rtp = drcdp->rrtp;
  179. /* Get data from rt */
  180. #ifndef _WIN32
  181. count = read((int)run_rtp->fd, line, RT_MAXLINE);
  182. if (count <= 0) {
  183. read_failed = 1;
  184. }
  185. #else
  186. if (Tcl_Eof(run_rtp->chan) ||
  187. (!ReadFile(run_rtp->fd, line, RT_MAXLINE, &count, 0))) {
  188. read_failed = 1;
  189. }
  190. #endif
  191. /* sanity clamping */
  192. if (count < 0) {
  193. perror("READ ERROR");
  194. count = 0;
  195. } else if (count > RT_MAXLINE) {
  196. count = RT_MAXLINE;
  197. }
  198. if (read_failed) {
  199. int aborted;
  200. /* was it aborted? */
  201. #ifndef _WIN32
  202. int rpid;
  203. int retcode = 0;
  204. Tcl_DeleteFileHandler(run_rtp->fd);
  205. close(run_rtp->fd);
  206. /* wait for the forked process */
  207. while ((rpid = wait(&retcode)) != run_rtp->pid && rpid != -1);
  208. aborted = run_rtp->aborted;
  209. #else
  210. DWORD retcode = 0;
  211. Tcl_DeleteChannelHandler(run_rtp->chan,
  212. _ged_rt_output_handler,
  213. (ClientData)drcdp);
  214. Tcl_Close(brlcad_interp, run_rtp->chan);
  215. /* wait for the forked process
  216. * either EOF has been sent or there was a read error.
  217. * there is no need to block indefinitely
  218. */
  219. WaitForSingleObject(run_rtp->hProcess, 120);
  220. /* !!! need to observe implications of being non-infinite
  221. * WaitForSingleObject(run_rtp->hProcess, INFINITE);
  222. */
  223. if (GetLastError() == ERROR_PROCESS_ABORTED) {
  224. run_rtp->aborted = 1;
  225. }
  226. GetExitCodeProcess(run_rtp->hProcess, &retcode);
  227. /* may be useful to try pr_wait_status() here */
  228. aborted = run_rtp->aborted;
  229. #endif
  230. if (aborted)
  231. bu_log("Raytrace aborted.\n");
  232. else if (retcode)
  233. bu_log("Raytrace failed.\n");
  234. else
  235. bu_log("Raytrace complete.\n");
  236. if (drcdp->gedp->ged_gdp->gd_rtCmdNotify != (void (*)(int))0)
  237. drcdp->gedp->ged_gdp->gd_rtCmdNotify(aborted);
  238. /* free run_rtp */
  239. BU_LIST_DEQUEUE(&run_rtp->l);
  240. bu_free((genptr_t)run_rtp, "_ged_rt_output_handler: run_rtp");
  241. bu_free((genptr_t)drcdp, "_ged_rt_output_handler: drcdp");
  242. return;
  243. }
  244. /* for feelgoodedness */
  245. line[count] = '\0';
  246. /* handle (i.e., probably log to stderr) the resulting line */
  247. if (drcdp->gedp->ged_output_handler != (void (*)())0)
  248. drcdp->gedp->ged_output_handler(drcdp->gedp, line);
  249. else
  250. bu_vls_printf(drcdp->gedp->ged_result_str, "%s", line);
  251. }
  252. int
  253. _ged_run_rt(struct ged *gedp)
  254. {
  255. int i;
  256. FILE *fp_in;
  257. #ifndef _WIN32
  258. int pipe_in[2];
  259. int pipe_err[2];
  260. #else
  261. HANDLE pipe_in[2], pipe_inDup;
  262. HANDLE pipe_err[2], pipe_errDup;
  263. STARTUPINFO si = {0};
  264. PROCESS_INFORMATION pi = {0};
  265. SECURITY_ATTRIBUTES sa = {0};
  266. struct bu_vls line = BU_VLS_INIT_ZERO;
  267. #endif
  268. vect_t eye_model;
  269. struct ged_run_rt *run_rtp;
  270. struct _ged_rt_client_data *drcdp;
  271. #ifndef _WIN32
  272. int pid;
  273. int ret;
  274. ret = pipe(pipe_in);
  275. if (ret < 0)
  276. perror("pipe");
  277. ret = pipe(pipe_err);
  278. if (ret < 0)
  279. perror("pipe");
  280. if ((pid = fork()) == 0) {
  281. /* make this a process group leader */
  282. setpgid(0, 0);
  283. /* Redirect stdin and stderr */
  284. (void)close(0);
  285. ret = dup(pipe_in[0]);
  286. if (ret < 0)
  287. perror("dup");
  288. (void)close(2);
  289. ret = dup(pipe_err[1]);
  290. if (ret < 0)
  291. perror("dup");
  292. /* close pipes */
  293. (void)close(pipe_in[0]);
  294. (void)close(pipe_in[1]);
  295. (void)close(pipe_err[0]);
  296. (void)close(pipe_err[1]);
  297. for (i = 3; i < 20; i++)
  298. (void)close(i);
  299. (void)execvp(gedp->ged_gdp->gd_rt_cmd[0], gedp->ged_gdp->gd_rt_cmd);
  300. perror(gedp->ged_gdp->gd_rt_cmd[0]);
  301. exit(16);
  302. }
  303. /* As parent, send view information down pipe */
  304. (void)close(pipe_in[0]);
  305. fp_in = fdopen(pipe_in[1], "w");
  306. (void)close(pipe_err[1]);
  307. _ged_rt_set_eye_model(gedp, eye_model);
  308. _ged_rt_write(gedp, fp_in, eye_model);
  309. (void)fclose(fp_in);
  310. BU_GET(run_rtp, struct ged_run_rt);
  311. BU_LIST_INIT(&run_rtp->l);
  312. BU_LIST_APPEND(&gedp->ged_gdp->gd_headRunRt.l, &run_rtp->l);
  313. run_rtp->fd = pipe_err[0];
  314. run_rtp->pid = pid;
  315. BU_GET(drcdp, struct _ged_rt_client_data);
  316. drcdp->gedp = gedp;
  317. drcdp->rrtp = run_rtp;
  318. Tcl_CreateFileHandler(run_rtp->fd,
  319. TCL_READABLE,
  320. _ged_rt_output_handler,
  321. (ClientData)drcdp);
  322. return 0;
  323. #else
  324. sa.nLength = sizeof(sa);
  325. sa.bInheritHandle = TRUE;
  326. sa.lpSecurityDescriptor = NULL;
  327. /* Create a pipe for the child process's STDOUT. */
  328. CreatePipe(&pipe_err[0], &pipe_err[1], &sa, 0);
  329. /* Create noninheritable read handle and close the inheritable read handle. */
  330. DuplicateHandle(GetCurrentProcess(), pipe_err[0],
  331. GetCurrentProcess(), &pipe_errDup ,
  332. 0, FALSE,
  333. DUPLICATE_SAME_ACCESS);
  334. CloseHandle(pipe_err[0]);
  335. /* Create a pipe for the child process's STDIN. */
  336. CreatePipe(&pipe_in[0], &pipe_in[1], &sa, 0);
  337. /* Duplicate the write handle to the pipe so it is not inherited. */
  338. DuplicateHandle(GetCurrentProcess(), pipe_in[1],
  339. GetCurrentProcess(), &pipe_inDup,
  340. 0, FALSE, /* not inherited */
  341. DUPLICATE_SAME_ACCESS);
  342. CloseHandle(pipe_in[1]);
  343. si.cb = sizeof(STARTUPINFO);
  344. si.lpReserved = NULL;
  345. si.lpReserved2 = NULL;
  346. si.cbReserved2 = 0;
  347. si.lpDesktop = NULL;
  348. si.dwFlags = STARTF_USESTDHANDLES;
  349. si.hStdInput = pipe_in[0];
  350. si.hStdOutput = pipe_err[1];
  351. si.hStdError = pipe_err[1];
  352. for (i = 0; i < gedp->ged_gdp->gd_rt_cmd_len; i++) {
  353. bu_vls_printf(&line, "%s ", gedp->ged_gdp->gd_rt_cmd[i]);
  354. }
  355. CreateProcess(NULL, bu_vls_addr(&line), NULL, NULL, TRUE,
  356. DETACHED_PROCESS, NULL, NULL,
  357. &si, &pi);
  358. bu_vls_free(&line);
  359. CloseHandle(pipe_in[0]);
  360. CloseHandle(pipe_err[1]);
  361. /* As parent, send view information down pipe */
  362. fp_in = _fdopen(_open_osfhandle((intptr_t)pipe_inDup, _O_TEXT), "wb");
  363. _ged_rt_set_eye_model(gedp, eye_model);
  364. _ged_rt_write(gedp, fp_in, eye_model);
  365. (void)fclose(fp_in);
  366. BU_GET(run_rtp, struct ged_run_rt);
  367. BU_LIST_INIT(&run_rtp->l);
  368. BU_LIST_APPEND(&gedp->ged_gdp->gd_headRunRt.l, &run_rtp->l);
  369. run_rtp->fd = pipe_errDup;
  370. run_rtp->hProcess = pi.hProcess;
  371. run_rtp->pid = pi.dwProcessId;
  372. run_rtp->aborted=0;
  373. run_rtp->chan = Tcl_MakeFileChannel(run_rtp->fd, TCL_READABLE);
  374. BU_GET(drcdp, struct _ged_rt_client_data);
  375. drcdp->gedp = gedp;
  376. drcdp->rrtp = run_rtp;
  377. Tcl_CreateChannelHandler(run_rtp->chan,
  378. TCL_READABLE,
  379. _ged_rt_output_handler,
  380. (ClientData)drcdp);
  381. return 0;
  382. #endif
  383. }
  384. /**
  385. *
  386. */
  387. size_t
  388. ged_count_tops(struct ged *gedp)
  389. {
  390. struct ged_display_list *gdlp = NULL;
  391. size_t visibleCount = 0;
  392. for (BU_LIST_FOR(gdlp, ged_display_list, &gedp->ged_gdp->gd_headDisplay)) {
  393. visibleCount++;
  394. }
  395. return visibleCount;
  396. }
  397. /**
  398. * G E D _ B U I L D _ T O P S
  399. *
  400. * Build a command line vector of the tops of all objects in view.
  401. */
  402. int
  403. ged_build_tops(struct ged *gedp, char **start, char **end)
  404. {
  405. struct ged_display_list *gdlp;
  406. char **vp = start;
  407. for (BU_LIST_FOR(gdlp, ged_display_list, &gedp->ged_gdp->gd_headDisplay)) {
  408. if (gdlp->gdl_dp->d_addr == RT_DIR_PHONY_ADDR)
  409. continue;
  410. if ((vp != NULL) && (vp < end))
  411. *vp++ = bu_strdup(bu_vls_addr(&gdlp->gdl_path));
  412. else {
  413. bu_vls_printf(gedp->ged_result_str, "libged: ran out of command vector space at %s\n", gdlp->gdl_dp->d_namep);
  414. break;
  415. }
  416. }
  417. if ((vp != NULL) && (vp < end)) {
  418. *vp = (char *) 0;
  419. }
  420. return vp-start;
  421. }
  422. int
  423. ged_rt(struct ged *gedp, int argc, const char *argv[])
  424. {
  425. char **vp;
  426. int i;
  427. int units_supplied = 0;
  428. char pstring[32];
  429. int args;
  430. const char *bin;
  431. char rt[256] = {0};
  432. GED_CHECK_DATABASE_OPEN(gedp, GED_ERROR);
  433. GED_CHECK_DRAWABLE(gedp, GED_ERROR);
  434. GED_CHECK_VIEW(gedp, GED_ERROR);
  435. GED_CHECK_ARGC_GT_0(gedp, argc, GED_ERROR);
  436. /* initialize result */
  437. bu_vls_trunc(gedp->ged_result_str, 0);
  438. args = argc + 7 + 2 + ged_count_tops(gedp);
  439. gedp->ged_gdp->gd_rt_cmd = (char **)bu_calloc(args, sizeof(char *), "alloc gd_rt_cmd");
  440. bin = bu_brlcad_root("bin", 1);
  441. if (bin) {
  442. #ifdef _WIN32
  443. snprintf(rt, 256, "\"%s/%s\"", bin, argv[0]);
  444. #else
  445. snprintf(rt, 256, "%s/%s", bin, argv[0]);
  446. #endif
  447. }
  448. vp = &gedp->ged_gdp->gd_rt_cmd[0];
  449. *vp++ = rt;
  450. *vp++ = "-M";
  451. if (gedp->ged_gvp->gv_perspective > 0) {
  452. (void)sprintf(pstring, "-p%g", gedp->ged_gvp->gv_perspective);
  453. *vp++ = pstring;
  454. }
  455. for (i = 1; i < argc; i++) {
  456. if (argv[i][0] == '-' && argv[i][1] == 'u' &&
  457. BU_STR_EQUAL(argv[1], "-u")) {
  458. units_supplied=1;
  459. } else if (argv[i][0] == '-' && argv[i][1] == '-' &&
  460. argv[i][2] == '\0') {
  461. ++i;
  462. break;
  463. }
  464. *vp++ = (char *)argv[i];
  465. }
  466. /* default to local units when not specified on command line */
  467. if (!units_supplied) {
  468. *vp++ = "-u";
  469. *vp++ = "model";
  470. }
  471. /* XXX why is this different for win32 only? */
  472. #ifdef _WIN32
  473. {
  474. char buf[512];
  475. snprintf(buf, 512, "\"%s\"", gedp->ged_wdbp->dbip->dbi_filename);
  476. *vp++ = buf;
  477. }
  478. #else
  479. *vp++ = gedp->ged_wdbp->dbip->dbi_filename;
  480. #endif
  481. /*
  482. * Now that we've grabbed all the options, if no args remain,
  483. * append the names of all stuff currently displayed.
  484. * Otherwise, simply append the remaining args.
  485. */
  486. if (i == argc) {
  487. gedp->ged_gdp->gd_rt_cmd_len = vp - gedp->ged_gdp->gd_rt_cmd;
  488. gedp->ged_gdp->gd_rt_cmd_len += ged_build_tops(gedp, vp, &gedp->ged_gdp->gd_rt_cmd[args]);
  489. } else {
  490. while (i < argc)
  491. *vp++ = (char *)argv[i++];
  492. *vp = 0;
  493. vp = &gedp->ged_gdp->gd_rt_cmd[0];
  494. while (*vp)
  495. bu_vls_printf(gedp->ged_result_str, "%s ", *vp++);
  496. bu_vls_printf(gedp->ged_result_str, "\n");
  497. }
  498. (void)_ged_run_rt(gedp);
  499. bu_free(gedp->ged_gdp->gd_rt_cmd, "free gd_rt_cmd");
  500. gedp->ged_gdp->gd_rt_cmd = NULL;
  501. return GED_OK;
  502. }
  503. /*
  504. * Local Variables:
  505. * tab-width: 8
  506. * mode: C
  507. * indent-tabs-mode: t
  508. * c-file-style: "stroustrup"
  509. * End:
  510. * ex: shiftwidth=4 tabstop=8
  511. */