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

Last change on this file since 1219 was 1219, checked in by gah, 16 years ago

Add pan command to nanovis and pymolproxy

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