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

Last change on this file since 152 was 152, checked in by Torben Dannhauer, 13 years ago

Silverlining, Distortion now uses XMl configuration file for configuration.

Todo: vista2D and the whole dataIO tree.

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