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

Last change on this file since 2827 was 2827, checked in by ldelgass, 13 years ago

Move Vector3/4Array typdefs to the Vector3/4.h headers and remove TypeDefs?.h.
Also misc. cleanups

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