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

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