source: trunk/packages/vizservers/nanovis/nanovis.cpp @ 2831

Last change on this file since 2831 was 2831, checked in by ldelgass, 9 years ago

Refactor texture classes, misc. cleanups, cut down on header pollution -- still
need to fix header deps in Makefile.in

  • Property svn:eol-style set to native
File size: 66.9 KB
Line 
1/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 * ----------------------------------------------------------------------
4 * Nanovis: Visualization of Nanoelectronics Data
5 *
6 * ======================================================================
7 *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
8 *           Michael McLennan <mmclennan@purdue.edu>
9 *           Purdue Rendering and Perceptualization Lab (PURPL)
10 *
11 *  Copyright (c) 2004-2006  Purdue Research Foundation
12 *
13 *  See the file "license.terms" for information on usage and
14 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
15 * ======================================================================
16 */
17
18#include <assert.h>
19#include <errno.h>
20#include <fcntl.h>
21#include <getopt.h>
22#include <memory.h>
23#include <signal.h>
24#include <sys/resource.h>
25#include <sys/stat.h>
26#include <sys/time.h>
27#include <sys/times.h>
28#include <sys/types.h>
29#include <sys/uio.h> // for readv/writev
30#include <time.h>
31#include <unistd.h>
32
33#include <cstdlib>
34#include <cstdio>
35#include <cmath>
36
37#include <iostream>
38#include <fstream>
39#include <sstream>
40#include <string>
41
42#include <RpField1D.h>
43#include <RpFieldRect3D.h>
44#include <RpFieldPrism3D.h>
45#include <RpEncode.h>
46
47#include <R2/R2FilePath.h>
48#include <R2/R2Fonts.h>
49
50#include <vrutil/vrFilePath.h>
51
52#include <BMPImageLoaderImpl.h>
53#include <ImageLoaderFactory.h>
54
55#include <GL/glew.h>
56#include <GL/glut.h>
57
58#include "nanovis.h"
59#include "define.h"
60
61#include "FlowCmd.h"
62#include "Grid.h"
63#include "HeightMap.h"
64#include "NvCamera.h"
65#include "NvColorTableRenderer.h"
66#include "NvEventLog.h"
67#include "NvFlowVisRenderer.h"
68#include "NvLIC.h"
69#include "NvZincBlendeReconstructor.h"
70#include "PerfQuery.h"
71#include "PlaneRenderer.h"
72#ifdef USE_POINTSET_RENDERER
73#include "PointSetRenderer.h"
74#include "PointSet.h"
75#endif
76#include "RenderContext.h"
77#include "Switch.h"
78#include "Trace.h"
79#include "Unirect.h"
80#include "VelocityArrowsSlice.h"
81#include "VolumeInterpolator.h"
82#include "VolumeRenderer.h"
83#include "ZincBlendeVolume.h"
84
85#define SIZEOF_BMP_HEADER   54
86
87extern void NvInitCG(); // in Shader.cpp
88
89// Indicates "up" axis:  x=1, y=2, z=3, -x=-1, -y=-2, -z=-3
90enum AxisDirections {
91    X_POS = 1, Y_POS = 2, Z_POS = 3, X_NEG = -1, Y_NEG = -2, Z_NEG = -3
92};
93
94#define KEEPSTATS       1
95
96#define CVT2SECS(x)  ((double)(x).tv_sec) + ((double)(x).tv_usec * 1.0e-6)
97
98#define TRUE    1
99#define FALSE   0
100
101typedef struct {
102    pid_t pid;
103    size_t nFrames;             /* # of frames sent to client. */
104    size_t nBytes;              /* # of bytes for all frames. */
105    size_t nCommands;           /* # of commands executed */
106    double cmdTime;             /* Elasped time spend executing commands. */
107    struct timeval start;       /* Start of elapsed time. */
108} Stats;
109
110static Stats stats;
111
112// STATIC MEMBER DATA
113Grid *NanoVis::grid = NULL;
114int NanoVis::updir = Y_POS;
115NvCamera *NanoVis::cam = NULL;
116Tcl_HashTable NanoVis::volumeTable;
117Tcl_HashTable NanoVis::heightmapTable;
118VolumeRenderer *NanoVis::vol_renderer = NULL;
119#ifdef USE_POINTSET_RENDERER
120PointSetRenderer *NanoVis::pointset_renderer = NULL;
121std::vector<PointSet *> NanoVis::pointSet;
122#endif
123PlaneRenderer *NanoVis::plane_renderer = NULL;
124// pointers to 2D planes, currently handle up 10
125Texture2D *NanoVis::plane[10];
126NvColorTableRenderer *NanoVis::color_table_renderer = NULL;
127
128#ifndef NEW_FLOW_ENGINE
129NvParticleRenderer *NanoVis::flowVisRenderer = NULL;
130#else
131NvFlowVisRenderer *NanoVis::flowVisRenderer = NULL;
132#endif
133VelocityArrowsSlice *NanoVis::velocityArrowsSlice = 0;
134
135graphics::RenderContext *NanoVis::renderContext = NULL;
136NvLIC *NanoVis::licRenderer = NULL;
137R2Fonts *NanoVis::fonts;
138
139FILE *NanoVis::stdin = NULL;
140FILE *NanoVis::logfile = NULL;
141FILE *NanoVis::recfile = NULL;
142
143bool NanoVis::axis_on = true;
144bool NanoVis::config_pending = false;
145bool NanoVis::debug_flag = false;
146
147Tcl_Interp *NanoVis::interp;
148Tcl_DString NanoVis::cmdbuffer;
149
150//frame buffer for final rendering
151GLuint NanoVis::_final_color_tex = 0;
152GLuint NanoVis::_final_depth_rb = 0;
153GLuint NanoVis::_final_fbo = 0;
154int NanoVis::render_window = 0;       /* GLUT handle for the render window */
155int NanoVis::win_width = NPIX;        /* Width of the render window */
156int NanoVis::win_height = NPIX;       /* Height of the render window */
157
158unsigned char* NanoVis::screen_buffer = NULL;
159
160unsigned int NanoVis::flags = 0;
161Tcl_HashTable NanoVis::flowTable;
162double NanoVis::magMin = DBL_MAX;
163double NanoVis::magMax = -DBL_MAX;
164float NanoVis::xMin = FLT_MAX;
165float NanoVis::xMax = -FLT_MAX;
166float NanoVis::yMin = FLT_MAX;
167float NanoVis::yMax = -FLT_MAX;
168float NanoVis::zMin = FLT_MAX;
169float NanoVis::zMax = -FLT_MAX;
170float NanoVis::wMin = FLT_MAX;
171float NanoVis::wMax = -FLT_MAX;
172float NanoVis::xOrigin;
173float NanoVis::yOrigin;
174float NanoVis::zOrigin;
175
176/* FIXME: This variable is always true. */
177bool volume_mode = true;
178
179// in Command.cpp
180extern Tcl_Interp *initTcl();
181
182float vert[NMESH*NMESH*3];              //particle positions in main memory
183float slice_vector[NMESH*NMESH*4];      //per slice vectors in main memory
184
185// maps transfunc name to TransferFunction object
186Tcl_HashTable NanoVis::tfTable;
187
188PerfQuery *perf;                        //perfromance counter
189
190CGprogram m_passthru_fprog;
191CGparameter m_passthru_scale_param, m_passthru_bias_param;
192
193// Variables for mouse events
194
195// Default camera rotation angles.
196const float def_rot_x = 90.0f;
197const float def_rot_y = 180.0f;
198const float def_rot_z = -135.0f;
199
200// Default camera target.
201const float def_target_x = 0.0f;
202const float def_target_y = 0.0f;
203const float def_target_z = 100.0f;
204
205// Default camera location.
206const float def_eye_x = -0.0f;
207const float def_eye_y = -0.0f;
208const float def_eye_z = -2.5f;
209
210
211#ifndef XINETD
212// Last locations mouse events
213static int left_last_x;
214static int left_last_y;
215static int right_last_x;
216static int right_last_y;
217static bool left_down = false;
218static bool right_down = false;
219#endif /*XINETD*/
220
221// Image based flow visualization slice location
222// FLOW
223float NanoVis::lic_slice_x = 0.5f;
224float NanoVis::lic_slice_y = 0.5f;
225float NanoVis::lic_slice_z = 0.5f;
226int NanoVis::lic_axis = 2; // z axis
227
228#define RM_VOLUME 1
229#define RM_POINT 2
230
231int renderMode = RM_VOLUME;
232
233void removeAllData()
234{
235    //
236}
237
238void
239NanoVis::EventuallyRedraw(unsigned int flag)
240{
241    if (flag) {
242        flags |= flag;
243    }
244    if ((flags & REDRAW_PENDING) == 0) {
245        glutPostRedisplay();
246        flags |= REDRAW_PENDING;
247    }
248}
249
250#if KEEPSTATS
251
252static int
253WriteStats(const char *who, int code)
254{
255    double start, finish;
256    pid_t pid;
257    char buf[BUFSIZ];
258    Tcl_DString ds;
259
260    {
261        struct timeval tv;
262
263        /* Get ending time.  */
264        gettimeofday(&tv, NULL);
265        finish = CVT2SECS(tv);
266        tv = stats.start;
267        start = CVT2SECS(tv);
268    }
269    pid = getpid();
270    Tcl_DStringInit(&ds);
271
272    sprintf(buf, "<session server=\"%s\" ", who);
273    Tcl_DStringAppend(&ds, buf, -1);
274
275    gethostname(buf, BUFSIZ-1);
276    buf[BUFSIZ-1] = '\0';
277    Tcl_DStringAppend(&ds, "host=\"", -1);
278    Tcl_DStringAppend(&ds, buf, -1);
279    Tcl_DStringAppend(&ds, "\" ", -1);
280
281    strcpy(buf, ctime(&stats.start.tv_sec));
282    buf[strlen(buf) - 1] = '\0';
283    Tcl_DStringAppend(&ds, "date=\"", -1);
284    Tcl_DStringAppend(&ds, buf, -1);
285    Tcl_DStringAppend(&ds, "\" ", -1);
286
287    sprintf(buf, "date_secs=\"%ld\" ", stats.start.tv_sec);
288    Tcl_DStringAppend(&ds, buf, -1);
289
290    sprintf(buf, "pid=\"%d\" ", pid);
291    Tcl_DStringAppend(&ds, buf, -1);
292    sprintf(buf, "num_frames=\"%lu\" ", (unsigned long int)stats.nFrames);
293    Tcl_DStringAppend(&ds, buf, -1);
294    sprintf(buf, "frame_bytes=\"%lu\" ", (unsigned long int)stats.nBytes);
295    Tcl_DStringAppend(&ds, buf, -1);
296    sprintf(buf, "num_commands=\"%lu\" ", (unsigned long int)stats.nCommands);
297    Tcl_DStringAppend(&ds, buf, -1);
298    sprintf(buf, "cmd_time=\"%g\" ", stats.cmdTime);
299    Tcl_DStringAppend(&ds, buf, -1);
300    sprintf(buf, "session_time=\"%g\" ", finish - start);
301    Tcl_DStringAppend(&ds, buf, -1);
302    sprintf(buf, "status=\"%d\" ", code);
303    Tcl_DStringAppend(&ds, buf, -1);
304    {
305        long clocksPerSec = sysconf(_SC_CLK_TCK);
306        double clockRes = 1.0 / clocksPerSec;
307        struct tms tms;
308
309        memset(&tms, 0, sizeof(tms));
310        times(&tms);
311        sprintf(buf, "utime=\"%g\" ", tms.tms_utime * clockRes);
312        Tcl_DStringAppend(&ds, buf, -1);
313        sprintf(buf, "stime=\"%g\" ", tms.tms_stime * clockRes);
314        Tcl_DStringAppend(&ds, buf, -1);
315        sprintf(buf, "cutime=\"%g\" ", tms.tms_cutime * clockRes);
316        Tcl_DStringAppend(&ds, buf, -1);
317        sprintf(buf, "cstime=\"%g\" ", tms.tms_cstime * clockRes);
318        Tcl_DStringAppend(&ds, buf, -1);
319    }
320    Tcl_DStringAppend(&ds, "/>\n", -1);
321
322    {
323        int f;
324        ssize_t length;
325        int result;
326
327#define STATSDIR        "/var/tmp/visservers"
328#define STATSFILE       STATSDIR "/" "data.xml"
329        if (access(STATSDIR, X_OK) != 0) {
330            mkdir(STATSDIR, 0770);
331        }
332        length = Tcl_DStringLength(&ds);
333        f = open(STATSFILE, O_APPEND | O_CREAT | O_WRONLY, 0600);
334        result = FALSE;
335        if (f < 0) {
336            goto error;
337        }
338        if (write(f, Tcl_DStringValue(&ds), length) != length) {
339            goto error;
340        }
341        result = TRUE;
342    error:
343        if (f >= 0) {
344            close(f);
345        }
346        Tcl_DStringFree(&ds);
347        return result;
348    }
349}
350#endif
351
352static void
353DoExit(int code)
354{
355    TRACE("in DoExit\n");
356    removeAllData();
357
358#ifdef EVENTLOG
359    NvExitEventLog();
360#endif
361
362#ifdef XINETD
363    NvExitService();
364#endif
365
366#if KEEPSTATS
367    WriteStats("nanovis", code);
368#endif
369    closelog();
370    exit(code);
371}
372
373CGprogram
374LoadCgSourceProgram(CGcontext context, const char *fileName, CGprofile profile,
375                    const char *entryPoint)
376{
377    const char *path = R2FilePath::getInstance()->getPath(fileName);
378    if (path == NULL) {
379        ERROR("can't find program \"%s\"\n", fileName);
380    }
381    TRACE("cg program compiling: %s\n", path);
382    CGprogram program;
383    program = cgCreateProgramFromFile(context, CG_SOURCE, path, profile,
384                                      entryPoint, NULL);
385    cgGLLoadProgram(program);
386    CGerror LastError = cgGetError();
387    if (LastError) {
388        ERROR("Error message: %s\n", cgGetLastListing(context));
389    }
390    TRACE("successfully compiled program: %s\n", path);
391    delete [] path;
392    return program;
393}
394
395static int
396ExecuteCommand(Tcl_Interp *interp, Tcl_DString *dsPtr)
397{
398    struct timeval tv;
399    double start, finish;
400    int result;
401
402    TRACE("command: '%s'", Tcl_DStringValue(dsPtr));
403
404    gettimeofday(&tv, NULL);
405    start = CVT2SECS(tv);
406
407    if (NanoVis::recfile != NULL) {
408        fprintf(NanoVis::recfile, "%s", Tcl_DStringValue(dsPtr));
409        fflush(NanoVis::recfile);
410    }
411    result = Tcl_Eval(interp, Tcl_DStringValue(dsPtr));
412    Tcl_DStringSetLength(dsPtr, 0);
413
414    gettimeofday(&tv, NULL);
415    finish = CVT2SECS(tv);
416
417    stats.cmdTime += finish - start;
418    stats.nCommands++;
419    TRACE("leaving ExecuteCommand status=%d\n", result);
420    return result;
421}
422
423void
424NanoVis::pan(float dx, float dy)
425{
426    /* Move the camera and its target by equal amounts along the x and y
427     * axes. */
428    TRACE("pan: x=%f, y=%f\n", dx, dy);
429
430    cam->x(def_eye_x + dx);
431    cam->y(def_eye_y + dy);
432    TRACE("set eye to %f %f\n", cam->x(), cam->y());
433
434    cam->xAim(def_target_x + dx);
435    cam->yAim(def_target_y + dy);
436    TRACE("set aim to %f %f\n", cam->xAim(), cam->yAim());
437}
438
439
440/* Load a 3D volume
441 * index:       the index into the volume array, which stores pointers
442 *              to 3D volume instances
443 * data:        pointer to an array of floats.
444 * n_component: the number of scalars for each space point. All component
445 *              scalars for a point are placed consequtively in data array
446 *              width, height and depth: number of points in each dimension
447 */
448Volume *
449NanoVis::load_volume(const char *name, int width, int height, int depth,
450                     int n_component, float* data, double vmin, double vmax,
451                     double nzero_min)
452{
453    Tcl_HashEntry *hPtr;
454    hPtr = Tcl_FindHashEntry(&NanoVis::volumeTable, name);
455    if (hPtr != NULL) {
456        Volume *volPtr;
457        WARN("volume \"%s\" already exists", name);
458        volPtr = (Volume *)Tcl_GetHashValue(hPtr);
459        remove_volume(volPtr);
460    }
461    int isNew;
462    hPtr = Tcl_CreateHashEntry(&NanoVis::volumeTable, name, &isNew);
463    Volume* volPtr;
464    volPtr = new Volume(0.f, 0.f, 0.f, width, height, depth, 1., n_component,
465                data, vmin, vmax, nzero_min);
466    Tcl_SetHashValue(hPtr, volPtr);
467    volPtr->name(Tcl_GetHashKey(&NanoVis::volumeTable, hPtr));
468    return volPtr;
469}
470
471// Gets a colormap 1D texture by name.
472TransferFunction*
473NanoVis::get_transfunc(const char *name)
474{
475    Tcl_HashEntry *hPtr;
476
477    hPtr = Tcl_FindHashEntry(&tfTable, name);
478    if (hPtr == NULL) {
479        return NULL;
480    }
481    return (TransferFunction*)Tcl_GetHashValue(hPtr);
482}
483
484// Creates of updates a colormap 1D texture by name.
485TransferFunction*
486NanoVis::DefineTransferFunction(const char *name, size_t n, float *data)
487{
488    int isNew;
489    Tcl_HashEntry *hPtr;
490    TransferFunction *tfPtr;
491
492    hPtr = Tcl_CreateHashEntry(&tfTable, name, &isNew);
493    if (isNew) {
494        tfPtr = new TransferFunction(n, data);
495        tfPtr->name(Tcl_GetHashKey(&tfTable, hPtr));
496        Tcl_SetHashValue(hPtr, tfPtr);
497    } else {
498        /*
499         * You can't delete the transfer function because many
500         * objects may be holding its pointer.  We must update it.
501         */
502        tfPtr = (TransferFunction *)Tcl_GetHashValue(hPtr);
503        tfPtr->update(n, data);
504    }
505    return tfPtr;
506}
507
508int
509NanoVis::render_legend(TransferFunction *tf, double min, double max,
510                       int width, int height, const char* volArg)
511{
512    TRACE("in render_legend\n");
513
514    int old_width = win_width;
515    int old_height = win_height;
516
517    plane_renderer->set_screen_size(width, height);
518    resize_offscreen_buffer(width, height);
519
520    // generate data for the legend
521    float data[512];
522    for (int i=0; i < 256; i++) {
523        data[i] = data[i+256] = (float)(i/255.0);
524    }
525    plane[0] = new Texture2D(256, 2, GL_FLOAT, GL_LINEAR, 1, data);
526    int index = plane_renderer->add_plane(plane[0], tf);
527    plane_renderer->set_active_plane(index);
528
529    offscreen_buffer_capture();
530    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear screen
531    plane_renderer->render();
532
533    // INSOO
534    glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, screen_buffer);
535    //glReadPixels(0, 0, width, height, GL_BGR, GL_UNSIGNED_BYTE, screen_buffer); // INSOO's
536
537    {
538        char prefix[200];
539        ssize_t nWritten;
540
541        TRACE("ppm legend image");
542        sprintf(prefix, "nv>legend %s %g %g", volArg, min, max);
543        ppm_write(prefix);
544        nWritten = write(1, "\n", 1);
545        assert(nWritten == 1);
546    }
547    plane_renderer->remove_plane(index);
548    resize_offscreen_buffer(old_width, old_height);
549
550    TRACE("leaving render_legend\n");
551    delete plane[0];
552    return TCL_OK;
553}
554
555//initialize frame buffer objects for offscreen rendering
556void
557NanoVis::init_offscreen_buffer()
558{
559    TRACE("in init_offscreen_buffer\n");
560    // Initialize a fbo for final display.
561    glGenFramebuffersEXT(1, &_final_fbo);
562
563    glGenTextures(1, &_final_color_tex);
564    glBindTexture(GL_TEXTURE_2D, _final_color_tex);
565
566    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
567    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
568#ifdef NV40
569    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, win_width, win_height, 0,
570                 GL_RGB, GL_INT, NULL);
571#else
572    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, win_width, win_height, 0,
573                 GL_RGB, GL_INT, NULL);
574#endif
575    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _final_fbo);
576    glGenRenderbuffersEXT(1, &_final_depth_rb);
577    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, _final_depth_rb);
578    glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24,
579                             win_width, win_height);
580    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
581                              GL_TEXTURE_2D, _final_color_tex, 0);
582    glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
583                                 GL_RENDERBUFFER_EXT, _final_depth_rb);
584
585    GLenum status;
586    if (!CheckFBO(&status)) {
587        PrintFBOStatus(status, "final_fbo");
588        DoExit(3);
589    }
590
591    // Check framebuffer completeness at the end of initialization.
592    //CHECK_FRAMEBUFFER_STATUS();
593
594    //assert(glGetError()==0);
595    TRACE("leaving init_offscreen_buffer\n");
596}
597
598//resize the offscreen buffer
599void
600NanoVis::resize_offscreen_buffer(int w, int h)
601{
602    TRACE("in resize_offscreen_buffer(%d, %d)\n", w, h);
603    if ((w == win_width) && (h == win_height)) {
604        return;
605    }
606    win_width = w;
607    win_height = h;
608
609    if (fonts) {
610        fonts->resize(w, h);
611    }
612    TRACE("screen_buffer size: %d %d\n", w, h);
613
614    if (screen_buffer != NULL) {
615        delete [] screen_buffer;
616        screen_buffer = NULL;
617    }
618
619    screen_buffer = new unsigned char[4*win_width*win_height];
620    assert(screen_buffer != NULL);
621   
622    //delete the current render buffer resources
623    glDeleteTextures(1, &_final_color_tex);
624    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, _final_depth_rb);
625    glDeleteRenderbuffersEXT(1, &_final_depth_rb);
626
627    TRACE("before deleteframebuffers\n");
628    glDeleteFramebuffersEXT(1, &_final_fbo);
629
630    TRACE("reinitialize FBO\n");
631    //Reinitialize final fbo for final display
632    glGenFramebuffersEXT(1, &_final_fbo);
633
634    glGenTextures(1, &_final_color_tex);
635    glBindTexture(GL_TEXTURE_2D, _final_color_tex);
636
637    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
638    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
639#ifdef NV40
640    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, win_width, win_height, 0,
641                 GL_RGB, GL_INT, NULL);
642#else
643    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, win_width, win_height, 0,
644                 GL_RGB, GL_INT, NULL);
645#endif
646    TRACE("before bindframebuffer\n");
647    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _final_fbo);
648    TRACE("after bindframebuffer\n");
649    glGenRenderbuffersEXT(1, &_final_depth_rb);
650    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, _final_depth_rb);
651    glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24,
652                             win_width, win_height);
653    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
654                              GL_TEXTURE_2D, _final_color_tex, 0);
655    glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
656                                 GL_RENDERBUFFER_EXT, _final_depth_rb);
657
658    GLenum status;
659    if (!CheckFBO(&status)) {
660        PrintFBOStatus(status, "final_fbo");
661        DoExit(3);
662    }
663
664    //CHECK_FRAMEBUFFER_STATUS();
665    TRACE("change camera\n");
666    //change the camera setting
667    cam->set_screen_size(0, 0, win_width, win_height);
668    plane_renderer->set_screen_size(win_width, win_height);
669
670    TRACE("leaving resize_offscreen_buffer(%d, %d)\n", w, h);
671}
672
673/*
674 * FIXME: This routine is fairly expensive (60000 floating pt divides).
675 *      I've put an ifdef around the call to it so that the released
676 *      builds don't include it.  Define PROTOTYPE to 1 in config.h
677 *      to turn it back on.
678 */
679void
680make_test_2D_data()
681{
682    int w = 300;
683    int h = 200;
684    float *data = new float[w*h];
685
686    //procedurally make a gradient plane
687    for (int j = 0; j < h; j++){
688        for (int i = 0; i < w; i++){
689            data[w*j+i] = float(i)/float(w);
690        }
691    }
692
693    NanoVis::plane[0] = new Texture2D(w, h, GL_FLOAT, GL_LINEAR, 1, data);
694    delete[] data;
695}
696
697void NanoVis::initParticle()
698{
699    flowVisRenderer->initialize();
700    licRenderer->make_patterns();
701}
702
703void CgErrorCallback(void)
704{
705    CGerror lastError = cgGetError();
706
707    if (lastError) {
708        TRACE("\n---------------------------------------------------\n");
709        TRACE("%s\n\n", cgGetErrorString(lastError));
710        TRACE("%s\n", cgGetLastListing(g_context));
711        TRACE("-----------------------------------------------------\n");
712        TRACE("Cg error, exiting...\n");
713        cgDestroyContext(g_context);
714        DoExit(-1);
715    }
716}
717
718void NanoVis::init(const char* path)
719{
720    // print system information
721    system_info();
722
723    if (path == NULL) {
724        ERROR("No path defined for shaders or resources\n");
725        DoExit(1);
726    }
727    GLenum err = glewInit();
728    if (GLEW_OK != err) {
729        ERROR("%s\n", glewGetErrorString(err));
730        getchar();
731        //assert(false);
732    }
733    TRACE("Using GLEW %s\n", glewGetString(GLEW_VERSION));
734
735    if (!R2FilePath::getInstance()->setPath(path)) {
736        ERROR("can't set file path to %s\n", path);
737        DoExit(1);
738    }
739
740    vrFilePath::getInstance()->setPath(path);
741   
742    NvInitCG();
743    NvShader::setErrorCallback(CgErrorCallback);
744   
745    fonts = new R2Fonts();
746    fonts->addFont("verdana", "verdana.fnt");
747    fonts->setFont("verdana");
748   
749    color_table_renderer = new NvColorTableRenderer();
750    color_table_renderer->setFonts(fonts);
751#ifndef NEW_FLOW_ENGINE
752    flowVisRenderer = new NvParticleRenderer(NMESH, NMESH, g_context);
753#else
754    flowVisRenderer = new NvFlowVisRenderer(NMESH, NMESH, g_context);
755#endif
756
757    NanoVis::velocityArrowsSlice = new VelocityArrowsSlice;
758
759    licRenderer = new NvLIC(NMESH, NPIX, NPIX, lic_axis,
760                            Vector3(lic_slice_x, lic_slice_y, lic_slice_z),
761                            g_context);
762
763    ImageLoaderFactory::getInstance()->addLoaderImpl("bmp", new BMPImageLoaderImpl());
764    grid = new Grid();
765    grid->setFont(fonts);
766
767#ifdef USE_POINTSET_RENDERER
768    pointset_renderer = new PointSetRenderer();
769#endif
770}
771
772/*----------------------------------------------------*/
773void
774NanoVis::initGL(void)
775{
776    TRACE("in initGL\n");
777    //buffer to store data read from the screen
778    if (screen_buffer) {
779        delete[] screen_buffer;
780        screen_buffer = NULL;
781    }
782    screen_buffer = new unsigned char[4*win_width*win_height];
783    assert(screen_buffer != NULL);
784
785    //create the camera with default setting
786    cam = new NvCamera(0, 0, win_width, win_height,
787                       def_eye_x, def_eye_y, def_eye_z,          /* location. */
788                       def_target_x, def_target_y, def_target_z, /* target. */
789                       def_rot_x, def_rot_y, def_rot_z);         /* angle. */
790
791    glEnable(GL_TEXTURE_2D);
792    glShadeModel(GL_FLAT);
793    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
794
795    glClearColor(0,0,0,1);
796    //glClearColor(0.7,0.7,0.7,1);
797    glClear(GL_COLOR_BUFFER_BIT);
798
799    //initialize lighting
800    GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0};
801    GLfloat mat_shininess[] = {30.0};
802    GLfloat white_light[] = {1.0, 1.0, 1.0, 1.0};
803    GLfloat green_light[] = {0.1, 0.5, 0.1, 1.0};
804
805    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
806    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
807    glLightfv(GL_LIGHT0, GL_DIFFUSE, white_light);
808    glLightfv(GL_LIGHT0, GL_SPECULAR, white_light);
809    glLightfv(GL_LIGHT1, GL_DIFFUSE, green_light);
810    glLightfv(GL_LIGHT1, GL_SPECULAR, white_light);
811
812    // init table of transfer functions
813    Tcl_InitHashTable(&tfTable, TCL_STRING_KEYS);
814
815    //check if performance query is supported
816    if(check_query_support()){
817        //create queries to count number of rendered pixels
818        perf = new PerfQuery();
819    }
820
821    init_offscreen_buffer();    //frame buffer object for offscreen rendering
822
823    //create volume renderer and add volumes to it
824    vol_renderer = new VolumeRenderer();
825
826    // create
827    renderContext = new graphics::RenderContext();
828
829    //create an 2D plane renderer
830    plane_renderer = new PlaneRenderer(g_context, win_width, win_height);
831#if PROTOTYPE
832    make_test_2D_data();
833    plane_renderer->add_plane(plane[0], get_transfunc("default"));
834#endif
835
836    //assert(glGetError()==0);
837
838    TRACE("leaving initGL\n");
839}
840
841#if DO_RLE
842char rle[512*512*3];
843int rle_size;
844
845short offsets[512*512*3];
846int offsets_size;
847
848void
849do_rle()
850{
851    int len = NanoVis::win_width*NanoVis::win_height*3;
852    rle_size = 0;
853    offsets_size = 0;
854
855    int i=0;
856    while(i<len){
857        if (NanoVis::screen_buffer[i] == 0) {
858            int pos = i+1;
859            while ( (pos<len) && (NanoVis::screen_buffer[pos] == 0)) {
860                pos++;
861            }
862            offsets[offsets_size++] = -(pos - i);
863            i = pos;
864        }
865
866        else {
867            int pos;
868            for (pos = i; (pos<len) && (NanoVis::screen_buffer[pos] != 0);pos++){
869                rle[rle_size++] = NanoVis::screen_buffer[pos];
870            }
871            offsets[offsets_size++] = (pos - i);
872            i = pos;
873        }
874
875    }
876}
877#endif
878
879// used internally to build up the BMP file header
880// Writes an integer value into the header data structure at pos
881static inline void
882bmp_header_add_int(unsigned char* header, int& pos, int data)
883{
884#ifdef WORDS_BIGENDIAN
885    header[pos++] = (data >> 24) & 0xFF;
886    header[pos++] = (data >> 16) & 0xFF;
887    header[pos++] = (data >> 8)  & 0xFF;
888    header[pos++] = (data)       & 0xFF;
889#else
890    header[pos++] = data & 0xff;
891    header[pos++] = (data >> 8) & 0xff;
892    header[pos++] = (data >> 16) & 0xff;
893    header[pos++] = (data >> 24) & 0xff;
894#endif
895}
896
897// INSOO
898// FOR DEBUGGING
899void
900NanoVis::bmp_write_to_file(int frame_number, const char *directory_name)
901{
902    unsigned char header[SIZEOF_BMP_HEADER];
903    int pos = 0;
904    header[pos++] = 'B';
905    header[pos++] = 'M';
906
907    // BE CAREFUL:  BMP files must have an even multiple of 4 bytes
908    // on each scan line.  If need be, we add padding to each line.
909    int pad = 0;
910    if ((3*win_width) % 4 > 0) {
911        pad = 4 - ((3*win_width) % 4);
912    }
913
914    // file size in bytes
915    int fsize = (3*win_width+pad)*win_height + SIZEOF_BMP_HEADER;
916    bmp_header_add_int(header, pos, fsize);
917
918    // reserved value (must be 0)
919    bmp_header_add_int(header, pos, 0);
920
921    // offset in bytes to start of bitmap data
922    bmp_header_add_int(header, pos, SIZEOF_BMP_HEADER);
923
924    // size of the BITMAPINFOHEADER
925    bmp_header_add_int(header, pos, 40);
926
927    // width of the image in pixels
928    bmp_header_add_int(header, pos, win_width);
929
930    // height of the image in pixels
931    bmp_header_add_int(header, pos, win_height);
932
933    // 1 plane + (24 bits/pixel << 16)
934    bmp_header_add_int(header, pos, 1572865);
935
936    // no compression
937    // size of image for compression
938    bmp_header_add_int(header, pos, 0);
939    bmp_header_add_int(header, pos, 0);
940
941    // x pixels per meter
942    // y pixels per meter
943    bmp_header_add_int(header, pos, 0);
944    bmp_header_add_int(header, pos, 0);
945
946    // number of colors used (0 = compute from bits/pixel)
947    // number of important colors (0 = all colors important)
948    bmp_header_add_int(header, pos, 0);
949    bmp_header_add_int(header, pos, 0);
950
951    // BE CAREFUL: BMP format wants BGR ordering for screen data
952    unsigned char* scr = screen_buffer;
953    for (int row=0; row < win_height; row++) {
954        for (int col=0; col < win_width; col++) {
955            unsigned char tmp = scr[2];
956            scr[2] = scr[0];  // B
957            scr[0] = tmp;     // R
958            scr += 3;
959        }
960        scr += pad;  // skip over padding already in screen data
961    }
962
963    FILE* f;
964    char filename[100];
965    if (frame_number >= 0) {
966        if (directory_name)
967            sprintf(filename, "%s/image%03d.bmp", directory_name, frame_number);
968        else
969            sprintf(filename, "/tmp/flow_animation/image%03d.bmp", frame_number);
970
971        TRACE("Writing %s\n", filename);
972        f = fopen(filename, "wb");
973        if (f == 0) {
974            ERROR("cannot create file\n");
975        }
976    } else {
977        f = fopen("/tmp/image.bmp", "wb");
978        if (f == 0) {
979            ERROR("cannot create file\n");
980        }
981    }
982    if (fwrite(header, SIZEOF_BMP_HEADER, 1, f) != 1) {
983        ERROR("can't write header: short write\n");
984    }
985    if (fwrite(screen_buffer, (3*win_width+pad)*win_height, 1, f) != 1) {
986        ERROR("can't write data: short write\n");
987    }
988    fclose(f);
989}
990
991void
992NanoVis::bmp_write(const char *prefix)
993{
994    unsigned char header[SIZEOF_BMP_HEADER];
995    ssize_t nWritten;
996    int pos = 0;
997
998    // BE CAREFUL:  BMP files must have an even multiple of 4 bytes
999    // on each scan line.  If need be, we add padding to each line.
1000    int pad = 0;
1001    if ((3*win_width) % 4 > 0) {
1002        pad = 4 - ((3*win_width) % 4);
1003    }
1004    pad = 0;
1005    int fsize = (3*win_width+pad)*win_height + sizeof(header);
1006
1007    char string[200];
1008    sprintf(string, "%s %d\n", prefix, fsize);
1009    nWritten = write(1, string, strlen(string));
1010    assert(nWritten == (ssize_t)strlen(string));
1011    header[pos++] = 'B';
1012    header[pos++] = 'M';
1013
1014    // file size in bytes
1015    bmp_header_add_int(header, pos, fsize);
1016
1017    // reserved value (must be 0)
1018    bmp_header_add_int(header, pos, 0);
1019
1020    // offset in bytes to start of bitmap data
1021    bmp_header_add_int(header, pos, SIZEOF_BMP_HEADER);
1022
1023    // size of the BITMAPINFOHEADER
1024    bmp_header_add_int(header, pos, 40);
1025
1026    // width of the image in pixels
1027    bmp_header_add_int(header, pos, win_width);
1028
1029    // height of the image in pixels
1030    bmp_header_add_int(header, pos, win_height);
1031
1032    // 1 plane + (24 bits/pixel << 16)
1033    bmp_header_add_int(header, pos, 1572865);
1034
1035    // no compression
1036    // size of image for compression
1037    bmp_header_add_int(header, pos, 0);
1038    bmp_header_add_int(header, pos, 0);
1039
1040    // x pixels per meter
1041    // y pixels per meter
1042    bmp_header_add_int(header, pos, 0);
1043    bmp_header_add_int(header, pos, 0);
1044
1045    // number of colors used (0 = compute from bits/pixel)
1046    // number of important colors (0 = all colors important)
1047    bmp_header_add_int(header, pos, 0);
1048    bmp_header_add_int(header, pos, 0);
1049
1050    // BE CAREFUL: BMP format wants BGR ordering for screen data
1051    unsigned char* scr = screen_buffer;
1052    for (int row=0; row < win_height; row++) {
1053        for (int col=0; col < win_width; col++) {
1054            unsigned char tmp = scr[2];
1055            scr[2] = scr[0];  // B
1056            scr[0] = tmp;     // R
1057            scr += 3;
1058        }
1059        scr += pad;  // skip over padding already in screen data
1060    }
1061
1062    nWritten = write(1, header, SIZEOF_BMP_HEADER);
1063    assert(nWritten == SIZEOF_BMP_HEADER);
1064    nWritten = write(1, screen_buffer, (3*win_width+pad)*win_height);
1065    assert(nWritten == (3*win_width+pad)*win_height);
1066    stats.nFrames++;
1067    stats.nBytes += (3*win_width+pad)*win_height;
1068}
1069
1070/*
1071 * ppm_write --
1072 *
1073 *  Writes the screen image as PPM binary data to the nanovisviewer
1074 *  client.  The PPM binary format is very simple.
1075 *
1076 *      P6 w h 255\n
1077 *      3-byte RGB pixel data.
1078 *
1079 *  The nanovisviewer client (using the TkImg library) will do less work
1080 *  to unpack this format, as opposed to BMP or PNG.  (This doesn't
1081 *  eliminate the need to look into DXT compression performed on the GPU).
1082 *
1083 *      Note that currently the image data from the screen is both row-padded
1084 *      and the scan lines are reversed.  This routine could be made even
1085 *      simpler (faster) if the screen buffer is an array of packed 3-bytes
1086 *      per pixels (no padding) and where the origin is the top-left corner.
1087 */
1088void
1089NanoVis::ppm_write(const char *prefix)
1090{
1091#define PPM_MAXVAL 255
1092    char header[200];
1093
1094    TRACE("Enter ppm_write (%dx%d)\n", win_width, win_height);
1095    // Generate the PPM binary file header
1096    sprintf(header, "P6 %d %d %d\n", win_width, win_height, PPM_MAXVAL);
1097
1098    size_t header_length = strlen(header);
1099    size_t data_length = win_width * win_height * 3;
1100
1101    char command[200];
1102    sprintf(command, "%s %lu\n", prefix,
1103            (unsigned long)header_length + data_length);
1104
1105    size_t wordsPerRow = (win_width * 24 + 31) / 32;
1106    size_t bytesPerRow = wordsPerRow * 4;
1107    size_t rowLength = win_width * 3;
1108    size_t nRecs = win_height + 2;
1109
1110    struct iovec *iov;
1111    iov = (struct iovec *)malloc(sizeof(struct iovec) * nRecs);
1112
1113    // Write the nanovisviewer command, then the image header and data.
1114    // Command
1115    iov[0].iov_base = command;
1116    iov[0].iov_len = strlen(command);
1117    // Header of image data
1118    iov[1].iov_base = header;
1119    iov[1].iov_len = header_length;
1120    // Image data.
1121    int y;
1122    unsigned char *srcRowPtr = screen_buffer;
1123    for (y = win_height + 1; y >= 2; y--) {
1124        iov[y].iov_base = srcRowPtr;
1125        iov[y].iov_len = rowLength;
1126        srcRowPtr += bytesPerRow;
1127    }
1128    if (writev(1, iov, nRecs) < 0) {
1129        ERROR("write failed: %s\n", strerror(errno));
1130    }
1131    free(iov);
1132    stats.nFrames++;
1133    stats.nBytes += (bytesPerRow * win_height);
1134    TRACE("Leaving ppm_write (%dx%d)\n", win_width, win_height);
1135}
1136
1137void
1138NanoVis::sendDataToClient(const char *command, const char *data, size_t dlen)
1139{
1140    /*
1141      char header[200];
1142
1143      // Generate the PPM binary file header
1144      sprintf(header, "P6 %d %d %d\n", win_width, win_height, PPM_MAXVAL);
1145
1146      size_t header_length = strlen(header);
1147      size_t data_length = win_width * win_height * 3;
1148
1149      char command[200];
1150      sprintf(command, "%s %lu\n", prefix,
1151      (unsigned long)header_length + data_length);
1152    */
1153
1154    //    size_t wordsPerRow = (win_width * 24 + 31) / 32;
1155    //    size_t bytesPerRow = wordsPerRow * 4;
1156    //    size_t rowLength = win_width * 3;
1157    size_t nRecs = 2;
1158
1159    struct iovec *iov = new iovec[nRecs];
1160
1161    // Write the nanovisviewer command, then the image header and data.
1162    // Command
1163    // FIXME: shouldn't have to cast this
1164    iov[0].iov_base = (char *)command;
1165    iov[0].iov_len = strlen(command);
1166    // Data
1167    // FIXME: shouldn't have to cast this
1168    iov[1].iov_base = (char *)data;
1169    iov[1].iov_len = dlen;
1170    if (writev(1, iov, nRecs) < 0) {
1171        ERROR("write failed: %s\n", strerror(errno));
1172    }
1173    delete [] iov;
1174    // stats.nFrames++;
1175    // stats.nBytes += (bytesPerRow * win_height);
1176}
1177
1178
1179/*----------------------------------------------------*/
1180void
1181NanoVis::idle()
1182{
1183    TRACE("in idle()\n");
1184    glutSetWindow(render_window);
1185
1186#ifdef XINETD
1187    xinetd_listen();
1188#else
1189    glutPostRedisplay();
1190#endif
1191    TRACE("leaving idle()\n");
1192}
1193
1194void
1195NanoVis::display_offscreen_buffer()
1196{
1197    TRACE("in display_offscreen_buffer\n");
1198    glEnable(GL_TEXTURE_2D);
1199    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1200    glBindTexture(GL_TEXTURE_2D, _final_color_tex);
1201
1202    glViewport(0, 0, win_width, win_height);
1203    glMatrixMode(GL_PROJECTION);
1204    glLoadIdentity();
1205    gluOrtho2D(0, win_width, 0, win_height);
1206    glMatrixMode(GL_MODELVIEW);
1207    glLoadIdentity();
1208
1209    glColor3f(1.,1.,1.);                //MUST HAVE THIS LINE!!!
1210    glBegin(GL_QUADS);
1211    {
1212        glTexCoord2f(0, 0); glVertex2f(0, 0);
1213        glTexCoord2f(1, 0); glVertex2f(win_width, 0);
1214        glTexCoord2f(1, 1); glVertex2f(win_width, win_height);
1215        glTexCoord2f(0, 1); glVertex2f(0, win_height);
1216    }
1217    glEnd();
1218    TRACE("leaving display_offscreen_buffer\n");
1219}
1220
1221#if 0
1222//oddeven sort on GPU
1223void
1224sortstep()
1225{
1226    // perform one step of the current sorting algorithm
1227
1228#ifdef notdef
1229    // swap buffers
1230    int sourceBuffer = targetBuffer;
1231    targetBuffer = (targetBuffer+1)%2;
1232    int pstage = (1<<stage);
1233    int ppass  = (1<<pass);
1234    int activeBitonicShader = 0;
1235
1236#ifdef _WIN32
1237    buffer->BindBuffer(wglTargets[sourceBuffer]);
1238#else
1239    buffer->BindBuffer(glTargets[sourceBuffer]);
1240#endif
1241    if (buffer->IsDoubleBuffered()) glDrawBuffer(glTargets[targetBuffer]);
1242#endif
1243
1244    checkGLError("after db");
1245
1246    int pstage = (1<<stage);
1247    int ppass  = (1<<pass);
1248    //int activeBitonicShader = 0;
1249
1250    // switch on correct sorting shader
1251    oddevenMergeSort.bind();
1252    glUniform3fARB(oddevenMergeSort.getUniformLocation("Param1"), float(pstage+pstage),
1253                   float(ppass%pstage), float((pstage+pstage)-(ppass%pstage)-1));
1254    glUniform3fARB(oddevenMergeSort.getUniformLocation("Param2"),
1255                   float(psys_width), float(psys_height), float(ppass));
1256    glUniform1iARB(oddevenMergeSort.getUniformLocation("Data"), 0);
1257    staticdebugmsg("sort","stage "<<pstage<<" pass "<<ppass);
1258
1259    // This clear is not necessary for sort to function. But if we are in
1260    // interactive mode unused parts of the texture that are visible will look
1261    // bad.
1262#ifdef notdef
1263    if (!perfTest) glClear(GL_COLOR_BUFFER_BIT);
1264
1265    buffer->Bind();
1266    buffer->EnableTextureTarget();
1267#endif
1268
1269    // Initiate the sorting step on the GPU a full-screen quad
1270    glBegin(GL_QUADS);
1271    {
1272#ifdef notdef
1273        glMultiTexCoord4fARB(GL_TEXTURE0_ARB,0.0f,0.0f,0.0f,1.0f);
1274        glVertex2f(-1.0f,-1.0f);
1275        glMultiTexCoord4fARB(GL_TEXTURE0_ARB,float(psys_width),0.0f,1.0f,1.0f);
1276        glVertex2f(1.0f,-1.0f);
1277        glMultiTexCoord4fARB(GL_TEXTURE0_ARB,float(psys_width),float(psys_height),1.0f,0.0f);
1278        glVertex2f(1.0f,1.0f);
1279        glMultiTexCoord4fARB(GL_TEXTURE0_ARB,0.0f,float(psys_height),0.0f,0.0f);
1280        glVertex2f(-1.0f,1.0f);
1281#endif
1282        glMultiTexCoord4fARB(GL_TEXTURE0_ARB,0.0f,0.0f,0.0f,1.0f);
1283        glVertex2f(0.,0.);
1284        glMultiTexCoord4fARB(GL_TEXTURE0_ARB,float(psys_width),0.0f,1.0f,1.0f);
1285        glVertex2f(float(psys_width), 0.);
1286        glMultiTexCoord4fARB(GL_TEXTURE0_ARB,float(psys_width),float(psys_height),1.0f,0.0f);
1287        glVertex2f(float(psys_width), float(psys_height));
1288        glMultiTexCoord4fARB(GL_TEXTURE0_ARB,0.0f,float(psys_height),0.0f,0.0f);
1289        glVertex2f(0., float(psys_height));
1290    }
1291    glEnd();
1292
1293    // switch off sorting shader
1294    oddevenMergeSort.release();
1295
1296    //buffer->DisableTextureTarget();
1297
1298    //assert(glGetError()==0);
1299}
1300#endif
1301
1302void
1303draw_3d_axis()
1304{
1305    glDisable(GL_TEXTURE_2D);
1306    glEnable(GL_DEPTH_TEST);
1307
1308    //draw axes
1309    GLUquadric *obj;
1310
1311    obj = gluNewQuadric();
1312
1313    glDepthFunc(GL_LESS);
1314    glEnable(GL_COLOR_MATERIAL);
1315    glEnable(GL_DEPTH_TEST);
1316    glDisable(GL_BLEND);
1317
1318    int segments = 50;
1319
1320    glColor3f(0.8, 0.8, 0.8);
1321    glPushMatrix();
1322    glTranslatef(0.4, 0., 0.);
1323    glRotatef(90, 1, 0, 0);
1324    glRotatef(180, 0, 1, 0);
1325    glScalef(0.0005, 0.0005, 0.0005);
1326    glutStrokeCharacter(GLUT_STROKE_ROMAN, 'x');
1327    glPopMatrix();
1328
1329    glPushMatrix();
1330    glTranslatef(0., 0.4, 0.);
1331    glRotatef(90, 1, 0, 0);
1332    glRotatef(180, 0, 1, 0);
1333    glScalef(0.0005, 0.0005, 0.0005);
1334    glutStrokeCharacter(GLUT_STROKE_ROMAN, 'y');
1335    glPopMatrix();
1336
1337    glPushMatrix();
1338    glTranslatef(0., 0., 0.4);
1339    glRotatef(90, 1, 0, 0);
1340    glRotatef(180, 0, 1, 0);
1341    glScalef(0.0005, 0.0005, 0.0005);
1342    glutStrokeCharacter(GLUT_STROKE_ROMAN, 'z');
1343    glPopMatrix();
1344
1345    glEnable(GL_LIGHTING);
1346    glEnable(GL_LIGHT0);
1347
1348    //glColor3f(0.2, 0.2, 0.8);
1349    glPushMatrix();
1350    glutSolidSphere(0.02, segments, segments );
1351    glPopMatrix();
1352
1353    glPushMatrix();
1354    glRotatef(-90, 1, 0, 0);
1355    gluCylinder(obj, 0.01, 0.01, 0.3, segments, segments);
1356    glPopMatrix();
1357
1358    glPushMatrix();
1359    glTranslatef(0., 0.3, 0.);
1360    glRotatef(-90, 1, 0, 0);
1361    gluCylinder(obj, 0.02, 0.0, 0.06, segments, segments);
1362    glPopMatrix();
1363
1364    glPushMatrix();
1365    glRotatef(90, 0, 1, 0);
1366    gluCylinder(obj, 0.01, 0.01, 0.3, segments, segments);
1367    glPopMatrix();
1368
1369    glPushMatrix();
1370    glTranslatef(0.3, 0., 0.);
1371    glRotatef(90, 0, 1, 0);
1372    gluCylinder(obj, 0.02, 0.0, 0.06, segments, segments);
1373    glPopMatrix();
1374
1375    glPushMatrix();
1376    gluCylinder(obj, 0.01, 0.01, 0.3, segments, segments);
1377    glPopMatrix();
1378
1379    glPushMatrix();
1380    glTranslatef(0., 0., 0.3);
1381    gluCylinder(obj, 0.02, 0.0, 0.06, segments, segments);
1382    glPopMatrix();
1383
1384    glDisable(GL_LIGHTING);
1385    glDisable(GL_DEPTH_TEST);
1386    gluDeleteQuadric(obj);
1387
1388    glEnable(GL_TEXTURE_2D);
1389    glDisable(GL_DEPTH_TEST);
1390}
1391
1392void NanoVis::update()
1393{
1394    if (vol_renderer->_volumeInterpolator->is_started()) {
1395        struct timeval clock;
1396        gettimeofday(&clock, NULL);
1397        double elapsed_time;
1398
1399        elapsed_time = clock.tv_sec + clock.tv_usec/1000000.0 -
1400            vol_renderer->_volumeInterpolator->getStartTime();
1401
1402        TRACE("%lf %lf\n", elapsed_time,
1403               vol_renderer->_volumeInterpolator->getInterval());
1404        float fraction;
1405        float f;
1406
1407        f = fmod((float) elapsed_time, (float)vol_renderer->_volumeInterpolator->getInterval());
1408        if (f == 0.0) {
1409            fraction = 0.0f;
1410        } else {
1411            fraction = f / vol_renderer->_volumeInterpolator->getInterval();
1412        }
1413        TRACE("fraction : %f\n", fraction);
1414        vol_renderer->_volumeInterpolator->update(fraction);
1415    }
1416}
1417
1418void
1419NanoVis::SetVolumeRanges()
1420{
1421    double xMin, xMax, yMin, yMax, zMin, zMax, wMin, wMax;
1422
1423    TRACE("in SetVolumeRanges\n");
1424    xMin = yMin = zMin = wMin = FLT_MAX;
1425    xMax = yMax = zMax = wMax = -FLT_MAX;
1426    Tcl_HashEntry *hPtr;
1427    Tcl_HashSearch iter;
1428    for (hPtr = Tcl_FirstHashEntry(&volumeTable, &iter); hPtr != NULL;
1429         hPtr = Tcl_NextHashEntry(&iter)) {
1430        Volume *volPtr;
1431
1432        volPtr = (Volume *)Tcl_GetHashValue(hPtr);
1433        if (xMin > volPtr->xAxis.min()) {
1434            xMin = volPtr->xAxis.min();
1435        }
1436        if (xMax < volPtr->xAxis.max()) {
1437            xMax = volPtr->xAxis.max();
1438        }
1439        if (yMin > volPtr->yAxis.min()) {
1440            yMin = volPtr->yAxis.min();
1441        }
1442        if (yMax < volPtr->yAxis.max()) {
1443            yMax = volPtr->yAxis.max();
1444        }
1445        if (zMin > volPtr->zAxis.min()) {
1446            zMin = volPtr->zAxis.min();
1447        }
1448        if (zMax < volPtr->zAxis.max()) {
1449            zMax = volPtr->zAxis.max();
1450        }
1451        if (wMin > volPtr->wAxis.min()) {
1452            wMin = volPtr->wAxis.min();
1453        }
1454        if (wMax < volPtr->wAxis.max()) {
1455            wMax = volPtr->wAxis.max();
1456        }
1457    }
1458    if ((xMin < DBL_MAX) && (xMax > -DBL_MAX)) {
1459        grid->xAxis.SetScale(xMin, xMax);
1460    }
1461    if ((yMin < DBL_MAX) && (yMax > -DBL_MAX)) {
1462        grid->yAxis.SetScale(yMin, yMax);
1463    }
1464    if ((zMin < DBL_MAX) && (zMax > -DBL_MAX)) {
1465        grid->zAxis.SetScale(zMin, zMax);
1466    }
1467    if ((wMin < DBL_MAX) && (wMax > -DBL_MAX)) {
1468        Volume::valueMin = wMin;
1469        Volume::valueMax = wMax;
1470    }
1471    Volume::update_pending = false;
1472    TRACE("leaving SetVolumeRanges\n");
1473}
1474
1475void
1476NanoVis::SetHeightmapRanges()
1477{
1478    double xMin, xMax, yMin, yMax, zMin, zMax, wMin, wMax;
1479
1480    TRACE("in SetHeightmapRanges\n");
1481    xMin = yMin = zMin = wMin = FLT_MAX;
1482    xMax = yMax = zMax = wMax = -FLT_MAX;
1483    Tcl_HashEntry *hPtr;
1484    Tcl_HashSearch iter;
1485    for (hPtr = Tcl_FirstHashEntry(&heightmapTable, &iter); hPtr != NULL;
1486         hPtr = Tcl_NextHashEntry(&iter)) {
1487        HeightMap *hmPtr;
1488        hmPtr = (HeightMap *)Tcl_GetHashValue(hPtr);
1489        if (xMin > hmPtr->xAxis.min()) {
1490            xMin = hmPtr->xAxis.min();
1491        }
1492        if (xMax < hmPtr->xAxis.max()) {
1493            xMax = hmPtr->xAxis.max();
1494        }
1495        if (yMin > hmPtr->yAxis.min()) {
1496            yMin = hmPtr->yAxis.min();
1497        }
1498        if (yMax < hmPtr->yAxis.max()) {
1499            yMax = hmPtr->yAxis.max();
1500        }
1501        if (zMin > hmPtr->zAxis.min()) {
1502            zMin = hmPtr->zAxis.min();
1503        }
1504        if (zMax < hmPtr->zAxis.max()) {
1505            zMax = hmPtr->zAxis.max();
1506        }
1507        if (wMin > hmPtr->wAxis.min()) {
1508            wMin = hmPtr->wAxis.min();
1509        }
1510        if (wMax < hmPtr->wAxis.max()) {
1511            wMax = hmPtr->wAxis.max();
1512        }
1513    }
1514    if ((xMin < DBL_MAX) && (xMax > -DBL_MAX)) {
1515        grid->xAxis.SetScale(xMin, xMax);
1516    }
1517    if ((yMin < DBL_MAX) && (yMax > -DBL_MAX)) {
1518        grid->yAxis.SetScale(yMin, yMax);
1519    }
1520    if ((zMin < DBL_MAX) && (zMax > -DBL_MAX)) {
1521        grid->zAxis.SetScale(zMin, zMax);
1522    }
1523    if ((wMin < DBL_MAX) && (wMax > -DBL_MAX)) {
1524        HeightMap::valueMin = grid->yAxis.min();
1525        HeightMap::valueMax = grid->yAxis.max();
1526    }
1527    for (hPtr = Tcl_FirstHashEntry(&heightmapTable, &iter); hPtr != NULL;
1528         hPtr = Tcl_NextHashEntry(&iter)) {
1529        HeightMap *hmPtr;
1530        hmPtr = (HeightMap *)Tcl_GetHashValue(hPtr);
1531        hmPtr->MapToGrid(grid);
1532    }
1533    HeightMap::update_pending = false;
1534    TRACE("leaving SetHeightmapRanges\n");
1535}
1536
1537/*----------------------------------------------------*/
1538void
1539NanoVis::display()
1540{
1541    TRACE("in display\n");
1542#ifdef notdef
1543    if (flags & MAP_FLOWS) {
1544        xMin = yMin = zMin = wMin = FLT_MAX, magMin = DBL_MAX;
1545        xMax = yMax = zMax = wMax = -FLT_MAX, magMax = -DBL_MAX;
1546    }
1547#endif
1548    if (flags & MAP_FLOWS) {
1549        MapFlows();
1550        grid->xAxis.SetScale(xMin, xMax);
1551        grid->yAxis.SetScale(yMin, yMax);
1552        grid->zAxis.SetScale(zMin, zMax);
1553    }
1554    //assert(glGetError()==0);
1555    if (HeightMap::update_pending) {
1556        SetHeightmapRanges();
1557    }
1558    if (Volume::update_pending) {
1559        SetVolumeRanges();
1560    }
1561    TRACE("in display: glClear\n");
1562    //start final rendering
1563    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear screen
1564
1565    if (volume_mode) {
1566        TRACE("in display: volume_mode\n");
1567        //3D rendering mode
1568        // TBD..
1569        //glEnable(GL_TEXTURE_2D);
1570        glEnable(GL_DEPTH_TEST);
1571
1572        //camera setting activated
1573        cam->initialize();
1574
1575        //set up the orientation of items in the scene.
1576        glPushMatrix();
1577        switch (updir) {
1578        case 1:  // x
1579            glRotatef(90, 0, 0, 1);
1580            glRotatef(90, 1, 0, 0);
1581            break;
1582
1583        case 2:  // y
1584            // this is the default
1585            break;
1586
1587        case 3:  // z
1588            glRotatef(-90, 1, 0, 0);
1589            glRotatef(-90, 0, 0, 1);
1590            break;
1591
1592        case -1:  // -x
1593            glRotatef(-90, 0, 0, 1);
1594            break;
1595
1596        case -2:  // -y
1597            glRotatef(180, 0, 0, 1);
1598            glRotatef(-90, 0, 1, 0);
1599            break;
1600
1601        case -3:  // -z
1602            glRotatef(90, 1, 0, 0);
1603            break;
1604        }
1605
1606        // TBD : This will be removed after being sure that all the functions work well.
1607        //glPushMatrix();
1608
1609        //now render things in the scene
1610        if (axis_on) {
1611            draw_3d_axis();
1612        }
1613        if (grid->isVisible()) {
1614            grid->render();
1615        }
1616        if ((licRenderer != NULL) && (licRenderer->active())) {
1617            licRenderer->render();
1618        }
1619
1620        if ((velocityArrowsSlice != NULL) && (velocityArrowsSlice->enabled())) {
1621            velocityArrowsSlice->render();
1622        }
1623#ifdef notdef
1624        if ((flowVisRenderer != NULL) && (flowVisRenderer->active())) {
1625            flowVisRenderer->render();
1626        }
1627#endif
1628        if (flowTable.numEntries > 0) {
1629            RenderFlows();
1630        }
1631
1632        //soft_display_verts();
1633        //perf->enable();
1634        //perf->disable();
1635        //TRACE("particle pixels: %d\n", perf->get_pixel_count());
1636        //perf->reset();
1637
1638        //perf->enable();
1639        vol_renderer->render_all();
1640        //perf->disable();
1641
1642        if (heightmapTable.numEntries > 0) {
1643            TRACE("in display: render heightmap\n");
1644            Tcl_HashEntry *hPtr;
1645            Tcl_HashSearch iter;
1646            for (hPtr = Tcl_FirstHashEntry(&heightmapTable, &iter); hPtr != NULL;
1647                 hPtr = Tcl_NextHashEntry(&iter)) {
1648                HeightMap *hmPtr;
1649                hmPtr = (HeightMap *)Tcl_GetHashValue(hPtr);
1650                if (hmPtr->isVisible()) {
1651                    hmPtr->render(renderContext);
1652                }
1653            }
1654        }
1655        glPopMatrix();
1656    } else {
1657        //2D rendering mode
1658        perf->enable();
1659        plane_renderer->render();
1660        perf->disable();
1661    }
1662
1663    perf->reset();
1664    CHECK_FRAMEBUFFER_STATUS();
1665    TRACE("leaving display\n");
1666}
1667
1668#ifndef XINETD
1669void
1670NanoVis::mouse(int button, int state, int x, int y)
1671{
1672    if(button==GLUT_LEFT_BUTTON){
1673        if (state==GLUT_DOWN) {
1674            left_last_x = x;
1675            left_last_y = y;
1676            left_down = true;
1677            right_down = false;
1678        } else {
1679            left_down = false;
1680            right_down = false;
1681        }
1682    } else {
1683        //TRACE("right mouse\n");
1684
1685        if(state==GLUT_DOWN){
1686            //TRACE("right mouse down\n");
1687            right_last_x = x;
1688            right_last_y = y;
1689            left_down = false;
1690            right_down = true;
1691        } else {
1692            //TRACE("right mouse up\n");
1693            left_down = false;
1694            right_down = false;
1695        }
1696    }
1697}
1698
1699void
1700NanoVis::update_rot(int delta_x, int delta_y)
1701{
1702    Vector3 angle;
1703
1704    angle = cam->rotate();
1705    angle.x += delta_x;
1706    angle.y += delta_y;
1707
1708    if (angle.x > 360.0) {
1709        angle.x -= 360.0;
1710    } else if(angle.x < -360.0) {
1711        angle.x += 360.0;
1712    }
1713    if (angle.y > 360.0) {
1714        angle.y -= 360.0;
1715    } else if(angle.y < -360.0) {
1716        angle.y += 360.0;
1717    }
1718    cam->rotate(angle);
1719}
1720
1721void
1722NanoVis::update_trans(int delta_x, int delta_y, int delta_z)
1723{
1724    cam->x(cam->x() + delta_x * 0.03);
1725    cam->y(cam->y() + delta_y * 0.03);
1726    cam->z(cam->z() + delta_z * 0.03);
1727}
1728
1729#ifdef NEW_FLOW_ENGINE
1730void addVectorField(const char* filename, const char* vf_name,
1731                    const char* plane_name1, const char* plane_name2,
1732                    const Vector4& color1, const Vector4& color2)
1733{
1734    Rappture::Outcome result;
1735    Rappture::Buffer buf;
1736
1737    buf.load(filename);
1738    int n = NanoVis::n_volumes;
1739    if (load_vector_stream2(result, n, buf.size(), buf.bytes())) {
1740        Volume *volPtr = NanoVis::volume[n];
1741        if (volPtr != NULL) {
1742            volPtr->set_n_slice(256-n);
1743            // volPtr->set_n_slice(512-n);
1744            volPtr->disable_cutplane(0);
1745            volPtr->disable_cutplane(1);
1746            volPtr->disable_cutplane(2);
1747            volPtr->transferFunction(NanoVis::get_transfunc("default"));
1748
1749            float dx0 = -0.5;
1750            float dy0 = -0.5*volPtr->height/volPtr->width;
1751            float dz0 = -0.5*volPtr->depth/volPtr->width;
1752            volPtr->move(Vector3(dx0, dy0, dz0));
1753            //volPtr->data(true);
1754            volPtr->data(false);
1755            NanoVis::flowVisRenderer->addVectorField(vf_name, volPtr,
1756                *(volPtr->get_location()),
1757                1.0f,
1758                volPtr->height / (float)volPtr->width,
1759                volPtr->depth  / (float)volPtr->width,
1760                1.0f);
1761            NanoVis::flowVisRenderer->activateVectorField(vf_name);
1762
1763            //////////////////////////////////
1764            // ADD Particle Injection Plane1
1765            NanoVis::flowVisRenderer->addPlane(vf_name, plane_name1);
1766            NanoVis::flowVisRenderer->setPlaneAxis(vf_name, plane_name1, 0);
1767            NanoVis::flowVisRenderer->setPlanePos(vf_name, plane_name1, 0.9);
1768            NanoVis::flowVisRenderer->setParticleColor(vf_name, plane_name1, color1);
1769            // ADD Particle Injection Plane2
1770            NanoVis::flowVisRenderer->addPlane(vf_name, plane_name2);
1771            NanoVis::flowVisRenderer->setPlaneAxis(vf_name, plane_name2, 0);
1772            NanoVis::flowVisRenderer->setPlanePos(vf_name, plane_name2, 0.2);
1773            NanoVis::flowVisRenderer->setParticleColor(vf_name, plane_name2, color2);
1774            NanoVis::flowVisRenderer->initialize(vf_name);
1775
1776            NanoVis::flowVisRenderer->activatePlane(vf_name, plane_name1);
1777            NanoVis::flowVisRenderer->activatePlane(vf_name, plane_name2);
1778
1779            NanoVis::licRenderer->
1780                setVectorField(volPtr->id,
1781                               *(volPtr->get_location()),
1782                               1.0f / volPtr->aspect_ratio_width,
1783                               1.0f / volPtr->aspect_ratio_height,
1784                               1.0f / volPtr->aspect_ratio_depth,
1785                               volPtr->wAxis.max());
1786        }
1787    }
1788    //NanoVis::initParticle();
1789}
1790#endif
1791
1792void
1793NanoVis::keyboard(unsigned char key, int x, int y)
1794{
1795#ifdef EVENTLOG
1796    if(log){
1797        float param[3];
1798        param[0] = cam->x();
1799        param[1] = cam->y();
1800        param[2] = cam->z();
1801        Event* tmp = new Event(EVENT_MOVE, param, NvGetTimeInterval());
1802        tmp->write(event_log);
1803        delete tmp;
1804    }
1805#endif
1806
1807#ifdef NEW_FLOW_ENGINE
1808    switch (key) {
1809    case 'a' :
1810        {
1811            TRACE("flowvis active\n");
1812            char cmd[] = {
1813                "foreach flow [flow names] {\n"
1814                "    $flow configure -hide no -slice yes\n"
1815                "}\n"
1816            };
1817            Tcl_Eval(interp, cmd);
1818#ifdef notdef
1819            NanoVis::flowVisRenderer->active(true);
1820            NanoVis::licRenderer->active(true);
1821#endif
1822        }
1823        break;
1824    case 'd' :
1825        {
1826            TRACE("flowvis deactived\n");
1827            char cmd[] = {
1828                "foreach flow [flow names] {\n"
1829                "    $flow configure -hide yes -slice no\n"
1830                "}\n"
1831            };
1832#ifdef notdef
1833            NanoVis::flowVisRenderer->active(false);
1834            NanoVis::licRenderer->active(false);
1835#endif
1836        }
1837        break;
1838    case '1' :
1839        {
1840            TRACE("add vector field\n");
1841            char cmd[] = {
1842                "flow create flow1\n"
1843                "flow1 data file /home/iwoo/projects/nanovis/rappture/packages/vizservers/nanovis/data/flowvis_dx_files/jwire/J-wire-vec.dx 3\n"
1844                "flow1 particles add plane1 -color { 0 0 1 1 }\n"
1845                "flow1 particles add plane2 -color { 0 1 1 1 }\n"
1846            };
1847            Tcl_Eval(interp, cmd);
1848#ifdef notdef
1849            addVectorField("/home/iwoo/projects/nanovis/rappture/packages/vizservers/nanovis/data/flowvis_dx_files/jwire/J-wire-vec.dx",
1850                           "vf_name2", "plane_name1", "plane_name2", Vector4(0, 0, 1, 1), Vector4(0, 1, 1, 1));
1851#endif
1852        }
1853        break;
1854    case '2' :
1855        {
1856            char cmd[] = {
1857                "flow create flow2\n"
1858                "flow2 data file /home/iwoo/projects/nanovis/rappture/packages/vizservers/nanovis/data/flowvis_dx_files/3DWireLeakage/SiO2/SiO2.dx 3\n"
1859                "flow2 particles add plane1 -color { 1 0 0 1 }\n"
1860                "flow2 particles add plane2 -color { 1 1 0 1 }\n"
1861            };
1862            Tcl_Eval(interp, cmd);
1863            TRACE("add vector field\n");
1864            addVectorField("/home/iwoo/projects/nanovis/rappture/packages/vizservers/nanovis/data/flowvis_dx_files/3DWireLeakage/SiO2/SiO2.dx",
1865                           "vf_name1", "plane_name1", "plane_name2", Vector4(1, 0, 0, 1), Vector4(1, 1, 0, 1));
1866        }
1867        break;
1868    case '3':
1869        {
1870            TRACE("activate\n");
1871            char cmd[] = {
1872                "flow1 particles add plane2 -hide no\n"
1873            };
1874            Tcl_Eval(interp, cmd);
1875#ifdef notdef
1876            NanoVis::flowVisRenderer->activatePlane("vf_name1", "plane_name2");
1877#endif
1878        }
1879        break;
1880    case '4' :
1881        {
1882            TRACE("deactivate\n");
1883            char cmd[] = {
1884                "flow1 particles add plane2 -hide yes\n"
1885            };
1886            Tcl_Eval(interp, cmd);
1887#ifdef notdef
1888            NanoVis::flowVisRenderer->deactivatePlane("vf_name1", "plane_name2");
1889#endif
1890        }
1891        break;
1892    case '5' :
1893        {
1894            TRACE("vector field deleted (vf_name2)\n");
1895            char cmd[] = {
1896                "flow delete flow2\n"
1897            };
1898            Tcl_Eval(interp, cmd);
1899#ifdef notdef
1900            NanoVis::flowVisRenderer->removeVectorField("vf_name2");
1901#endif
1902        }
1903        break;
1904    case '6' :
1905        {
1906            TRACE("add device shape\n");
1907            char cmd[] = {
1908                "flow1 box add box1 -corner1 {0 0 0} -corner2 {30 3 3} -color { 1 0 0 1 }\n"
1909                "flow1 box add box2 -corner1 {0 -1 -1} -corner2 {30 4 4} -color { 0 1 0 1 }\n"
1910                "flow1 box add box3 -corner1 {10 -1.5 -1} -corner2 {20 4.5 4.5} -color { 0 0 1 1 }\n"
1911            };
1912            Tcl_Eval(interp, cmd);
1913#ifdef notdef
1914            NvDeviceShape shape;
1915            shape.min.set(0, 0, 0);
1916            shape.max.set(30, 3, 3);
1917            shape.color.set(1, 0, 0, 1);
1918            NanoVis::flowVisRenderer->addDeviceShape("vf_name1", "device1", shape);
1919            shape.min.set(0, -1, -1);
1920            shape.max.set(30, 4, 4);
1921            shape.color.set(0, 1, 0, 1);
1922            NanoVis::flowVisRenderer->addDeviceShape("vf_name1", "device2", shape);
1923            shape.min.set(10, -1.5, -1);
1924            shape.max.set(20, 4.5, 4.5);
1925            shape.color.set(0, 0, 1, 1);
1926            NanoVis::flowVisRenderer->addDeviceShape("vf_name1", "device3", shape);
1927            NanoVis::flowVisRenderer->activateDeviceShape("vf_name1");
1928#endif
1929        }
1930        break;
1931    case '7' :
1932        {
1933            TRACE("hide shape \n");
1934            char cmd[] = {
1935                "flow1 box configure box1 -hide yes\n"
1936            };
1937            Tcl_Eval(interp, cmd);
1938#ifdef notdef
1939            NanoVis::flowVisRenderer->deactivateDeviceShape("vf_name1");
1940#endif
1941        }
1942        break;
1943    case '8' :
1944        {
1945            TRACE("show shape\n");
1946            char cmd[] = {
1947                "flow1 box configure box1 -hide no\n"
1948            };
1949            Tcl_Eval(interp, cmd);
1950#ifdef notdef
1951            NanoVis::flowVisRenderer->activateDeviceShape("vf_name1");
1952#endif
1953        }
1954        break;
1955    case '9' :
1956        {
1957            TRACE("show a shape \n");
1958            char cmd[] = {
1959                "flow1 box configure box3 -hide no\n"
1960            };
1961            Tcl_Eval(interp, cmd);
1962#ifdef notdef
1963            NanoVis::flowVisRenderer->activateDeviceShape("vf_name1", "device3");
1964#endif
1965        }
1966        break;
1967    case '0' :
1968        {
1969            TRACE("delete a shape \n");
1970            char cmd[] = {
1971                "flow1 box delete box3\n"
1972            };
1973            Tcl_Eval(interp, cmd);
1974#ifdef notdef
1975            NanoVis::flowVisRenderer->deactivateDeviceShape("vf_name1", "device3");
1976#endif
1977        }
1978        break;
1979    case 'r' :
1980        {
1981            TRACE("reset \n");
1982            char cmd[] = {
1983                "flow reset\n"
1984            };
1985            Tcl_Eval(interp, cmd);
1986#ifdef notdef
1987            NanoVis::flowVisRenderer->reset();
1988            NanoVis::licRenderer->reset();
1989#endif
1990        }
1991        break;
1992    }
1993#endif
1994}
1995
1996void
1997NanoVis::motion(int x, int y)
1998{
1999    int old_x, old_y;
2000
2001    if(left_down){
2002        old_x = left_last_x;
2003        old_y = left_last_y;
2004    } else if(right_down){
2005        old_x = right_last_x;
2006        old_y = right_last_y;
2007    }
2008
2009    int delta_x = x - old_x;
2010    int delta_y = y - old_y;
2011
2012    //more coarse event handling
2013    //if(abs(delta_x)<10 && abs(delta_y)<10)
2014    //return;
2015
2016    if(left_down){
2017        left_last_x = x;
2018        left_last_y = y;
2019
2020        update_rot(-delta_y, -delta_x);
2021    } else if (right_down){
2022        //TRACE("right mouse motion (%d,%d)\n", x, y);
2023
2024        right_last_x = x;
2025        right_last_y = y;
2026
2027        update_trans(0, 0, delta_x);
2028    }
2029
2030#ifdef EVENTLOG
2031    Vector3 angle = cam->rotate();
2032    Event* tmp = new Event(EVENT_ROTATE, &angle, NvGetTimeInterval());
2033    tmp->write(event_log);
2034    delete tmp;
2035#endif
2036    glutPostRedisplay();
2037}
2038
2039#endif /*XINETD*/
2040
2041void
2042NanoVis::render()
2043{
2044
2045#ifdef notdef
2046    if ((NanoVis::licRenderer != NULL) && (NanoVis::licRenderer->active())) {
2047        NanoVis::licRenderer->convolve();
2048    }
2049#else
2050    if (NanoVis::licRenderer != NULL) {
2051        NanoVis::licRenderer->convolve();
2052    }
2053#endif
2054
2055#ifdef notdef
2056    if ((NanoVis::flowVisRenderer != NULL) && (NanoVis::flowVisRenderer->active())) {
2057        NanoVis::flowVisRenderer->advect();
2058    }
2059#endif
2060    NanoVis::update();
2061    display();
2062    glutSwapBuffers();
2063}
2064
2065void
2066NanoVis::resize(int x, int y)
2067{
2068    glViewport(0, 0, x, y);
2069}
2070
2071void
2072NanoVis::xinetd_listen(void)
2073{
2074    NanoVis::flags &= ~REDRAW_PENDING;
2075
2076    TRACE("Enter xinetd_listen\n");
2077
2078    int flags = fcntl(0, F_GETFL, 0);
2079    fcntl(0, F_SETFL, flags & ~O_NONBLOCK);
2080
2081    int status = TCL_OK;
2082
2083    //  Read and execute as many commands as we can from stdin...
2084
2085    int nCommands = 0;
2086    bool isComplete = false;
2087    while ((!feof(NanoVis::stdin)) && (status == TCL_OK)) {
2088        //
2089        //  Read the next command from the buffer.  First time through we
2090        //  block here and wait if necessary until a command comes in.
2091        //
2092        //  BE CAREFUL: Read only one command, up to a newline.  The "volume
2093        //  data follows" command needs to be able to read the data
2094        //  immediately following the command, and we shouldn't consume it
2095        //  here.
2096        //
2097        TRACE("in xinetd_listen: EOF=%d\n", feof(NanoVis::stdin));
2098        while (!feof(NanoVis::stdin)) {
2099            int c = fgetc(NanoVis::stdin);
2100            char ch;
2101            if (c <= 0) {
2102                if (errno == EWOULDBLOCK) {
2103                    break;
2104                }
2105                DoExit(100);
2106            }
2107            ch = (char)c;
2108            Tcl_DStringAppend(&cmdbuffer, &ch, 1);
2109            if (ch == '\n') {
2110                isComplete = Tcl_CommandComplete(Tcl_DStringValue(&cmdbuffer));
2111                if (isComplete) {
2112                    break;
2113                }
2114            }
2115        }
2116        // no command? then we're done for now
2117        if (Tcl_DStringLength(&cmdbuffer) == 0) {
2118            break;
2119        }
2120        if (isComplete) {
2121            // back to original flags during command evaluation...
2122            fcntl(0, F_SETFL, flags & ~O_NONBLOCK);
2123            status = ExecuteCommand(interp, &cmdbuffer);
2124            // non-blocking for next read -- we might not get anything
2125            fcntl(0, F_SETFL, flags | O_NONBLOCK);
2126            isComplete = false;
2127            nCommands++;
2128            CHECK_FRAMEBUFFER_STATUS();
2129        }
2130    }
2131    fcntl(0, F_SETFL, flags);
2132
2133    if (status != TCL_OK) {
2134        const char *string;
2135        int nBytes;
2136
2137        string = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
2138        TRACE("errorInfo=(%s)\n", string);
2139        nBytes = strlen(string);
2140        struct iovec iov[3];
2141        iov[0].iov_base = (char *)"NanoVis Server Error: ";
2142        iov[0].iov_len = strlen((char *)iov[0].iov_base);
2143        iov[1].iov_base = (char *)string;
2144        iov[1].iov_len = nBytes;
2145        iov[2].iov_len = 1;
2146        iov[2].iov_base = (char *)'\n';
2147        if (writev(1, iov, 3) < 0) {
2148            ERROR("write failed: %s\n", strerror(errno));
2149        }
2150        TRACE("Leaving xinetd_listen on ERROR\n");
2151        return;
2152    }
2153    if (feof(NanoVis::stdin)) {
2154        DoExit(90);
2155    }
2156
2157    NanoVis::update();
2158
2159    NanoVis::offscreen_buffer_capture();  //enable offscreen render
2160
2161    NanoVis::display();
2162
2163    // INSOO
2164#ifdef XINETD
2165    NanoVis::read_screen();
2166    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
2167#else
2168    NanoVis::display_offscreen_buffer(); //display the final rendering on screen
2169    NanoVis::read_screen();
2170    glutSwapBuffers();
2171#endif
2172
2173    if (feof(NanoVis::stdin)) {
2174        DoExit(90);
2175    }
2176#if DO_RLE
2177    do_rle();
2178    int sizes[2] = {  offsets_size*sizeof(offsets[0]), rle_size };
2179    TRACE("Writing %d,%d\n", sizes[0], sizes[1]);
2180    write(1, &sizes, sizeof(sizes));
2181    write(1, offsets, offsets_size*sizeof(offsets[0]));
2182    write(1, rle, rle_size);    //unsigned byte
2183#else
2184    NanoVis::ppm_write("\nnv>image -type image -bytes");
2185#endif
2186    TRACE("Leaving xinetd_listen OK\n");
2187}
2188
2189
2190/*----------------------------------------------------*/
2191int
2192main(int argc, char **argv)
2193{
2194    const char *path;
2195    char *newPath;
2196    struct timeval tv;
2197
2198    newPath = NULL;
2199    path = NULL;
2200    NanoVis::stdin = stdin;
2201
2202    fprintf(stdout, "NanoVis %s\n", NANOVIS_VERSION);
2203    fflush(stdout);
2204
2205    openlog("nanovis", LOG_CONS | LOG_PERROR | LOG_PID, LOG_USER);
2206    gettimeofday(&tv, NULL);
2207    stats.start = tv;
2208
2209    /* Initialize GLUT here so it can parse and remove GLUT-specific
2210     * command-line options before we parse the command-line below. */
2211    glutInit(&argc, argv);
2212    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
2213    glutInitWindowSize(NanoVis::win_width, NanoVis::win_height);
2214    glutInitWindowPosition(10, 10);
2215    NanoVis::render_window = glutCreateWindow("nanovis");
2216    glutIdleFunc(NanoVis::idle);
2217
2218#ifndef XINETD
2219    glutMouseFunc(NanoVis::mouse);
2220    glutMotionFunc(NanoVis::motion);
2221    glutKeyboardFunc(NanoVis::keyboard);
2222    glutReshapeFunc(NanoVis::resize);
2223    glutDisplayFunc(NanoVis::render);
2224#else
2225    glutDisplayFunc(NanoVis::display);
2226    glutReshapeFunc(NanoVis::resize_offscreen_buffer);
2227#endif
2228
2229    while (1) {
2230        static struct option long_options[] = {
2231            {"infile",  required_argument, NULL,           0},
2232            {"path",    required_argument, NULL,           2},
2233            {"debug",   no_argument,       NULL,           3},
2234            {"record",  required_argument, NULL,           4},
2235            {0, 0, 0, 0}
2236        };
2237        int option_index = 0;
2238        int c;
2239
2240        c = getopt_long(argc, argv, ":dp:i:l:r:", long_options, &option_index);
2241        if (c == -1) {
2242            break;
2243        }
2244        switch (c) {
2245        case '?':
2246            fprintf(stderr, "unknown option -%c\n", optopt);
2247            return 1;
2248        case ':':
2249            if (optopt < 4) {
2250                fprintf(stderr, "argument missing for --%s option\n",
2251                        long_options[optopt].name);
2252            } else {
2253                fprintf(stderr, "argument missing for -%c option\n", optopt);
2254            }
2255            return 1;
2256        case 2:
2257        case 'p':
2258            path = optarg;
2259            break;
2260        case 3:
2261        case 'd':
2262            NanoVis::debug_flag = true;
2263            break;
2264        case 0:
2265        case 'i':
2266            NanoVis::stdin = fopen(optarg, "r");
2267            if (NanoVis::stdin == NULL) {
2268                perror(optarg);
2269                return 2;
2270            }
2271            break;
2272        case 4:
2273        case 'r':
2274            Tcl_DString ds;
2275            char buf[200];
2276
2277            Tcl_DStringInit(&ds);
2278            Tcl_DStringAppend(&ds, optarg, -1);
2279            sprintf(buf, ".%d", getpid());
2280            Tcl_DStringAppend(&ds, buf, -1);
2281            NanoVis::recfile = fopen(Tcl_DStringValue(&ds), "w");
2282            if (NanoVis::recfile == NULL) {
2283                perror(optarg);
2284                return 2;
2285            }
2286            break;
2287        default:
2288            fprintf(stderr,"unknown option '%c'.\n", c);
2289            return 1;
2290        }
2291    }     
2292    if (path == NULL) {
2293        char *p;
2294
2295        // See if we can derive the path from the location of the program.
2296        // Assume program is in the form <path>/bin/nanovis.
2297
2298#ifdef XINETD
2299        path = argv[0];
2300        p = strrchr((char *)path, '/');
2301        if (p != NULL) {
2302            *p = '\0';
2303            p = strrchr((char *)path, '/');
2304        }
2305        if (p == NULL) {
2306            TRACE("path not specified\n");
2307            return 1;
2308        }
2309        *p = '\0';
2310        newPath = new char[(strlen(path) + 15) * 2 + 1];
2311        sprintf(newPath, "%s/lib/shaders:%s/lib/resources", path, path);
2312        path = newPath;
2313#else
2314        char buff[256];
2315        getcwd(buff, 255);
2316        p = strrchr(buff, '/');
2317        if (p != NULL) {
2318            *p = '\0';
2319        }
2320        newPath = new char[(strlen(buff) + 15) * 2 + 1];
2321        sprintf(newPath, "%s/lib/shaders:%s/lib/resources", buff, buff);
2322        path = newPath;
2323#endif
2324    }
2325
2326    R2FilePath::getInstance()->setWorkingDirectory(argc, (const char**) argv);
2327    vrFilePath::getInstance()->setWorkingDirectory(argc, (const char**) argv);
2328
2329#ifdef XINETD
2330#ifdef notdef
2331    signal(SIGPIPE, SIG_IGN);
2332#endif
2333    NvInitService();
2334#endif
2335
2336    NanoVis::init(path);
2337    if (newPath != NULL) {
2338        delete [] newPath;
2339    }
2340    NanoVis::initGL();
2341#ifdef EVENTLOG
2342    NvInitEventLog();
2343#endif
2344    Tcl_DStringInit(&NanoVis::cmdbuffer);
2345    NanoVis::interp = initTcl();
2346    NanoVis::resize_offscreen_buffer(NanoVis::win_width, NanoVis::win_height);
2347
2348    glutMainLoop();
2349    DoExit(80);
2350}
2351
2352int
2353NanoVis::render_2d_contour(HeightMap* heightmap, int width, int height)
2354{
2355    int old_width = win_width;
2356    int old_height = win_height;
2357
2358    resize_offscreen_buffer(width, height);
2359
2360    /*
2361      plane_renderer->set_screen_size(width, height);
2362
2363      // generate data for the legend
2364      float data[512];
2365      for (int i=0; i < 256; i++) {
2366      data[i] = data[i+256] = (float)(i/255.0);
2367      }
2368      plane[0] = new Texture2D(256, 2, GL_FLOAT, GL_LINEAR, 1, data);
2369      int index = plane_renderer->add_plane(plane[0], tf);
2370      plane_renderer->set_active_plane(index);
2371
2372      offscreen_buffer_capture();
2373      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear screen
2374
2375      //plane_renderer->render();
2376      // INSOO : is going to implement here for the topview of the heightmap
2377      heightmap->render(renderContext);
2378
2379      // INSOO
2380      glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, screen_buffer);
2381      //glReadPixels(0, 0, width, height, GL_BGR, GL_UNSIGNED_BYTE, screen_buffer); // INSOO's
2382      */
2383
2384
2385    // HELP ME
2386    // GEORGE
2387    // I am not sure what I should do
2388    //char prefix[200];
2389    //sprintf(prefix, "nv>height_top_view %s %g %g", volArg, min, max);
2390    //ppm_write(prefix);
2391    //write(1, "\n", 1);
2392    //plane_renderer->remove_plane(index);
2393
2394    // CURRENT
2395    offscreen_buffer_capture();
2396    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear screen
2397    //glEnable(GL_TEXTURE_2D);
2398    //glEnable(GL_DEPTH_TEST);
2399    //heightmap->render_topview(renderContext, width, height);
2400    //NanoVis::display();
2401    if (HeightMap::update_pending) {
2402        SetHeightmapRanges();
2403    }
2404
2405    //cam->initialize();
2406
2407    heightmap->render_topview(renderContext, width, height);
2408
2409    NanoVis::read_screen();
2410    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
2411
2412    // INSOO TEST CODE
2413    bmp_write_to_file(1, "/tmp");
2414
2415    resize_offscreen_buffer(old_width, old_height);
2416
2417    return TCL_OK;
2418}
2419
2420void
2421NanoVis::remove_volume(Volume *volPtr)
2422{
2423    Tcl_HashEntry *hPtr;
2424    hPtr = Tcl_FindHashEntry(&volumeTable, volPtr->name());
2425    if (hPtr != NULL) {
2426        Tcl_DeleteHashEntry(hPtr);
2427    }
2428    delete volPtr;                     
2429}
2430
2431/*
2432void NanoVis::drawArrows(const Vector3& v1, const Vector3& v2)
2433{
2434    Vector3 v3, v4;
2435    if if((v1.z-v2.z) != 0)
2436    {
2437        v3.set(1, 1, (-(v1.x-v2.x)-(v1.y-v2.y))/(v1.z-v2.z));
2438
2439        adj = sqrt((x1-x2)^2 + (y1-y2)^2 + (z1-z2)^2)) / (4 * sqrt((x3^2)+(y3^2)+(z3^2)));
2440        v3.scale(adj);
2441        v4 = -v3;
2442
2443        //x3 = x1 + (3/4)*(x1-x2) + x3
2444        //y3 = y1 + (3/4)*(y1-y2) + y3
2445        //z3 = z1 + (3/4)*(z1-z2) + z3
2446
2447        //x4 = x1 + (3/4)*(x1-x2) + x4
2448        //y4 = y1 + (3/4)*(y1-y2) + y4
2449        //z4 = z1 + (3/4)*(z1-z2) + z4
2450    }
2451}
2452*/
Note: See TracBrowser for help on using the repository browser.