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

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

changes to allow panning and zooming (via scrollwhell)

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