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

Last change on this file since 1297 was 1295, checked in by dkearney, 16 years ago

adding flowvisviewer widget and flowvis-test program for exercising flow
commands. most stuff works in the flowvis-test gui, there are not transfer
functions or legends. play/pause, stop and record work, record download's or
saves the video file to users's desktop. adding iconc for pause, record and
stop.

added "flow play" command to nanovis. the goal of this command is to send back
the next frame to the client. the play functionality allows users to see
frames as if they were a movie, and also send command nanovis server. this
makes the experience more interactive than waiting for a movie to be made and
downloading it. also the play functionality can be used as a cheap preview to
get the best angle and settings before recording the movie.

added sendDataToClient function to nanovis server so i could send back movie
files. we create the movie on the render server and send back the mpeg binary
for the user to download. the function is pretty general so it can be used to
send any blob of data.

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