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

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