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

Last change on this file since 1247 was 1247, checked in by gah, 15 years ago

Fix for interrupted nanovis session

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