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

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

Initial commit of new flow visualization command structure

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