BRL-CAD
rtwizard.c
Go to the documentation of this file.
1 /* R T W I Z A R D . C
2  * BRL-CAD
3  *
4  * Copyright (c) 2008-2014 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/rtwizard.c
21  *
22  * The rtwizard command.
23  *
24  */
25 
26 #include "common.h"
27 
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
33 #endif
34 
35 #ifdef HAVE_SYS_WAIT_H
36 # include <sys/wait.h>
37 #endif
38 
39 
40 #include "tcl.h"
41 #include "bu/cmd.h"
42 
43 
44 #include "./ged_private.h"
45 
46 
47 struct _ged_rt_client_data {
48  struct ged_run_rt *rrtp;
49  struct ged *gedp;
50 };
51 
52 
53 int
54 _ged_run_rtwizard(struct ged *gedp)
55 {
56  int i;
57  FILE *fp_in;
58 #ifndef _WIN32
59  int pipe_in[2];
60  int pipe_err[2];
61 #else
62  HANDLE pipe_in[2], pipe_inDup;
63  HANDLE pipe_err[2], pipe_errDup;
64  STARTUPINFO si = {0};
65  PROCESS_INFORMATION pi = {0};
66  SECURITY_ATTRIBUTES sa = {0};
67  struct bu_vls line = BU_VLS_INIT_ZERO;
68 #endif
69  struct ged_run_rt *run_rtp;
70  struct _ged_rt_client_data *drcdp;
71 #ifndef _WIN32
72  int pid;
73  int ret;
74 
75  ret = pipe(pipe_in);
76  if (ret < 0)
77  perror("pipe");
78  ret = pipe(pipe_err);
79  if (ret < 0)
80  perror("pipe");
81 
82  if ((pid = fork()) == 0) {
83  /* make this a process group leader */
84  setpgid(0, 0);
85 
86  /* Redirect stdin and stderr */
87  (void)close(0);
88  ret = dup(pipe_in[0]);
89  if (ret < 0)
90  perror("dup");
91  (void)close(2);
92  ret = dup(pipe_err[1]);
93  if (ret < 0)
94  perror("dup");
95 
96  /* close pipes */
97  (void)close(pipe_in[0]);
98  (void)close(pipe_in[1]);
99  (void)close(pipe_err[0]);
100  (void)close(pipe_err[1]);
101 
102  for (i = 3; i < 20; i++)
103  (void)close(i);
104 
105  (void)execvp(gedp->ged_gdp->gd_rt_cmd[0], gedp->ged_gdp->gd_rt_cmd);
106  perror(gedp->ged_gdp->gd_rt_cmd[0]);
107  exit(16);
108  }
109 
110  /* As parent, send view information down pipe */
111  (void)close(pipe_in[0]);
112  fp_in = fdopen(pipe_in[1], "w");
113 
114  (void)close(pipe_err[1]);
115 
116  (void)fclose(fp_in);
117 
118  /* must be BU_GET() to match release in _ged_rt_output_handler */
119  BU_GET(run_rtp, struct ged_run_rt);
120  BU_LIST_INIT(&run_rtp->l);
121  BU_LIST_APPEND(&gedp->ged_gdp->gd_headRunRt.l, &run_rtp->l);
122 
123  run_rtp->fd = pipe_err[0];
124  run_rtp->pid = pid;
125 
126  /* must be BU_GET() to match release in _ged_rt_output_handler */
127  BU_GET(drcdp, struct _ged_rt_client_data);
128  drcdp->gedp = gedp;
129  drcdp->rrtp = run_rtp;
130 
131  Tcl_CreateFileHandler(run_rtp->fd,
132  TCL_READABLE,
134  (ClientData)drcdp);
135 
136  return 0;
137 
138 #else
139  sa.nLength = sizeof(sa);
140  sa.bInheritHandle = TRUE;
141  sa.lpSecurityDescriptor = NULL;
142 
143  /* Create a pipe for the child process's STDOUT. */
144  CreatePipe(&pipe_err[0], &pipe_err[1], &sa, 0);
145 
146  /* Create noninheritable read handle and close the inheritable read handle. */
147  DuplicateHandle(GetCurrentProcess(), pipe_err[0],
148  GetCurrentProcess(), &pipe_errDup ,
149  0, FALSE,
150  DUPLICATE_SAME_ACCESS);
151  CloseHandle(pipe_err[0]);
152 
153  /* Create a pipe for the child process's STDIN. */
154  CreatePipe(&pipe_in[0], &pipe_in[1], &sa, 0);
155 
156  /* Duplicate the write handle to the pipe so it is not inherited. */
157  DuplicateHandle(GetCurrentProcess(), pipe_in[1],
158  GetCurrentProcess(), &pipe_inDup,
159  0, FALSE, /* not inherited */
160  DUPLICATE_SAME_ACCESS);
161  CloseHandle(pipe_in[1]);
162 
163 
164  si.cb = sizeof(STARTUPINFO);
165  si.lpReserved = NULL;
166  si.lpReserved2 = NULL;
167  si.cbReserved2 = 0;
168  si.lpDesktop = NULL;
169  si.dwFlags = STARTF_USESTDHANDLES;
170  si.hStdInput = pipe_in[0];
171  si.hStdOutput = pipe_err[1];
172  si.hStdError = pipe_err[1];
173 
174  for (i = 0; i < gedp->ged_gdp->gd_rt_cmd_len; i++) {
175  bu_vls_printf(&line, "\"%s\" ", gedp->ged_gdp->gd_rt_cmd[i]);
176  }
177 
178  CreateProcess(NULL, bu_vls_addr(&line), NULL, NULL, TRUE,
179  DETACHED_PROCESS, NULL, NULL,
180  &si, &pi);
181  bu_vls_free(&line);
182 
183  CloseHandle(pipe_in[0]);
184  CloseHandle(pipe_err[1]);
185 
186  /* As parent, send view information down pipe */
187  fp_in = _fdopen(_open_osfhandle((intptr_t)pipe_inDup, _O_TEXT), "wb");
188 
189  (void)fclose(fp_in);
190 
191  /* must be BU_GET() to match release in _ged_rt_output_handler */
192  BU_GET(run_rtp, struct ged_run_rt);
193  BU_LIST_INIT(&run_rtp->l);
194  BU_LIST_APPEND(&gedp->ged_gdp->gd_headRunRt.l, &run_rtp->l);
195 
196  run_rtp->fd = pipe_errDup;
197  run_rtp->hProcess = pi.hProcess;
198  run_rtp->pid = pi.dwProcessId;
199  run_rtp->aborted=0;
200  run_rtp->chan = Tcl_MakeFileChannel(run_rtp->fd, TCL_READABLE);
201 
202  /* must be BU_GET() to match release in _ged_rt_output_handler */
203  BU_GET(drcdp, struct _ged_rt_client_data);
204  drcdp->gedp = gedp;
205  drcdp->rrtp = run_rtp;
206 
207  Tcl_CreateChannelHandler(run_rtp->chan,
208  TCL_READABLE,
210  (ClientData)drcdp);
211 
212  return 0;
213 #endif
214 }
215 
216 
217 int
218 ged_rtwizard(struct ged *gedp, int argc, const char *argv[])
219 {
220  char **vp;
221  int i;
222  char pstring[32];
223  int args;
224  quat_t quat;
225  vect_t eye_model;
226  struct bu_vls perspective_vls = BU_VLS_INIT_ZERO;
227  struct bu_vls size_vls = BU_VLS_INIT_ZERO;
228  struct bu_vls orient_vls = BU_VLS_INIT_ZERO;
229  struct bu_vls eye_vls = BU_VLS_INIT_ZERO;
230 
231  const char *bin;
232  char rt[256] = {0};
233  char rtscript[256] = {0};
234 
237  GED_CHECK_VIEW(gedp, GED_ERROR);
238  GED_CHECK_ARGC_GT_0(gedp, argc, GED_ERROR);
239 
240  /* initialize result */
241  bu_vls_trunc(gedp->ged_result_str, 0);
242 
243  if (gedp->ged_gvp->gv_perspective > 0)
244  /* btclsh rtwizard --no_gui -perspective p -i db.g --viewsize size --orientation "A B C D} --eye_pt "X Y Z" */
245  args = argc + 1 + 1 + 1 + 2 + 2 + 2 + 2 + 2;
246  else
247  /* btclsh rtwizard --no_gui -i db.g --viewsize size --orientation "A B C D} --eye_pt "X Y Z" */
248  args = argc + 1 + 1 + 1 + 2 + 2 + 2 + 2;
249 
250  gedp->ged_gdp->gd_rt_cmd = (char **)bu_calloc(args, sizeof(char *), "alloc gd_rt_cmd");
251 
252  bin = bu_brlcad_root("bin", 1);
253  if (bin) {
254  snprintf(rt, 256, "%s/btclsh", bin);
255  snprintf(rtscript, 256, "%s/rtwizard", bin);
256  } else {
257  snprintf(rt, 256, "btclsh");
258  snprintf(rtscript, 256, "rtwizard");
259  }
260 
261  _ged_rt_set_eye_model(gedp, eye_model);
262  quat_mat2quat(quat, gedp->ged_gvp->gv_rotation);
263 
264  bu_vls_printf(&size_vls, "%.15e", gedp->ged_gvp->gv_size);
265  bu_vls_printf(&orient_vls, "%.15e %.15e %.15e %.15e", V4ARGS(quat));
266  bu_vls_printf(&eye_vls, "%.15e %.15e %.15e", V3ARGS(eye_model));
267 
268  vp = &gedp->ged_gdp->gd_rt_cmd[0];
269  *vp++ = rt;
270  *vp++ = rtscript;
271  *vp++ = "--no-gui";
272  *vp++ = "--viewsize";
273  *vp++ = bu_vls_addr(&size_vls);
274  *vp++ = "--orientation";
275  *vp++ = bu_vls_addr(&orient_vls);
276  *vp++ = "--eye_pt";
277  *vp++ = bu_vls_addr(&eye_vls);
278 
279  if (gedp->ged_gvp->gv_perspective > 0) {
280  *vp++ = "--perspective";
281  (void)sprintf(pstring, "%g", gedp->ged_gvp->gv_perspective);
282  *vp++ = pstring;
283  }
284 
285  *vp++ = "-i";
286  *vp++ = gedp->ged_wdbp->dbip->dbi_filename;
287 
288  /* Append all args */
289  for (i = 1; i < argc; i++)
290  *vp++ = (char *)argv[i];
291  *vp = 0;
292 
293  /*
294  * Accumulate the command string.
295  */
296  vp = &gedp->ged_gdp->gd_rt_cmd[0];
297  while (*vp)
298  bu_vls_printf(gedp->ged_result_str, "%s ", *vp++);
299  bu_vls_printf(gedp->ged_result_str, "\n");
300 
301  gedp->ged_gdp->gd_rt_cmd_len = vp - gedp->ged_gdp->gd_rt_cmd;
302  (void)_ged_run_rtwizard(gedp);
303  bu_free(gedp->ged_gdp->gd_rt_cmd, "free gd_rt_cmd");
304  gedp->ged_gdp->gd_rt_cmd = NULL;
305 
306  bu_vls_free(&perspective_vls);
307  bu_vls_free(&size_vls);
308  bu_vls_free(&orient_vls);
309  bu_vls_free(&eye_vls);
310 
311  return GED_OK;
312 }
313 
314 
315 /*
316  * Local Variables:
317  * tab-width: 8
318  * mode: C
319  * indent-tabs-mode: t
320  * c-file-style: "stroustrup"
321  * End:
322  * ex: shiftwidth=4 tabstop=8
323  */
#define GED_OK
Definition: ged.h:55
#define FALSE
Definition: ged.h:338
struct db_i * dbip
Definition: raytrace.h:1266
struct ged_run_rt * rrtp
Definition: rt.c:48
void _ged_rt_set_eye_model(struct ged *gedp, vect_t eye_model)
Definition: rt.c:88
void bu_vls_trunc(struct bu_vls *vp, int len)
Definition: vls.c:198
#define GED_CHECK_ARGC_GT_0(_gedp, _argc, _flags)
Definition: ged.h:202
struct ged_run_rt gd_headRunRt
head of forked rt processes
Definition: ged.h:314
int fd
Definition: ged.h:272
struct rt_wdb * ged_wdbp
Definition: ged.h:340
Header file for the BRL-CAD common definitions.
fastf_t gv_perspective
perspective angle
Definition: bview.h:214
#define BU_LIST_APPEND(old, new)
Definition: list.h:197
#define GED_ERROR
Definition: ged.h:61
struct bview * ged_gvp
Definition: ged.h:361
void bu_vls_free(struct bu_vls *vp)
Definition: vls.c:248
struct bu_list l
Definition: ged.h:260
#define GED_CHECK_VIEW(_gedp, _flags)
Definition: ged.h:140
#define GED_CHECK_DATABASE_OPEN(_gedp, _flags)
Definition: ged.h:114
int gd_rt_cmd_len
Definition: ged.h:313
FILE * fdopen(int, const char *)
void * bu_calloc(size_t nelem, size_t elsize, const char *str)
Definition: malloc.c:321
void _ged_rt_output_handler(ClientData clientData, int mask)
Definition: rt.c:132
#define V3ARGS(a)
Definition: color.c:56
fastf_t gv_size
2.0 * scale
Definition: bview.h:212
#define BU_GET(_ptr, _type)
Definition: malloc.h:201
char ** gd_rt_cmd
Definition: ged.h:312
#define GED_CHECK_DRAWABLE(_gedp, _flags)
Definition: ged.h:129
int ged_rtwizard(struct ged *gedp, int argc, const char *argv[])
Definition: rtwizard.c:218
char * bu_vls_addr(const struct bu_vls *vp)
Definition: vls.c:111
struct bu_vls * ged_result_str
Definition: ged.h:357
struct ged_drawable * ged_gdp
Definition: ged.h:360
struct ged * gedp
Definition: rt.c:49
mat_t gv_rotation
Definition: bview.h:220
#define BU_LIST_INIT(_hp)
Definition: list.h:148
int aborted
Definition: ged.h:275
HIDDEN fastf_t bin(fastf_t val, fastf_t step)
Definition: nmg_tri_mc.c:461
void bu_vls_printf(struct bu_vls *vls, const char *fmt,...) _BU_ATTR_PRINTF23
Definition: vls.c:694
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
void quat_mat2quat(quat_t quat, const mat_t mat)
Quaternion math routines.
#define BU_VLS_INIT_ZERO
Definition: vls.h:84
int pid
Definition: ged.h:273
const char * bu_brlcad_root(const char *rhs, int fail_quietly)
Definition: brlcad_path.c:292
Definition: vls.h:56
char * dbi_filename
file name
Definition: raytrace.h:805
int _ged_run_rtwizard(struct ged *gedp)
Definition: rtwizard.c:54
#define TRUE