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

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

Moved memory leak detection from source file to headerfile. Its still in the class but at least not in the source file.

The leak detection works, but the false positives are not stopped.
Use Linux/Valgrind? to make your final leak detection beyond the easy first approach in MSVC

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