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

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

added stats counters

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