App_Vivid.cpp 32.8 KB
Newer Older
Michele Bosi's avatar
Michele Bosi committed
1 2 3 4 5
/**************************************************************************************/
/*                                                                                    */
/*  Visualization Library                                                             */
/*  http://visualizationlibrary.org                                                   */
/*                                                                                    */
Michele Bosi's avatar
Michele Bosi committed
6
/*  Copyright (c) 2005-2016, Michele Bosi                                             */
Michele Bosi's avatar
Michele Bosi committed
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
/*  All rights reserved.                                                              */
/*                                                                                    */
/*  Redistribution and use in source and binary forms, with or without modification,  */
/*  are permitted provided that the following conditions are met:                     */
/*                                                                                    */
/*  - Redistributions of source code must retain the above copyright notice, this     */
/*  list of conditions and the following disclaimer.                                  */
/*                                                                                    */
/*  - Redistributions in binary form must reproduce the above copyright notice, this  */
/*  list of conditions and the following disclaimer in the documentation and/or       */
/*  other materials provided with the distribution.                                   */
/*                                                                                    */
/*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND   */
/*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED     */
/*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE            */
/*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR  */
/*  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    */
/*  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;      */
/*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON    */
/*  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT           */
/*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS     */
/*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                      */
/*                                                                                    */
/**************************************************************************************/

#include "BaseDemo.hpp"
#include <vlCore/glsl_math.hpp>
#include <vlGraphics/GLSL.hpp>
#include <vlGraphics/Light.hpp>
#include <vlGraphics/Text.hpp>
#include <vlGraphics/FontManager.hpp>
#include <vlCore/VisualizationLibrary.hpp>
#include <vlCore/FileSystem.hpp>
#include <vlCore/DiskDirectory.hpp>
#include <vlCore/ResourceDatabase.hpp>
#include <vlCore/LoadWriterManager.hpp>
#include <vlGraphics/TriangleStripGenerator.hpp>
#include <vlGraphics/DoubleVertexRemover.hpp>
#include <vlGraphics/FontManager.hpp>
#include <vlGraphics/plugins/ioVLX.hpp>
#include <vlGraphics/DepthSortCallback.hpp>
#include <vlGraphics/GeometryPrimitives.hpp>
Michele Bosi's avatar
Michele Bosi committed
49
#include <vlVivid/VividRendering.hpp>
50
#include <vlGraphics/CalibratedCamera.hpp>
51
#include <vlGraphics/AdjacencyExtractor.hpp>
Michele Bosi's avatar
Michele Bosi committed
52

53
// #define MODEL_FILENAME "/tmp/dragon.ply"
54
// #define MODEL_FILENAME "/tmp/bunny.ply"
55 56
// #define MODEL_FILENAME "/tmp/niftk.vlb"
#define MODEL_FILENAME "/tmp/rsg-liver.vlb"
Michele Bosi's avatar
Michele Bosi committed
57 58
// #define MODEL_FILENAME "/tmp/MRV.stl"

Michele Bosi's avatar
Michele Bosi committed
59

60 61
using namespace vl;

