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

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

various cleanups

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