source: branches/blt4/packages/vizservers/vtkvis/RpVtkRenderServer.cpp @ 2542

Last change on this file since 2542 was 2542, checked in by gah, 12 years ago

update from trunk

File size: 10.1 KB
Line 
1
2/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
3/*
4 * Copyright (C) 2011, Purdue Research Foundation
5 *
6 * Author: Leif Delgass <ldelgass@purdue.edu>
7 */
8
9#include <cstdio>
10#include <cstring>
11#include <cstdlib>
12#include <cerrno>
13#include <unistd.h>
14#include <signal.h>
15
16#ifdef WANT_TRACE
17#include <sys/time.h>
18#endif
19
20#include <string>
21#include <sstream>
22
23#include "Trace.h"
24#include "RpVtkRenderServer.h"
25#include "RpVtkRendererCmd.h"
26#include "RpVtkRenderer.h"
27#include "PPMWriter.h"
28#include "TGAWriter.h"
29#ifdef USE_THREADS
30#include <pthread.h>
31#include "ResponseQueue.h"
32#endif
33
34using namespace Rappture::VtkVis;
35
36int Rappture::VtkVis::g_fdIn = STDIN_FILENO; ///< Input file descriptor
37int Rappture::VtkVis::g_fdOut = STDOUT_FILENO; ///< Output file descriptor
38FILE *Rappture::VtkVis::g_fIn = stdin; ///< Input file handle
39FILE *Rappture::VtkVis::g_fOut = stdout; ///< Output file handle
40FILE *Rappture::VtkVis::g_fLog = NULL; ///< Trace logging file handle
41Renderer *Rappture::VtkVis::g_renderer = NULL; ///< Main render worker
42
43#define ELAPSED_TIME(t1, t2) \
44    ((t1).tv_sec == (t2).tv_sec ? (((t2).tv_usec - (t1).tv_usec)/1.0e+3f) : \
45     (((t2).tv_sec - (t1).tv_sec))*1.0e+3f + (float)((t2).tv_usec - (t1).tv_usec)/1.0e+3f)
46
47#ifdef USE_THREADS
48static void
49queueFrame(ResponseQueue *queue, vtkUnsignedCharArray *imgData)
50{
51#ifdef DEBUG
52    if (g_renderer->getCameraMode() == Renderer::IMAGE) {
53        double xywh[4];
54        g_renderer->getScreenWorldCoords(xywh);
55        TRACE("Image bbox: %g %g %g %g",
56              xywh[0],
57              (xywh[1] + xywh[3]),
58              (xywh[0] + xywh[2]),
59              xywh[1]);
60    }
61
62#ifdef RENDER_TARGA
63    writeTGAFile("/tmp/frame.tga",
64                 imgData->GetPointer(0),
65                 g_renderer->getWindowWidth(),
66                 g_renderer->getWindowHeight(),
67                 TARGA_BYTES_PER_PIXEL);
68#else
69    writeTGAFile("/tmp/frame.tga",
70                 imgData->GetPointer(0),
71                 g_renderer->getWindowWidth(),
72                 g_renderer->getWindowHeight(),
73                 TARGA_BYTES_PER_PIXEL,
74                 true);
75#endif  /*RENDER_TARGA*/
76
77#else
78    if (g_renderer->getCameraMode() == Renderer::IMAGE) {
79        double xywh[4];
80        g_renderer->getCameraZoomRegion(xywh);
81        std::ostringstream oss;
82        oss.precision(12);
83        // Send upper left and lower right corners as bbox
84        oss << "nv>image -type image -bbox {"
85            << std::scientific
86            << xywh[0] << " "
87            << xywh[1] << " "
88            << xywh[2] << " "
89            << xywh[3] << "} -bytes";
90
91#ifdef RENDER_TARGA
92        queueTGA(queue, oss.str().c_str(),
93                 imgData->GetPointer(0),
94                 g_renderer->getWindowWidth(),
95                 g_renderer->getWindowHeight(),
96                 TARGA_BYTES_PER_PIXEL);
97#else
98        queuePPM(queue, oss.str().c_str(),
99                 imgData->GetPointer(0),
100                 g_renderer->getWindowWidth(),
101                 g_renderer->getWindowHeight());
102#endif  /*RENDER_TARGA*/
103    } else {
104#ifdef RENDER_TARGA
105        queueTGA(queue, "nv>image -type image -bytes",
106                 imgData->GetPointer(0),
107                 g_renderer->getWindowWidth(),
108                 g_renderer->getWindowHeight(),
109                 TARGA_BYTES_PER_PIXEL);
110#else
111        queuePPM(queue, "nv>image -type image -bytes",
112                 imgData->GetPointer(0),
113                 g_renderer->getWindowWidth(),
114                 g_renderer->getWindowHeight());
115#endif  /*RENDER_TARGA*/
116    }
117#endif  /*DEBUG*/
118}
119
120#else
121
122static void
123writeFrame(int fd, vtkUnsignedCharArray *imgData)
124{
125#ifdef DEBUG
126    if (g_renderer->getCameraMode() == Renderer::IMAGE) {
127        double xywh[4];
128        g_renderer->getScreenWorldCoords(xywh);
129        TRACE("Image bbox: %g %g %g %g",
130              xywh[0],
131              (xywh[1] + xywh[3]),
132              (xywh[0] + xywh[2]),
133              xywh[1]);
134    }
135
136#ifdef RENDER_TARGA
137    writeTGAFile("/tmp/frame.tga",
138                 imgData->GetPointer(0),
139                 g_renderer->getWindowWidth(),
140                 g_renderer->getWindowHeight(),
141                 TARGA_BYTES_PER_PIXEL);
142#else
143    writeTGAFile("/tmp/frame.tga",
144                 imgData->GetPointer(0),
145                 g_renderer->getWindowWidth(),
146                 g_renderer->getWindowHeight(),
147                 TARGA_BYTES_PER_PIXEL,
148                 true);
149#endif  /*RENDER_TARGA*/
150
151#else
152    if (g_renderer->getCameraMode() == Renderer::IMAGE) {
153        double xywh[4];
154        g_renderer->getCameraZoomRegion(xywh);
155        std::ostringstream oss;
156        oss.precision(12);
157        // Send upper left and lower right corners as bbox
158        oss << "nv>image -type image -bbox {"
159            << std::scientific
160            << xywh[0] << " "
161            << xywh[1] << " "
162            << xywh[2] << " "
163            << xywh[3] << "} -bytes";
164
165#ifdef RENDER_TARGA
166        writeTGA(fd, oss.str().c_str(),
167                 imgData->GetPointer(0),
168                 g_renderer->getWindowWidth(),
169                 g_renderer->getWindowHeight(),
170                 TARGA_BYTES_PER_PIXEL);
171#else
172        writePPM(fd, oss.str().c_str(),
173                 imgData->GetPointer(0),
174                 g_renderer->getWindowWidth(),
175                 g_renderer->getWindowHeight());
176#endif  /*RENDER_TARGA*/
177    } else {
178#ifdef RENDER_TARGA
179        writeTGA(fd, "nv>image -type image -bytes",
180                 imgData->GetPointer(0),
181                 g_renderer->getWindowWidth(),
182                 g_renderer->getWindowHeight(),
183                 TARGA_BYTES_PER_PIXEL);
184#else
185        writePPM(fd, "nv>image -type image -bytes",
186                 imgData->GetPointer(0),
187                 g_renderer->getWindowWidth(),
188                 g_renderer->getWindowHeight());
189#endif  /*RENDER_TARGA*/
190    }
191#endif  /*DEBUG*/
192}
193#endif /*USE_THREADS*/
194
195static void
196initService()
197{
198    const char *user = getenv("USER");
199    char *logName = NULL;
200    int logNameLen = 0;
201
202    if (user == NULL) {
203        logNameLen = 19+1;
204        logName = (char *)calloc(logNameLen, sizeof(char));
205        strncpy(logName, "/tmp/vtkvis_log.txt", logNameLen);
206    }
207    else {
208        logNameLen = 16+strlen(user)+4+1;
209        logName = (char *)calloc(logNameLen, sizeof(char));
210        strncpy(logName, "/tmp/vtkvis_log_", logNameLen);
211        strncat(logName, user, strlen(user));
212        strncat(logName, ".txt", 4);
213    }
214
215    // open log and map stderr to log file
216    g_fLog = fopen(logName, "w");
217    close(STDERR_FILENO);
218    dup2(fileno(g_fLog), STDERR_FILENO);
219    // flush junk
220    fflush(stderr);
221
222    // clean up malloc'd memory
223    if (logName != NULL) {
224        free(logName);
225    }
226}
227
228static void
229exitService()
230{
231    // close log file
232    if (g_fLog != NULL) {
233        fclose(g_fLog);
234        g_fLog = NULL;
235    }
236}
237
238#ifdef USE_THREADS
239static void *
240readerThread(void *clientData)
241{
242    ResponseQueue *queue = (ResponseQueue *)clientData;
243    Tcl_Interp *interp;
244
245    TRACE("starting reader thread");
246    interp = (Tcl_Interp *)queue->clientData();
247    vtkSmartPointer<vtkUnsignedCharArray> imgData =
248        vtkSmartPointer<vtkUnsignedCharArray>::New();
249    for (;;) {
250        int ret;
251
252        ret = processCommands(interp, g_fIn, g_fOut);
253        if (ret < 0)
254            break;
255        if (g_renderer->render()) {
256            TRACE("Rendering new frame");
257            g_renderer->getRenderedFrame(imgData);
258            queueFrame(queue, imgData);
259        } else {
260            TRACE("No render required");
261        }
262        if (feof(g_fIn))
263            break;
264    }   
265    return NULL;
266}
267
268static void *
269writerThread(void *clientData)
270{
271    ResponseQueue *queue = (ResponseQueue *)clientData;
272
273    TRACE("starting writer thread");
274    for (;;) {
275        Response *response;
276
277        response = queue->dequeue();
278        if (fwrite(response->message(), sizeof(char), response->length(),
279                   g_fOut) != response->length()) {
280            ERROR("short write while trying to write %ld bytes",
281                  response->length());
282        }
283        fflush(g_fOut);
284        delete response;
285        if (feof(g_fOut))
286            break;
287    }   
288    return NULL;
289}
290
291#endif  /*USE_THREADS*/
292
293int
294main(int argc, char *argv[])
295{
296    // Ignore SIGPIPE.  **Is this needed? **
297    signal(SIGPIPE, SIG_IGN);
298    initService();
299    initLog();
300
301    TRACE("Starting VTKVis Server");
302
303    g_fIn = stdin;
304    g_fOut = stdout;
305    g_fdIn = fileno(stdin);
306    g_fdOut = fileno(stdout);
307
308    /* This synchronizes the client with the server, so that the client
309     * doesn't start writing commands before the server is ready. It could
310     * also be used to supply information about the server (version, memory
311     * size, etc). */
312    fprintf(stdout, "VtkVis 1.0\n");
313    fflush(stdout);
314
315    g_renderer = new Renderer();
316
317    Tcl_Interp *interp = Tcl_CreateInterp();
318
319#ifdef USE_THREADS
320    ResponseQueue queue((void *)interp);
321    initTcl(interp, (ClientData)&queue);
322
323    pthread_t readerThreadId, writerThreadId;
324    if (pthread_create(&readerThreadId, NULL, &readerThread, &queue) < 0) {
325        ERROR("can't create reader thread: %s", strerror(errno));
326    }
327    if (pthread_create(&writerThreadId, NULL, &writerThread, &queue) < 0) {
328        ERROR("can't create writer thread: %s", strerror(errno));
329    }
330    if (pthread_join(readerThreadId, NULL) < 0) {
331        ERROR("can't join reader thread: %s", strerror(errno));
332    }
333    if (pthread_join(writerThreadId, NULL) < 0) {
334        ERROR("can't join writer thread: %s", strerror(errno));
335    }
336#else
337    initTcl(interp, (ClientData)NULL);
338    int ret = 0;
339
340    vtkSmartPointer<vtkUnsignedCharArray> imgData =
341        vtkSmartPointer<vtkUnsignedCharArray>::New();
342    while (1) {
343        ret = processCommands(interp, g_fIn, g_fOut);
344        if (ret < 0)
345            break;
346
347        if (g_renderer->render()) {
348            TRACE("Rendering new frame");
349            g_renderer->getRenderedFrame(imgData);
350            writeFrame(g_fdOut, imgData);
351        } else {
352            TRACE("No render required");
353        }
354
355        if (feof(g_fIn))
356            break;
357    }
358#endif
359    INFO("exiting vtkvis");
360    exitTcl(interp);
361    interp = NULL;
362
363    delete g_renderer;
364    g_renderer = NULL;
365
366    TRACE("Exiting VTKVis Server");
367
368    closeLog();
369    exitService();
370
371    return 0;
372}
373
Note: See TracBrowser for help on using the repository browser.