Michele Bosi's avatar
Michele Bosi committed
62 63 64 65 66
class App_Vivid: public BaseDemo
{
public:
  void initEvent()
  {
Michele Bosi's avatar
Michele Bosi committed
67 68
    Log::notify( appletInfo() );

69 70
    Log::print( Say("GL_VERSION: %s\n") << glGetString(GL_VERSION));
    Log::print( Say("GL_RENDERER: %s\n\n") << glGetString(GL_RENDERER));
Michele Bosi's avatar
Michele Bosi committed
71

Michele Bosi's avatar
Michele Bosi committed
72
    openglContext()->setContinuousUpdate( false );
73 74 75

    // Vivid Rendering

76
    mVividRendering = new VividRendering;
77 78 79
    mVivid = mVividRendering->vividRenderer();
    trackball()->setCamera( mVividRendering->calibratedCamera() );

80 81
    // Other

82
    mLiverOutlineMode = new Uniform( "vl_Vivid.renderMode" );
83
    mLiverOutlineMode->setUniformI( 4 );
84
    mOutlineMode = new Uniform( "vl_Vivid.renderMode" );
85
    mOutlineMode->setUniformI( 0 );
86 87
    mOutlineSlicePlane = new Uniform( "vl_Vivid.outline.slicePlane" );
    mOutlineSlicePlane->setUniform( vec4( 1, 0, 0, 0 ) );
Michele Bosi's avatar
Michele Bosi committed
88

89 90
#if 1
    initScene2();
Michele Bosi's avatar
Michele Bosi committed
91
#else
92
    std::vector<String> files;
Michele Bosi's avatar
Michele Bosi committed
93 94
    files.push_back(MODEL_FILENAME);
    loadModel(files);
Michele Bosi's avatar
Michele Bosi committed
95
#endif
96

Michele Bosi's avatar
Michele Bosi committed
97 98
    // mBackgroundImages[0] = loadImage( "/tmp/rsg-liver.png" );
    mBackgroundImages[0] = loadImage( "/tmp/liver.jpg" );
99 100 101
    mBackgroundImages[1] = loadImage( "/images/sun1.png" );
    mBackgroundImages[2] = loadImage( "/images/sun2.png" );
    mBackgroundImages[3] = loadImage( "/images/sun3.png" );
102
    // deep copy
103
    mBackgroundImage = new Image;
104
    *mBackgroundImage = *mBackgroundImages[0];
Michele Bosi's avatar
Michele Bosi committed
105 106
  }

107

108
  void initScene1() {
109 110 111 112 113
    ref<Effect> fx1 = VividRendering::makeVividEffect();
    fx1->shader()->disable(EN_BLEND);
    fx1->shader()->enable(EN_DEPTH_TEST);
    fx1->shader()->enable(EN_LIGHTING);
    fx1->shader()->setRenderState( new Light, 0 );
Michele Bosi's avatar
Michele Bosi committed
114
    fx1->shader()->gocLightModel()->setTwoSide(true);
115
    fx1->shader()->gocLightModel()->setLocalViewer(true);
116 117 118
    fx1->shader()->gocMaterial()->setAmbient( fvec4(1.0f, 1.0f, 1.0f, 1.0f) );
    fx1->shader()->gocMaterial()->setDiffuse( fvec4(1.0f, 0.0f, 0.0f, 1.0f) );
    fx1->shader()->gocMaterial()->setSpecular( fvec4(1.0f, 1.0f, 1.0f, 1.0f) );
119
    fx1->shader()->gocMaterial()->setShininess(128.0f);
120
    fx1->shader()->gocMaterial()->setColorMaterialEnabled(false);
121
    fx1->shader()->gocMaterial()->setColorMaterial(PF_FRONT_AND_BACK, CM_DIFFUSE);
122
    fx1->shader()->gocUniform("vl_Vivid.colorMaterialEnabled")->setUniform( 0 );
Michele Bosi's avatar
Michele Bosi committed
123

124 125 126 127 128
    ref<Effect> fx2 = VividRendering::makeVividEffect();
    fx2->shader()->enable(EN_BLEND);
    fx2->shader()->enable(EN_DEPTH_TEST);
    fx2->shader()->enable(EN_LIGHTING);
    fx2->shader()->setRenderState( new Light, 0 );
Michele Bosi's avatar
Michele Bosi committed
129
    fx2->shader()->gocLightModel()->setTwoSide(true);
130
    fx2->shader()->gocLightModel()->setLocalViewer(true);
131 132
    fx2->shader()->gocMaterial()->setDiffuse( fvec4(1.0f, 1.0f, 0.0f, 0.25f) );
    fx2->shader()->gocMaterial()->setSpecular( fvec4(1.0f, 1.0f, 1.0f, 1.0f) );
133
    fx2->shader()->gocMaterial()->setShininess(128.0f);
134
    fx2->shader()->gocMaterial()->setColorMaterialEnabled(true);
135
    fx2->shader()->gocMaterial()->setColorMaterial(PF_FRONT_AND_BACK, CM_DIFFUSE);
136
    fx2->shader()->gocUniform("vl_Vivid.colorMaterialEnabled")->setUniform( 1 );
137

138 139
    ref< Transform > tr1 = new Transform();
    tr1->setLocalAndWorldMatrix(mat4::getTranslation(+0.025f, 0, 0));
Michele Bosi's avatar
Michele Bosi committed
140

141 142
    ref< Transform > tr2 = new Transform();
    tr2->setLocalAndWorldMatrix(mat4::getTranslation(-0.025f, 0, 0) * mat4::getRotationXYZ(90, 0, 0));
Michele Bosi's avatar
Michele Bosi committed
143

144 145
    ref< Geometry > torus = makeTorus( vec3( 0, 0, 0 ), 0.1f, 0.02f, 20, 40 );
    torus->setColorArray(fvec4(1.0f, 0.5f, 0.0f, 0.25f));
Michele Bosi's avatar
Michele Bosi committed
146

147 148
    mVividRendering->sceneManager()->tree()->addActor( torus.get(), fx1.get(), tr1.get() );
    mVividRendering->sceneManager()->tree()->addActor( torus.get(), fx2.get(), tr2.get() );
Michele Bosi's avatar
Michele Bosi committed
149 150 151 152

    adjustScene();
  }

153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
  void initScene2() {
    ref<Effect> fx1 = VividRendering::makeVividEffect();
    ref<Effect> fx2 = VividRendering::makeVividEffect();
    fx1->shader()->gocUniform( "vl_Vivid.material.diffuse" )->setUniform( vl::vec4(1, 0, 0, .5f) );
    fx2->shader()->gocUniform( "vl_Vivid.material.diffuse" )->setUniform( vl::vec4(1, 0, 0, .5f) );

    const float size = 5000;
#if 1
    ref< Geometry > box1 = makeBox( vl::vec3(0.0f), size, size, size, false );
#else
    ref< Geometry > box1 = makeUVSphere( vl::vec3(0.0f), 100, 20, 20 );
#endif
    ref< Geometry > box2 = makeBox( vl::vec3(0.0f), size * .8f, size * .8f, size * .8f, false );

    box1->computeNormals();
    box2->computeNormals();

    Actor* a1 = mVividRendering->sceneManager()->tree()->addActor( box1.get(), fx1.get(), NULL );
    Actor* a2 = mVividRendering->sceneManager()->tree()->addActor( box2.get(), fx2.get(), NULL );
    a1->setEnableMask( vl::Vivid::VividEnableMask );
    a2->setEnableMask( vl::Vivid::VividEnableMask );

    adjustScene();
  }

Michele Bosi's avatar
Michele Bosi committed
178 179
  void adjustScene() {
    // position the camera to nicely see the objects in the scene
180
    trackball()->adjustView( mVividRendering.get(), vec3(0,0,1), vec3(0,1,0), 1.0f );
Michele Bosi's avatar
Michele Bosi committed
181 182

    // throttle ghost camera manipulator speed based on the scene size, using a simple euristic formula
183 184 185
    mVividRendering->sceneManager()->computeBounds();
    const AABB& scene_aabb = mVividRendering->sceneManager()->boundingBox();
    real speed = (scene_aabb.width() + scene_aabb.height() + scene_aabb.depth()) / 20.0f;
Michele Bosi's avatar
Michele Bosi committed
186 187 188
    ghostCameraManipulator()->setMovementSpeed(speed);
  }

189 190
  String filename( const String& path ) {
      std::vector< String > splits;
191 192 193 194
      path.split('/', splits, true);
      return splits.back();
  }

195
  void loadModel(const std::vector<String>& files)
Michele Bosi's avatar
Michele Bosi committed
196 197 198
  {
    // default effects

199
    mVividRendering->sceneManager()->tree()->actors()->clear();
Michele Bosi's avatar
Michele Bosi committed
200 201 202

    for(unsigned int i=0; i<files.size(); ++i)
    {
203
      ref<ResourceDatabase> resource_db = loadResource(files[i], false);
Michele Bosi's avatar
Michele Bosi committed
204

205
      if (!resource_db || resource_db->count<Actor>() == 0)
Michele Bosi's avatar
Michele Bosi committed
206 207 208 209 210 211 212 213 214 215 216 217 218
      {
        VL_LOG_ERROR << "No data found.\n";
        continue;
      }

#if 0
      // VLX save
      String save_path = files[i].extractPath() + files[i].extractFileName() + ".vlb";
      saveVLB(save_path, resource_db.get());
#endif

      showStatistics(resource_db);

Michele Bosi's avatar
Michele Bosi committed
219
      for(size_t j=0; j<resource_db->resources().size(); ++j)
Michele Bosi's avatar
Michele Bosi committed
220
      {
221
        Actor* act = resource_db->resources()[j]->as<Actor>();
Michele Bosi's avatar
Michele Bosi committed
222

223
        if ( ! act )
Michele Bosi's avatar
Michele Bosi committed
224 225
          continue;

226
        printf( "Actor: %s\n", act->objectName().c_str() );
227

228 229 230 231
        mLastModelName = filename( files[i] );

        // saveActor( act );

232
        // act->actorEventCallbacks()->push_back( new DepthSortCallback );
Michele Bosi's avatar
Michele Bosi committed
233

234
        Geometry* geom = act->lod(0)->as<Geometry>();
235
        geom->computeNormals();
236 237
        if ( geom->drawCalls()[0]->primitiveType() != PT_TRIANGLES_ADJACENCY ) {
          ref< Geometry > geom_adj = AdjacencyExtractor::extract( geom );
238 239
          geom->shallowCopyFrom( *geom_adj );
        }
240

241
        // const AABB& aabb = act->boundingBox();
242 243 244
        geom->setBoundsDirty( true );
        act->computeBounds();

245 246
        #if 0
          // Center
247
          geom->vertexArray()->transform( mat4::getTranslation( -1.0f * aabb.center() ) );
248 249 250 251 252 253 254 255
          geom->setBoundsDirty( true );
          act->computeBounds();
          if ( act->transform() ) {
            act->transform()->computeWorldMatrix();
          }

          // Scale to 1 meter
          float s = 1000.0f / aabb.width();
256
          geom->vertexArray()->transform( mat4::getScaling( s, s, s ) );
257 258 259 260 261 262 263 264
          geom->setBoundsDirty( true );
          act->computeBounds();

          printf("aabb: %f %f %f\n", aabb.width(), aabb.height(), aabb.depth() );
          printf("aabb-min: %f %f %f\n", aabb.minCorner().x(), aabb.minCorner().y(), aabb.minCorner().z() );
          printf("aabb-max: %f %f %f\n", aabb.maxCorner().x(), aabb.maxCorner().y(), aabb.maxCorner().z() );
        #endif

265
        // Get, init or create the effect using incoming material settings if any
266
        ref<Effect> fx1 = VividRendering::makeVividEffect( act->effect() );
267
        act->setEffect( fx1.get() );
268 269 270 271 272 273 274 275
        if ( fx1->shader()->getMaterial() ) {
          Shader* sh = fx1->shader();
          sh->gocUniform( "vl_Vivid.material.diffuse" )->setUniform( sh->getMaterial()->frontDiffuse() );
          sh->gocUniform( "vl_Vivid.material.specular" )->setUniform( sh->getMaterial()->frontSpecular() );
          sh->gocUniform( "vl_Vivid.material.ambient" )->setUniform( sh->getMaterial()->frontAmbient() );
          sh->gocUniform( "vl_Vivid.material.emission" )->setUniform( sh->getMaterial()->frontEmission() );
          sh->gocUniform( "vl_Vivid.material.shininess" )->setUniformF( sh->getMaterial()->frontShininess() );
        }
Michele Bosi's avatar
Michele Bosi committed
276

277
        //if ( ! fx1.get() ) {
278
        //  fx1 = new Effect;
279 280
        //  act->setEffect(fx1.get());
        //}
281

282 283 284 285 286 287 288
        // Skip skin
        if ( act->objectName() == "surface:skin" ) {
          continue;
        }

        // bones
        if ( act->objectName() == "surface:bones" ) {
289
          //  fx1->shader()->gocMaterial()->setDiffuse( fvec4(0.8f, 0.0f, 0.0f, 1) );
290 291 292 293 294
          continue;
        }

        // Stencil Test: liver geometry
        if ( act->objectName() == "surface:liver" ) {
Michele Bosi's avatar
Michele Bosi committed
295
          // mVividRendering->stencilActors().push_back( act );
296
          // mVividRendering->setStencilEnabled( true );
297 298 299 300 301
          // continue;
          mLiverActor = act;
          // mLiverActor->setEnableMask( 0 );
        }

302 303
        if ( ! fx1->shader()->getMaterial() )
        {
304 305
          fx1->shader()->gocMaterial()->setDiffuse( fvec4(1.0f, 0.6f, 0.5f, 1.0) );
          fx1->shader()->gocMaterial()->setSpecular( fvec4(1.0f, 1.0f, 1.0f, 1.0f) );
306 307
          fx1->shader()->gocMaterial()->setShininess(128.0f);
        }
308

Michele Bosi's avatar
Michele Bosi committed
309 310
#if 0
        if ( j == 11 ) {
311
          fx1->shader()->gocMaterial()->setDiffuse( fvec4( 1, 1, 1, 1 ) );
Michele Bosi's avatar
Michele Bosi committed
312 313
          // continue;
        } else if ( j == 3 ) {
314
          fx1->shader()->gocMaterial()->setDiffuse( fvec4( 0.8f, 0.8f, 0.0f, 0.20 ) );
Michele Bosi's avatar
Michele Bosi committed
315 316 317 318 319
        } else {
          continue;
        }
#endif

320 321 322 323
        fx1->shader()->enable( EN_BLEND );
        fx1->shader()->enable( EN_DEPTH_TEST );
        fx1->shader()->enable( EN_LIGHTING );
        fx1->shader()->setRenderState( new Light, 0 );
324 325
        fx1->shader()->gocLightModel()->setTwoSide( true );
        fx1->shader()->gocLightModel()->setLocalViewer( true );
326
        // fx1->shader()->gocDepthMask()->set( false );
327

328
#if 0
329
        // Fog
330 331 332
        fx1->shader()->disable( EN_FOG );
        fx1->shader()->gocFog()->setMode( FM_LINEAR );
        fx1->shader()->gocFog()->setColor( black );
333 334 335
        fx1->shader()->gocFog()->setStart( act->boundingBox().width() * 1 ); // Only used with Linear mode
        fx1->shader()->gocFog()->setEnd( act->boundingBox().width() * 2 );   // Only used with Linear mode
        fx1->shader()->gocFog()->setDensity( 1.0f );                         // Only used with Exp & Exp2 mode
336 337
        fx1->shader()->gocUniform("vl_Vivid.fog.mode")->setUniformI( 1 );   // 0=OFF, 1=Linear, 2=Exp, 3=Exp2
        fx1->shader()->gocUniform("vl_Vivid.fog.target")->setUniformI( 0 ); // 0=Color, 1=Alpha, 2=Saturation
338 339
#endif

340
        fx1->shader()->gocUniform("vl_Vivid.outline.color")->setUniform( white );
341

342
        // Outline
343
        if ( act->objectName() == "surface:liver" ) {
344 345
          fx1->shader()->setUniform( mLiverOutlineMode.get() );
          fx1->shader()->setUniform( mOutlineSlicePlane.get() );
346
          fx1->shader()->gocUniform("vl_Vivid.outline.color")->setUniform( royalblue );
347
          fx1->shader()->gocUniform("vl_Vivid.renderMode")->setUniformI( 4 );
348 349 350
          fx1->setRenderRank( 1 );
        } else
        if ( act->objectName() == "surface:liver tumor" ) {
351
          fx1->shader()->gocUniform("vl_Vivid.outline.color")->setUniform( green );
352
          fx1->shader()->gocUniform("vl_Vivid.renderMode")->setUniformI( 4 );
353 354 355
          fx1->setRenderRank( 2 );
        } else
        if ( act->objectName() == "surface:liver hypervascular lump" ) {
356
          fx1->shader()->gocUniform("vl_Vivid.outline.color")->setUniform( green );
357
          fx1->shader()->gocUniform("vl_Vivid.renderMode")->setUniformI( 4 );
358 359
          fx1->setRenderRank( 2 );
        } else {
360 361 362 363 364
          // fx1->shader()->gocUniform("vl_Vivid.renderMode")->setUniformI( j == 0 || j == 11 ); // 0=Polys, 1=Outline3D, 2=Polys + Outline
          // fx1->shader()->gocUniform("vl_Vivid.renderMode")->setUniformI( 0 ); // 0=Polys, 1=Outline3D, 2=Polys + Outline
          fx1->shader()->setUniform( mOutlineMode.get() );
          fx1->shader()->setUniform( mOutlineSlicePlane.get() );
          // Outline color must be provided
365
          // fx1->shader()->gocUniform("vl_Vivid.outline.color")->setUniform( j == 11 ? violet : pink );
366 367 368
        }

        // draw all outlines
369
        // fx1->shader()->gocUniform("vl_Vivid.renderMode")->setUniformI( 1 );
370

371
#if 0
372
        // Clipping
373

374
        // Clip volume #0
375 376 377
        fx1->shader()->gocUniform("vl_Vivid.smartClip[0].mode")->setUniformI( 2 ); // 0=OFF, 1=Sphere, 2=Box, 3=Plane
        fx1->shader()->gocUniform("vl_Vivid.smartClip[0].fadeRange")->setUniformF( 0.0 ); // 0=Sharp, 0...=Fuzzy
        fx1->shader()->gocUniform("vl_Vivid.smartClip[0].target")->setUniformI( 0 ); // 0=Color, 1=Alpha, 2=Saturation
378 379 380 381
        fx1->shader()->gocUniform("vl_Vivid.smartClip[0].color")->setUniform( royalblue );
        fx1->shader()->gocUniform("vl_Vivid.smartClip[0].sphere")->setUniform( vec4( 0, 0, 0, 350.0 ) );  // Sphere X,Y,Z,Radius (World Coords)
        fx1->shader()->gocUniform("vl_Vivid.smartClip[0].boxMin")->setUniform( vec3( -250, -250, -250 ) ); // AABB min edge       (World Coords)
        fx1->shader()->gocUniform("vl_Vivid.smartClip[0].boxMax")->setUniform( vec3( +250, +250, +250 ) ); // AABB max edge       (World Coords)
382
        fx1->shader()->gocUniform("vl_Vivid.smartClip[0].reverse")->setUniformI( 0 ); // 0=FALSE, 1=TRUE
383 384

        // Clip volume #1
385 386 387
        fx1->shader()->gocUniform("vl_Vivid.smartClip[1].mode")->setUniformI( 1 ); // 0=OFF, 1=Sphere, 2=Box, 3=Plane
        fx1->shader()->gocUniform("vl_Vivid.smartClip[1].fadeRange")->setUniformF( 50.0 ); // 0=Sharp, 0...=Fuzzy
        fx1->shader()->gocUniform("vl_Vivid.smartClip[1].target")->setUniformI( 1 ); // 0=Color, 1=Alpha, 2=Saturation
388 389 390 391
        fx1->shader()->gocUniform("vl_Vivid.smartClip[1].color")->setUniform( royalblue );
        fx1->shader()->gocUniform("vl_Vivid.smartClip[1].sphere")->setUniform( vec4( 0, -350, 0, 350.0 ) );  // Sphere X,Y,Z,Radius (World Coords)
        fx1->shader()->gocUniform("vl_Vivid.smartClip[1].boxMin")->setUniform( vec3( -250, -250, -250 ) ); // AABB min edge       (World Coords)
        fx1->shader()->gocUniform("vl_Vivid.smartClip[1].boxMax")->setUniform( vec3( +250, +250, +250 ) ); // AABB max edge       (World Coords)
392
        fx1->shader()->gocUniform("vl_Vivid.smartClip[1].reverse")->setUniformI( 1 ); // 0=FALSE, 1=TRUE
393

394
        // Clip volume #2
395 396 397
        fx1->shader()->gocUniform("vl_Vivid.smartClip[2].mode")->setUniformI( 3 ); // 0=OFF, 1=Sphere, 2=Box, 3=Plane
        fx1->shader()->gocUniform("vl_Vivid.smartClip[2].fadeRange")->setUniformF( 00.0 ); // 0=Sharp, 0...=Fuzzy
        fx1->shader()->gocUniform("vl_Vivid.smartClip[2].target")->setUniformI( 2 ); // 0=Color, 1=Alpha, 2=Saturation
398 399
        fx1->shader()->gocUniform("vl_Vivid.smartClip[2].color")->setUniform( royalblue );
        fx1->shader()->gocUniform("vl_Vivid.smartClip[2].plane")->setUniform( vec4( 0, 1, 0, -250 ) );    // Plane Nx,Ny,Nz,Pd (World Coords)
400 401 402
        fx1->shader()->gocUniform("vl_Vivid.smartClip[2].reverse")->setUniformI( 1 ); // 0=FALSE, 1=TRUE

        fx1->shader()->gocUniform("vl_Vivid.smartClip[3].mode")->setUniformI( 0 );
403
#else
404 405 406 407
        fx1->shader()->gocUniform("vl_Vivid.smartClip[0].mode")->setUniformI( 0 );
        fx1->shader()->gocUniform("vl_Vivid.smartClip[1].mode")->setUniformI( 0 );
        fx1->shader()->gocUniform("vl_Vivid.smartClip[2].mode")->setUniformI( 0 );
        fx1->shader()->gocUniform("vl_Vivid.smartClip[3].mode")->setUniformI( 0 );
408
#endif
Michele Bosi's avatar
Michele Bosi committed
409

410
        mVividRendering->sceneManager()->tree()->addActor( act );
Michele Bosi's avatar
Michele Bosi committed
411
        act->setEnableMask( vl::Vivid::VividEnableMask );
Michele Bosi's avatar
Michele Bosi committed
412 413 414 415
      }
    }

    adjustScene();
416 417 418 419
    // mic fixme:
    // - adjustScene() should take care of this?
    // - why don't we call it before?
    mVividRendering->sceneManager()->computeBounds();
420
    mVividRendering->sceneManager()->tree()->computeAABB();
421

Michele Bosi's avatar
Michele Bosi committed
422
#if 1
423
    // make spherical stencil
424 425 426
    ref< Geometry > icosphere = makeIcosphere( mVividRendering->sceneManager()->tree()->aabb().center() + vec3( -50, 0, 25 ), 100, 3 );
    // ref< Geometry > stencil = makeIcosphere( vec3( 0, 0, 0 ), 100, 3 );
    icosphere->computeNormals();
427 428
    // stencil = AdjacencyExtractor::extract( stencil.get() );
    ref< Effect > fx = VividRendering::makeVividEffect();
429 430 431 432 433 434 435 436 437 438
    ref< Transform > tr1 = new Transform;
    ref< Transform > tr2 = new Transform;
    Actor* stencil_act1 = mVividRendering->sceneManager()->tree()->addActor( icosphere.get(), fx.get(), tr1.get() );
    stencil_act1->setEnableMask( 0 );
    Actor* stencil_act2 = mVividRendering->sceneManager()->tree()->addActor( icosphere.get(), fx.get(), tr2.get() );
    stencil_act2->setEnableMask( 0 );
    mVividRendering->stencilActors().push_back( stencil_act1 );
    mVividRendering->stencilActors().push_back( stencil_act2 );
    tr1->setLocalAndWorldMatrix( vl::mat4::getTranslation(-50,0,0) );
    tr2->setLocalAndWorldMatrix( vl::mat4::getTranslation(+50,0,0) );
Michele Bosi's avatar
Michele Bosi committed
439
#endif
440

Michele Bosi's avatar
Michele Bosi committed
441
#if 1
Michele Bosi's avatar
Michele Bosi committed
442 443 444 445 446 447 448 449 450 451
    // make points
    {
      ref< Geometry > points = makeIcosphere( mVividRendering->sceneManager()->tree()->aabb().center() + vec3( -50, 0, 25 ), 100, 3 );
      points->drawCalls().clear();
      points->drawCalls().push_back( new vl::DrawArrays( vl::PT_POINTS, 0, points->vertexArray()->size() ) );
      points->setColorArray( vl::yellow );
      fx = VividRendering::makeVividEffect();
      fx->shader()->getPointSize()->set( 20 );
      Actor* points_act = mVividRendering->sceneManager()->tree()->addActor( points.get(), fx.get(), NULL );
  #if 1
Michele Bosi's avatar
Michele Bosi committed
452
      points_act->setEnableMask( vl::Vivid::VividEnableMask );
Michele Bosi's avatar
Michele Bosi committed
453 454 455 456
      fx->shader()->getUniform( "vl_Vivid.enableLighting" )->setUniformI( 0 );
      fx->shader()->getUniform( "vl_Vivid.enablePointSprite" )->setUniformI( 1 );
      fx->shader()->gocUniform( "vl_Vivid.enableTextureMapping" )->setUniformI( 1 );
      ref<vl::Image> img = new Image("/images/sphere.png");
Michele Bosi's avatar
Michele Bosi committed
457
      ref<vl::Texture> texture = fx->shader()->getTextureSampler( vl::Vivid::UserTexture )->texture();
Michele Bosi's avatar
Michele Bosi committed
458 459
      texture->createTexture2D( img.get(), vl::TF_UNKNOWN, false, false );
  #else
460
      points_act->setEnableMask( vl::VividRenderer::StandardEnableMask );
Michele Bosi's avatar
Michele Bosi committed
461 462 463 464 465 466
      fx->shader()->enable( vl::EN_POINT_SMOOTH );
      fx->shader()->enable( vl::EN_BLEND );
      fx->shader()->disable( vl::EN_LIGHTING );
      fx->shader()->gocHint()->setPointSmoothHint( vl::HM_FASTEST );
  #endif
    }
Michele Bosi's avatar
Michele Bosi committed
467 468
#endif

469
#if 0
470
    // fog
471 472 473 474 475
    ref< Fog > fog = new Fog();
    fog->setMode( FM_LINEAR );
    fog->setColor( black );
    fog->setStart( 100 /*mVividRendering->sceneManager()->boundingBox().width() * 1*/ ); // Only used with Linear mode
    fog->setEnd( 150 /*mVividRendering->sceneManager()->boundingBox().width() * 2*/ );   // Only used with Linear mode
476
    fog->setDensity( 1.0f );                                    // Only used with Exp & Exp2 mode
477

478
    // uniforms
479
    mFogMode = new Uniform( "vl_Vivid.fog.mode" );
480
    mFogMode->setUniformI( 0 );   // 0=OFF, 1=Linear, 2=Exp, 3=Exp2
481
    mFogTarget = new Uniform( "vl_Vivid.fog.target" );
482 483
    mFogTarget->setUniformI( 0 ); // 0=Color, 1=Alpha, 2=Saturation

484
    ActorCollection* actors = mVividRendering->sceneManager()->tree()->actors();
485
    for( int i=0; i<actors->size(); ++i ) {
486 487
      Shader* sh = actors->at( i )->effect()->shader();
        sh->disable( EN_FOG );
488 489 490 491
        sh->setRenderState( fog.get() );
        sh->setUniform( mFogMode.get() );
        sh->setUniform( mFogTarget.get() );
    }
492 493 494
#endif

    // Volume
495 496 497 498 499
    vec3 volume_box_center = mVividRendering->sceneManager()->tree()->aabb().center();
    AABB volume_box;
    volume_box.setMinCorner( volume_box_center - vec3(100,50,50) );
    volume_box.setMaxCorner( volume_box_center + vec3(100,50,50) );
    printf("%f %f %f\n", volume_box.width(), volume_box.height(), volume_box.depth() );
Michele Bosi's avatar
Michele Bosi committed
500
#if 1
501
    ref< Image > volume = vl::loadImage("/volume/BostonTeapot.dat");
502
    mVividRendering->setupVolume( volume.get(), volume_box, NULL );
503 504 505

    // volume bounding box outline
    ref<Effect> fx_box = VividRendering::makeVividEffect();
Michele Bosi's avatar
Michele Bosi committed
506
    fx_box->shader()->gocLineWidth()->set( 3 );
507
    fx_box->shader()->gocPolygonMode()->set( PM_LINE, PM_LINE );
508
    fx_box->shader()->gocUniform( "vl_Vivid.enableLighting" )->setUniformI( 0 );
509 510
    ref<Geometry> box_outline = vl::makeBox( volume_box );
    box_outline->computeNormals();
511
    box_outline->setColorArray( vl::red );
512
    Actor* vol_box = mVividRendering->sceneManager()->tree()->addActor( box_outline.get(), fx_box.get(), mVividRendering->vividVolume()->volumeTransform() );
Michele Bosi's avatar
Michele Bosi committed
513
    vol_box->setEnableMask( vl::Vivid::VividEnableMask );
514
    vol_box->setObjectName( "Volume Box" );
Michele Bosi's avatar
Michele Bosi committed
515
#endif
516

Michele Bosi's avatar
Michele Bosi committed
517
#if 1
Michele Bosi's avatar
Michele Bosi committed
518 519 520 521 522 523
    // texture mapped quad
    ref<Image> vl_img = loadImage( "/tmp/liver/VL-Stencil.png" );
    ref<Geometry> quad = vl::makeGrid( volume_box.center(), volume_box.width(), volume_box.depth(), 10, 10, true );
    fx = vl::VividRendering::makeVividEffect();
    Actor* quad_act = mVividRendering->sceneManager()->tree()->addActor( quad.get(), fx.get(), NULL );
    quad->setObjectName( "QUAD" );
Michele Bosi's avatar
Michele Bosi committed
524
    quad_act->setEnableMask( vl::Vivid::VividEnableMask );
Michele Bosi's avatar
Michele Bosi committed
525 526 527 528 529
    fx->shader()->getUniform("vl_Vivid.enableTextureMapping")->setUniformI( 1 );
    fx->shader()->getUniform("vl_Vivid.enableLighting")->setUniformI( 0 );
    // When texture mapping is enabled texture is modulated by vertex color
    quad->setColorArray( vl::white );
    // These must be present as part of the default Vivid material
Michele Bosi's avatar
Michele Bosi committed
530 531
    VL_CHECK( fx->shader()->getTextureSampler( vl::Vivid::UserTexture ) )
    VL_CHECK( fx->shader()->getTextureSampler( vl::Vivid::UserTexture )->texture() )
532 533
    VL_CHECK( fx->shader()->getUniform("vl_UserTexture2D") );
    VL_CHECK( fx->shader()->getUniform("vl_UserTexture2D")->getUniformI() == vl::Vivid::UserTexture );
Michele Bosi's avatar
Michele Bosi committed
534
    ref<vl::Texture> texture = fx->shader()->getTextureSampler( vl::Vivid::UserTexture )->texture();
Michele Bosi's avatar
Michele Bosi committed
535 536
    // Recreate new texture (TexParameter is not reset so we can keep the current defaults)
    texture->createTexture2D( vl_img.get(), vl::TF_UNKNOWN, false, false );
Michele Bosi's avatar
Michele Bosi committed
537
#endif
538
    adjustScene();
Michele Bosi's avatar
Michele Bosi committed
539 540
  }

541 542
  void saveActor( Actor* act ) {
      ref< ResourceDatabase > db = new ResourceDatabase;
543
      // db->resources().push_back( act );
544
      // String fname = filename( files[i] );
545
      db->resources().push_back( act );
546 547
      Geometry* geom = act->lod(0)->as< Geometry >();
      ref< ArrayAbstract > na = geom->normalArray();
548
      geom->setNormalArray( NULL );
549 550 551
      String fname = mLastModelName;
      saveVLT( "C:/git-ucl/VisualizationLibrary/data/tmp/_" + fname + ".vlt", db.get() );
      saveVLB( "C:/git-ucl/VisualizationLibrary/data/tmp/_" + fname + ".vlb", db.get() );
552 553
      geom->setNormalArray( na.get() );
  }
Michele Bosi's avatar
Michele Bosi committed
554
  //--------------------------------------------------------------------------
555
  void keyPressEvent(unsigned short unicode_ch, EKey /*key*/)
Michele Bosi's avatar
Michele Bosi committed
556 557 558 559 560
  {
    // BaseDemo::keyReleaseEvent(unicode_ch, key);

    switch((unsigned char)tolower(unicode_ch))
    {
Michele Bosi's avatar
Michele Bosi committed
561
    case 'b':
562 563
      mVividRendering->setBackgroundImageEnabled( ! mVividRendering->backgroundImageEnabled() );
      if ( mVividRendering->backgroundImageEnabled() ) {
564 565
        // mVividRendering->setBackgroundImage( mBackgroundImage.get() );
        mVividRendering->backgroundTexSampler()->texture()->createTexture2D( mBackgroundImage.get(), TF_RGBA, false, false );
566 567
      }
      break;
Michele Bosi's avatar
Michele Bosi committed
568
    case 'v':
569
      mVividRendering->setStencilEnabled( ! mVividRendering->stencilEnabled() );
570
      break;
571
    case 'n':
572
      mOutlineMode->setUniformI( (mOutlineMode->getUniformI() + 1) % 6 );
Michele Bosi's avatar
Michele Bosi committed
573 574
      break;
    case 'r':
575
      mVivid->initShaders();
576
      mVividRendering->vividVolume()->volumeGLSLProgram()->reload();
577
      break;
Michele Bosi's avatar
Michele Bosi committed
578
    case 'q':
579 580
      mVivid->setUseQueryObject(!mVivid->useQueryObject());
      break;
Michele Bosi's avatar
Michele Bosi committed
581
    case '+':
582 583
      mVivid->setNumPasses(mVivid->numPasses() + 1);
      break;
Michele Bosi's avatar
Michele Bosi committed
584
    case '-':
585 586 587 588
      if (mVivid->numPasses() > 1) {
        mVivid->setNumPasses(mVivid->numPasses() - 1);
      }
      break;
Michele Bosi's avatar
Michele Bosi committed
589
    case '1':
Michele Bosi's avatar
Michele Bosi committed
590
      mVividRendering->setRenderingMode(Vivid::DepthPeeling);
591
      break;
Michele Bosi's avatar
Michele Bosi committed
592
    case '2':
Michele Bosi's avatar
Michele Bosi committed
593
      mVividRendering->setRenderingMode(Vivid::FastRender);
594
      break;
Michele Bosi's avatar
Michele Bosi committed
595
    case '3':
Michele Bosi's avatar
Michele Bosi committed
596
      mVividRendering->setRenderingMode(Vivid::StencilRender);
597 598
      break;
    case 's':
599
      saveActor( this->mVividRendering->sceneManager()->tree()->actors()->at(0) );
600
      break;
Michele Bosi's avatar
Michele Bosi committed
601
    case 'a': {
602
        float opacity = mVividRendering->opacity() - 0.025f;
603
        opacity = max(opacity, 0.0f);
604
        mVividRendering->setOpacity( opacity );
605 606
        printf("opacity: %f\n", opacity);
      }
Michele Bosi's avatar
Michele Bosi committed
607 608
      break;
    case 'd': {
609
        float opacity = mVividRendering->opacity() + 0.025f;
610
        opacity = min(opacity, 1.0f);
611
        mVividRendering->setOpacity( opacity );
612 613 614
        printf("opacity: %f\n", opacity);
      }
      break;
615 616 617 618 619 620 621
    case 'o':
      mFogMode->setUniformI( ( mFogMode->getUniformI() + 1 ) % 4 );
      break;
    case 'p':
      mFogTarget->setUniformI( ( mFogTarget->getUniformI() + 1 ) % 3 );
      break;
    case 'i':
622 623
      mLiverOutlineMode->setUniformI( ( mLiverOutlineMode->getUniformI() + 1 ) % 6 );
      // mLiverActor->setEnableMask( mLiverOutlineMode->getUniformI() == 1 );
624 625
      break;
    }
Michele Bosi's avatar
Michele Bosi committed
626

627
    const char* method[] = { "DepthPeeling", "FastRender", "StencilRender" };
628
    printf("method:           %s\n", method[mVividRendering->renderingMode()]);
Michele Bosi's avatar
Michele Bosi committed
629 630 631
    printf("pass counter:     %d\n", mVivid->passCounter());
    printf("num passes:       %d\n", mVivid->numPasses());
    printf("use query object: %d\n", mVivid->useQueryObject());
Michele Bosi's avatar
Michele Bosi committed
632 633 634 635
    printf("---\n");
    openglContext()->update();
  }

636 637 638 639 640 641
  void resizeEvent(int w, int h)
  {
    mVividRendering->camera()->viewport()->set( 0, 0, w, h );
    mVividRendering->camera()->setProjectionPerspective();
  }

642
  void updateEvent() {
643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662
    openglContext()->makeCurrent();

    // FPS counter
    if (Time::currentTime() - mStartTime > 0.500f)
    {
      double secs = (Time::currentTime() - mStartTime);
      mFPS = mFrameCount / secs;
      mFrameCount = 0;
      mStartTime = Time::currentTime();
    }
    mFrameCount++;

    // update the scene content
    updateScene();

    // set frame time for all the rendering
    real now_time = Time::currentTime();
    mVividRendering->setFrameClock( now_time );

    // execute rendering
663
    mVividRendering->render( openglContext()->framebuffer() );
664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680

    // show rendering
    if ( openglContext()->hasDoubleBuffer() ) {
      openglContext()->swapBuffers();
    }

    VL_CHECK_OGL();

    // useful for debugging
    // wglMakeCurrent(NULL,NULL);

    if ( mFPSTimer.elapsed() > 1 )
    {
      mFPSTimer.start();
      openglContext()->setWindowTitle( vl::Say("[%.1n] %s") << fps() << appletName()  + " - " + vl::String("VL ") + vl::VisualizationLibrary::versionString() );
      vl::Log::print( vl::Say("FPS=%.1n\n") << fps() );
    }
681

682
    // update textured quad
683
    //if ( mVivid->backgroundImage() == mBackgroundImage.get() && mVivid->backgroundImageEnabled() ) {
684
    //  if ( fract( Time::currentTime() ) < 0.25f ) {
685 686
    //    memcpy( mBackgroundImage->pixels(), mBackgroundImages[0]->pixels(), mBackgroundImage->requiredMemory() );
    //    mVivid->updateBackgroundImage();
687
    //  } else
688
    //  if ( fract( Time::currentTime() ) < 0.50f ) {
689 690
    //    memcpy( mBackgroundImage->pixels(), mBackgroundImages[1]->pixels(), mBackgroundImage->requiredMemory() );
    //    mVivid->updateBackgroundImage();
691
    //  } else
692
    //  if ( fract( Time::currentTime() ) < 0.75f ) {
693 694 695 696 697 698 699
    //    memcpy( mBackgroundImage->pixels(), mBackgroundImages[2]->pixels(), mBackgroundImage->requiredMemory() );
    //    mVivid->updateBackgroundImage();
    //  } else {
    //    memcpy( mBackgroundImage->pixels(), mBackgroundImages[3]->pixels(), mBackgroundImage->requiredMemory() );
    //    mVivid->updateBackgroundImage();
    //  }
    //}
700 701
  }

702
  void showStatistics(ref<ResourceDatabase> res_db)
Michele Bosi's avatar
Michele Bosi committed
703
  {
704 705 706
    std::set<Geometry*> geometries;
    std::vector< ref<Geometry> > geom_db;
    std::vector< ref<Actor> > actor_db;
Michele Bosi's avatar
Michele Bosi committed
707

708 709
    res_db->get<Actor>(actor_db);
    res_db->get<Geometry>(geom_db);
Michele Bosi's avatar
Michele Bosi committed
710 711 712 713 714 715 716 717

    // find number of unique geometries

    for(size_t i=0; i<geom_db.size(); ++i)
      geometries.insert( geom_db[i].get() );

    for(size_t i=0; i<actor_db.size(); ++i)
    {
718
      Geometry* geom = actor_db[i]->lod(0)->as<Geometry>();
Michele Bosi's avatar
Michele Bosi committed
719 720 721 722 723 724
      if (geom)
        geometries.insert( geom );
    }

    int total_triangles = 0;
    int total_draw_calls = 0;
725
    for( std::set<Geometry*>::iterator it = geometries.begin(); it != geometries.end(); ++it )
Michele Bosi's avatar
Michele Bosi committed
726 727 728 729 730 731 732 733 734 735 736 737 738
    {
      total_draw_calls += (*it)->drawCalls().size();
      for(int i=0; i < (*it)->drawCalls().size(); ++i )
        total_triangles += (*it)->drawCalls().at(i)->countTriangles();
    }

    VL_LOG_PRINT << "Statistics:\n";
    VL_LOG_PRINT << "+ Total triangles  = " << total_triangles << "\n";
    VL_LOG_PRINT << "+ Total draw calls = " << total_draw_calls << "\n";
    VL_LOG_PRINT << "+ Actors           = " << actor_db.size() << "\n";
    VL_LOG_PRINT << "+ Geometries       = " << geometries.size() << "\n";
  }

739
  void fileDroppedEvent(const std::vector<String>& files)
Michele Bosi's avatar
Michele Bosi committed
740 741 742 743 744 745 746
  {
    loadModel(files);
    // update the rendering
    openglContext()->update();
  }

protected:
Michele Bosi's avatar
Michele Bosi committed
747
  ref<VividRendering> mVividRendering;
748 749
  ref<VividRenderer> mVivid;

Michele Bosi's avatar
Michele Bosi committed
750
  std::set<ref<Effect>> mEffects;
751 752
  std::vector<String> mLastShaders;
  String mLastModelName;
Michele Bosi's avatar
Michele Bosi committed
753 754 755 756 757 758 759 760
  ref<Image> mBackgroundImages[4];
  ref<Image> mBackgroundImage;
  ref<Uniform> mOutlineMode;
  ref<Uniform> mOutlineSlicePlane;
  ref<Uniform> mFogMode;
  ref<Uniform> mFogTarget;
  ref<Uniform> mLiverOutlineMode;
  ref<Actor> mLiverActor;
Michele Bosi's avatar
Michele Bosi committed
761 762 763 764 765
};

// Have fun!

BaseDemo* Create_App_Vivid() { return new App_Vivid; }