source: osgVisual/src/distortion/visual_distortion.cpp @ 87

Last change on this file since 87 was 87, checked in by Torben Dannhauer, 14 years ago

Introductes VS 2008 Memory Leak Debugging.
Todo: Compile on Linux and compare with Valgrind, VS 2008 seems to be awkward in leak debugging

File size: 19.2 KB
Line 
1/* -*-c++-*- osgVisual - Copyright (C) 2009-2010 Torben Dannhauer
2 *
3 * This library is based on OpenSceneGraph, open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * osgVisual requires for some proprietary modules a license from the correspondig manufacturer.
9 * You have to aquire licenses for all used proprietary modules.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * OpenSceneGraph Public License for more details.
15*/
16
17#include <visual_distortion.h>
18
19using namespace osgVisual;
20
21visual_distortion::visual_distortion(osgViewer::Viewer* viewer_, osg::ArgumentParser& arguments_) : viewer(viewer_), arguments(arguments_)
22{
23        OSG_NOTIFY (osg::ALWAYS ) << "visual_distortion instantiated." << std::endl;
24        #include <leakDetection.h>
25
26        initialized = false;
27        distortionEnabled = false;
28        parser = new CameraConfigParser();
29
30        distortedGraph = NULL;
31        cleanGraph = NULL;
32
33        distortMapTexture = NULL;
34        blendMapTexture = NULL;
35}
36
37visual_distortion::~visual_distortion(void)
38{
39        OSG_NOTIFY (osg::ALWAYS ) << "visual_distortion destroyed." << std::endl;
40}
41
42bool visual_distortion::processCommandlineparameters()
43{
44        arguments.getApplicationUsage()->addCommandLineOption("-C <channelname>","Setup the channel name, this is the preset for blendmap, distortionmap and camera configuration file.");
45        arguments.getApplicationUsage()->addCommandLineOption("--fbo","Use Frame Buffer Object for render to texture, where supported.");
46    arguments.getApplicationUsage()->addCommandLineOption("--fb","Use FrameBuffer for render to texture.");
47    arguments.getApplicationUsage()->addCommandLineOption("--pbuffer","Use Pixel Buffer for render to texture, where supported.");
48    arguments.getApplicationUsage()->addCommandLineOption("--window","Use a seperate Window for render to texture.");
49    arguments.getApplicationUsage()->addCommandLineOption("--width","Set the width of the render to texture.");
50    arguments.getApplicationUsage()->addCommandLineOption("--height","Set the height of the render to texture.");
51    arguments.getApplicationUsage()->addCommandLineOption("--texture-rectangle","Use osg::TextureRectangle for doing the render to texure to.");
52    arguments.getApplicationUsage()->addCommandLineOption("--distortionmap","Set a distortion map file name.");
53    arguments.getApplicationUsage()->addCommandLineOption("--blendmap","Set a blend map file name.");
54    arguments.getApplicationUsage()->addCommandLineOption("--shaderDistortion","Use OpenGL shader for distortion and blending.");
55        arguments.getApplicationUsage()->addKeyboardMouseBinding("d", "Toggle Distortion.");
56
57        // Read out Distortion CMDLine arguments
58        tex_width = 2048;
59    tex_height = 2048;
60    while (arguments.read("--width", tex_width)) {}
61    while (arguments.read("--height", tex_height)) {}
62
63        renderImplementation = osg::Camera::FRAME_BUFFER_OBJECT;
64
65    while (arguments.read("--fbo")) { renderImplementation = osg::Camera::FRAME_BUFFER_OBJECT; }
66    while (arguments.read("--pbuffer")) { renderImplementation = osg::Camera::PIXEL_BUFFER; }
67    while (arguments.read("--pbuffer-rtt")) { renderImplementation = osg::Camera::PIXEL_BUFFER_RTT; }
68    while (arguments.read("--fb")) { renderImplementation = osg::Camera::FRAME_BUFFER; }
69    while (arguments.read("--window")) { renderImplementation = osg::Camera::SEPERATE_WINDOW; }
70
71    useTextureRectangle = false;
72    while (arguments.read("--texture-rectangle")) { useTextureRectangle = true; }
73        useShaderDistortion = false;
74    while (arguments.read("--shaderDistortion")) { useShaderDistortion = true; }
75    useHDR = false; 
76    while (arguments.read("--hdr")) { useHDR = true; }
77
78        distortMapFileName = "..\\resources\\distortion\\distort_distDisabled.bmp";
79    while (arguments.read("--distortionmap", distortMapFileName)) { }
80        blendMapFileName = "..\\resources\\distortion\\blend_distDisabled.bmp";
81    while (arguments.read("--blendmap", blendMapFileName)) { }
82
83        std::string pre_cfg("..\\resources\\distortion\\view_");
84        std::string pre_distortion("..\\resources\\distortion\\distort_");
85        std::string pre_blend("..\\resources\\distortion\\blend_");
86        std::string post_cfg(".cfg");
87        std::string post_distortion(".bmp");
88        std::string post_blend(".bmp");
89        std::string channelname;
90        while (arguments.read("-C",channelname))
91        {
92                OSG_NOTIFY(osg::INFO) << "channelname:" << channelname << std::endl;
93                // load channel config
94                parser->parseConfigFile((pre_cfg+channelname+post_cfg).data());
95                // load channel blendmap
96                blendMapFileName = (pre_blend+channelname+post_blend).data();
97                // load channel distortionmap
98                distortMapFileName = (pre_distortion+channelname+post_distortion).data(); 
99                // set channel frustum
100                if( parser->isConfigParsed())
101                        viewer->getCamera()->setProjectionMatrixAsFrustum((parser->getFrustumDataset())[0], (parser->getFrustumDataset())[1], (parser->getFrustumDataset())[2], (parser->getFrustumDataset())[3], (parser->getFrustumDataset())[4], (parser->getFrustumDataset())[5]);
102                else
103                        OSG_NOTIFY(osg::WARN) << "WARNING: Unable to parse Frustum values from '" << pre_cfg<<channelname<<post_cfg << "' -- continue without valid frustum values." << std::endl;
104        }
105
106         // report any errors if they have occurred when parsing the program arguments.
107    if (arguments.errors())
108    {
109        arguments.writeErrorMessages(std::cout);
110                exit(1);
111    }
112        return true;
113}
114
115osg::Group* visual_distortion::initialize(osg::Group* subgraph, const osg::Vec4& clearColor )
116{
117        OSG_NOTIFY (osg::ALWAYS ) << "visual_distortion initialize..." << std::endl;
118
119        // Process Commandline arguments:
120        processCommandlineparameters();
121
122        // Add this node to the scenegraph to get updated during update traversal.
123        subgraph->addChild( this );
124
125        // add the keyboard handler for toggle distortion
126        kBEventHandler = new ToggleDistortionKBEventHandler( this );
127        viewer->addEventHandler( kBEventHandler );
128
129        cleanGraph = subgraph;
130        distortedGraph = createPreRenderSubGraph( subgraph, clearColor );
131
132        // Create and install updateCallback (to get called for copying the main cameras view matrixes to the PRE_RENDER camera)
133        // -- must be called _AFTER_ createPreRenderSubGraph() (necessary because sceneCamera is set by createPreRenderSubGraph())
134        updateCallback = new distortionUpdateCallback( viewer, sceneCamera );
135        this->setUpdateCallback( updateCallback );
136
137        // Note down state flags..
138        initialized = true;
139        distortionEnabled = true;
140
141        distortionEnabled = true;
142        viewer->setSceneData( distortedGraph );
143       
144        return distortedGraph;
145}
146
147void visual_distortion::shutdown()
148{
149        if(initialized)
150        {
151                // Remove this Node from scenegraph
152                cleanGraph->removeChild( this );
153
154                // Remove update callback
155                this->removeUpdateCallback( updateCallback );
156                updateCallback = NULL;
157
158                OSG_NOTIFY (osg::ALWAYS ) << "visual_distortion shutdown complete." << std::endl;
159        }
160}
161
162void visual_distortion::distortionUpdateCallback::operator()(osg::Node* node, osg::NodeVisitor* nv)
163{
164        // Copy Main Camera's matrixes to the PRE_RENDER Camera.
165        std::cout << "distortion updatecallback" << std::endl;
166        sceneCamera->setViewMatrix( viewer->getCamera()->getViewMatrix() );
167        sceneCamera->setProjectionMatrix( viewer->getCamera()->getProjectionMatrix() );
168}
169
170void visual_distortion::toggleDistortion()
171{
172        // Toggle
173        //// If not Distorted: enabled distortion
174        if( !distortionEnabled )
175        {
176                distortionEnabled = true;
177                viewer->setSceneData( distortedGraph );
178        }
179        else    // .. otherwise disable distortion
180        {
181                distortionEnabled = false;
182                viewer->setSceneData( cleanGraph );
183        }
184}
185
186
187osg::Group* visual_distortion::createPreRenderSubGraph(osg::Group* subgraph, const osg::Vec4& clearColor )
188{
189    if (!subgraph) return 0;
190
191    // create a group to contain the flag and the pre rendering camera.
192    osg::Group* parent = new osg::Group;
193
194    // texture to render to and to use for rendering of flag.
195    osg::Texture* texture = 0;
196    if (useTextureRectangle)
197    {
198        osg::TextureRectangle* textureRect = new osg::TextureRectangle;
199        textureRect->setTextureSize(tex_width, tex_height);
200        textureRect->setInternalFormat(GL_RGBA);
201        textureRect->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
202        textureRect->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
203       
204        texture = textureRect;
205    }
206    else
207    {
208        osg::Texture2D* texture2D = new osg::Texture2D;
209        texture2D->setTextureSize(tex_width, tex_height);
210        texture2D->setInternalFormat(GL_RGBA);
211        texture2D->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
212        texture2D->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
213       
214        texture = texture2D;
215    } 
216
217    if (useHDR)
218    {
219        texture->setInternalFormat(GL_RGBA16F_ARB);
220        texture->setSourceFormat(GL_RGBA);
221        texture->setSourceType(GL_FLOAT);
222    }
223
224    // load a distortion map texture file
225        if ( osgDB::fileExists( distortMapFileName ) )
226                distortMapTexture = loadTexture(distortMapFileName);
227        else
228        {
229                OSG_NOTIFY(osg::FATAL) << "ERROR: Distortionmap file'" << distortMapFileName << "' not found! Please change the channelname, filename or copy the desired file to the applications root folder!" << std::endl;
230                exit(-1);
231        }
232
233    // load a blend map texture file
234        if ( osgDB::fileExists( blendMapFileName ) )
235                blendMapTexture = loadTexture(blendMapFileName);
236        else
237        {
238                OSG_NOTIFY(osg::FATAL) << "ERROR: Blendmap file'" << blendMapFileName << "' not found! Please change the channelname, filename or copy the desired file to the applications root folder!" << std::endl;
239                exit(-1);
240        }
241
242    // set up the plane to render the rendered view.
243    {
244        // create the quad to visualize.
245        osg::Geometry* polyGeom = new osg::Geometry();
246
247        polyGeom->setSupportsDisplayList(false);
248
249        osg::Vec3 origin(0.0f,0.0f,0.0f);
250        osg::Vec3 xAxis(1.0f,0.0f,0.0f);
251        osg::Vec3 yAxis(0.0f,1.0f,0.0f);
252        osg::Vec3 zAxis(0.0f,0.0f,1.0f);
253        float height = 1024.0f;
254        float width = 1280.0f;
255        int noSteps = 128;
256        if (useShaderDistortion)
257            noSteps = 2;
258
259        osg::Vec3Array* vertices = new osg::Vec3Array;
260        osg::Vec2Array* texcoords = new osg::Vec2Array;
261        osg::Vec2Array* texcoords2 = useShaderDistortion?NULL:(new osg::Vec2Array);
262        osg::Vec4Array* colors = new osg::Vec4Array;
263
264        osg::Vec3 bottom = origin;
265        osg::Vec3 dx = xAxis*(width/((float)(noSteps-1)));
266        osg::Vec3 dy = yAxis*(height/((float)(noSteps-1)));
267
268        osg::Vec2 bottom_texcoord(0.0f,0.0f);
269        osg::Vec2 dx_texcoord(1.0f/(float)(noSteps-1),0.0f);
270        osg::Vec2 dy_texcoord(0.0f,1.0f/(float)(noSteps-1));
271
272        osg::Vec3 cursor = bottom;
273        osg::Vec2 texcoord = bottom_texcoord;
274        int i,j;
275        for(i=0;i<noSteps;++i)
276        {
277            osg::Vec3 cursor = bottom+dy*(float)i;
278            osg::Vec2 texcoord = bottom_texcoord+dy_texcoord*(float)i;
279            for(j=0;j<noSteps;++j)
280            {
281                vertices->push_back(cursor);
282                if (distortMapTexture && !useShaderDistortion)
283                {
284                    osg::Vec2 imgcoord = osg::Vec2((distortMapTexture->getImage(0)->s()-1) * texcoord.x(),
285                                                   (distortMapTexture->getImage(0)->t()-1) * texcoord.y());
286                    unsigned char* pPixel = &distortMapTexture->getImage(0)->data()[(int)imgcoord.y()*distortMapTexture->getImage(0)->getRowSizeInBytes()+
287                                                                                    (int)imgcoord.x()*distortMapTexture->getImage(0)->getPixelSizeInBits()/8];
288                    texcoords->push_back(osg::Vec2(((float)pPixel[2] / 255.0f + (pPixel[0] % 16)) / 16.0f,
289                                                   1.0f - ((float)pPixel[1] / 255.0f + (pPixel[0] / 16)) / 16.0f));
290                    texcoords2->push_back(osg::Vec2(texcoord.x(), texcoord.y()));
291                }
292                else
293                    texcoords->push_back(osg::Vec2(texcoord.x(), texcoord.y()));
294                colors->push_back(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
295
296                cursor += dx;
297                texcoord += dx_texcoord;
298            }
299        }
300
301        // pass the created vertex array to the points geometry object.
302        polyGeom->setVertexArray(vertices);
303
304        polyGeom->setColorArray(colors);
305        polyGeom->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
306        polyGeom->setTexCoordArray(0,texcoords);
307        if (!useShaderDistortion)
308            polyGeom->setTexCoordArray(2,texcoords2);
309
310        for(i=0;i<noSteps-1;++i)
311        {
312            osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(osg::PrimitiveSet::QUAD_STRIP);
313            for(j=0;j<noSteps;++j)
314            {
315                elements->push_back(j+(i+1)*noSteps);
316                elements->push_back(j+(i)*noSteps);
317            }
318            polyGeom->addPrimitiveSet(elements);
319        }
320
321        // new we need to add the texture to the Drawable, we do so by creating a
322        // StateSet to contain the Texture StateAttribute.
323        osg::StateSet* stateset = polyGeom->getOrCreateStateSet();
324        stateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);
325        stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
326        stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
327
328        osg::Geode* geode = new osg::Geode();
329        geode->addDrawable(polyGeom);
330
331        if (useShaderDistortion)
332        {
333            // apply the distortion map texture
334            if (distortMapTexture)
335                geode->getOrCreateStateSet()->setTextureAttributeAndModes(1, distortMapTexture, osg::StateAttribute::ON);
336        }
337
338        // apply the blend map texture
339        if (blendMapTexture)
340            geode->getOrCreateStateSet()->setTextureAttributeAndModes(2, blendMapTexture, osg::StateAttribute::ON);
341
342        // set up the camera to render the textured quad
343        osg::Camera* camera = new osg::Camera;
344
345        // just inherit the main cameras view
346        camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
347        camera->setViewMatrix(osg::Matrix::identity());
348        //camera->setProjectionMatrixAsOrtho2D(0,viewer->getCamera()->getViewport()->width(),0,viewer->getCamera()->getViewport()->height());
349                camera->setProjectionMatrixAsOrtho2D(0,1280,0,1024);
350
351        // set the camera to render before the main camera.
352        camera->setRenderOrder(osg::Camera::POST_RENDER, 200);
353
354        // only clear the depth buffer
355        camera->setClearMask(0);
356
357        // add subgraph to render
358        camera->addChild(geode);
359
360        if (useShaderDistortion)
361        {
362            // create shaders for distortion
363            osg::StateSet* ss = geode->getOrCreateStateSet();
364
365            osg::Program* distortProgram = new osg::Program;
366            distortProgram->setName( "distortion" );
367            osg::Shader* distortVertObj = new osg::Shader( osg::Shader::VERTEX );
368            osg::Shader* distortFragObj = new osg::Shader( osg::Shader::FRAGMENT );
369
370            if (loadShaderSource( distortVertObj, "shader.vert" ) &&
371                loadShaderSource( distortFragObj, "shader.frag" ) &&
372                distortMapTexture)
373            {
374                distortProgram->addShader( distortFragObj );
375                distortProgram->addShader( distortVertObj );
376                ss->addUniform( new osg::Uniform("textureImage", 0) );
377                ss->addUniform( new osg::Uniform("textureDistort", 1) );
378                ss->addUniform( new osg::Uniform("textureBlend", 2) );
379                ss->setAttributeAndModes(distortProgram, osg::StateAttribute::ON);
380            }
381                        else
382                        {
383                                OSG_NOTIFY(osg::FATAL) << "##################################" << std::endl << "## Unable to activate ShaderDistortion!" << std::endl << "## ABORT" << std::endl << "##################################" << std::endl;
384                                exit(0);
385                        }
386        }
387
388        parent->addChild(camera);
389    }
390
391    // then create the camera node to do the render to texture
392    {   
393        osg::Camera* camera = new osg::Camera;
394
395        // set up the background color and clear mask.
396        camera->setClearColor(clearColor);
397        camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
398
399
400        // just inherit the main cameras view
401                /* ABSOLUTE_RF required to make intersections possible.
402                Disadvantage of ABOLUTE_RF : the maincameras view matrix and projection
403                matrix has to copied to the PRE_RENDER camera by our self.
404                Therefore an update callback is installed.
405                */
406                camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); 
407        camera->setProjectionMatrix(osg::Matrixd::identity());
408        camera->setViewMatrix(osg::Matrixd::identity());
409
410        // set viewport
411        camera->setViewport(0,0,tex_width,tex_height);
412
413        // set the camera to render before the main camera.
414        camera->setRenderOrder(osg::Camera::PRE_RENDER, 0);
415
416                sceneCamera = camera;
417
418        // tell the camera to use OpenGL frame buffer object where supported.
419        camera->setRenderTargetImplementation(renderImplementation);
420
421        // attach the texture and use it as the color buffer.
422        camera->attach(osg::Camera::COLOR_BUFFER, texture);     // No Multisampling/Antialiasing
423                //camera->attach(osg::Camera::COLOR_BUFFER, texture, 0, 0, false, 4, 4); // 4x Multisampling/Antialiasing
424
425        // add subgraph to render
426        camera->addChild(subgraph);
427
428        parent->addChild(camera);
429    }   
430    return parent;
431}
432
433
434bool visual_distortion::loadShaderSource( osg::Shader* shader, const std::string& fileName )
435{
436    std::string foundFileName = osgDB::findDataFile(fileName);
437    if (foundFileName.length() != 0 )
438    {
439        return shader->loadShaderSourceFromFile( foundFileName.c_str() );
440    }
441
442    OSG_NOTIFY(osg::WARN) << "File \"" << fileName << "\" not found." << std::endl;
443
444    return false;
445}
446
447osg::Texture* visual_distortion::loadTexture( const std::string& fileName )
448{
449    std::string foundFileName = osgDB::findDataFile(fileName);
450    if (foundFileName.length() != 0 )
451    {
452        // load distortion map texture file
453        osg::Image* image = osgDB::readImageFile(foundFileName);
454        if (image)
455        {
456                        osg::Texture2D* texture = new osg::Texture2D;
457            texture->setImage(image);
458            texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::NEAREST);
459            texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::NEAREST);
460            texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::CLAMP_TO_EDGE);
461            texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP_TO_EDGE);
462            return texture;
463        }
464    }
465
466    OSG_NOTIFY(osg::WARN) << "File \"" << fileName << "\" not found." << std::endl;
467
468    return NULL;
469}
Note: See TracBrowser for help on using the repository browser.