From 5eaf95ed0fd3480a50180ebc2910878bdcd6321b Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 17 Nov 2008 15:49:24 +0000 Subject: [PATCH] Ported example to using OSG objects for rendering rather than GLUT --- examples/osgbrowser/osgbrowser.cpp | 916 +++++++++++++---------------- 1 file changed, 404 insertions(+), 512 deletions(-) diff --git a/examples/osgbrowser/osgbrowser.cpp b/examples/osgbrowser/osgbrowser.cpp index 5d4381001..b61c671cd 100644 --- a/examples/osgbrowser/osgbrowser.cpp +++ b/examples/osgbrowser/osgbrowser.cpp @@ -5,588 +5,480 @@ #include #include +#include #include #include #include - -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Linden Lab Inc. (http://lindenlab.com) code. - * - * The Initial Developer of the Original Code is: - * Callum Prentice (callum@ubrowser.com) - * - * Portions created by the Initial Developer are Copyright (C) 2006 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Callum Prentice (callum@ubrowser.com) - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include - -#include +#include #include "llmozlib2.h" -//////////////////////////////////////////////////////////////////////////////// -// Implementation of the test app - implemented as a class and derrives from -// the observer so we can catch events emitted by LLMozLib -// -class testGL : - public LLEmbeddedBrowserWindowObserver +class UBrowserImage; + +class UBrowserImage : public osg::Image, public LLEmbeddedBrowserWindowObserver { - public: - testGL() : - mAppWindowWidth( 800 ), // dimensions of the app window - can be anything - mAppWindowHeight( 600 ), - mBrowserWindowWidth( mAppWindowWidth ), // dimensions of the embedded browser - can be anything - mBrowserWindowHeight( mAppWindowHeight ), // but looks best when it's the same as the app window - mAppTextureWidth( -1 ), // dimensions of the texture that the browser is rendered into - mAppTextureHeight( -1 ), // calculated at initialization - mAppTexture( 0 ), - mNeedsUpdate( true ), // flag to indicate if browser texture needs an update - mBrowserWindowId( 0 ), - mAppWindowName( "testGL" ), - //mHomeUrl( "http://www.google.com" ) - mHomeUrl( "http://www.google.com" ) - { - std::cout << "LLMozLib version: " << LLMozLib::getInstance()->getVersion() << std::endl; - }; + public: + + UBrowserImage(const std::string& appWindowName,int width, int height); + - //////////////////////////////////////////////////////////////////////////////// - // - void init( char* arg0 ) - { - // OpenGL initialization - glClearColor( 0.0f, 0.0f, 0.0f, 0.5f); - glEnable( GL_COLOR_MATERIAL ); - glColorMaterial( GL_FRONT, GL_AMBIENT_AND_DIFFUSE ); - glEnable( GL_TEXTURE_2D ); - glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); - glEnable( GL_CULL_FACE ); - // calculate texture size required (next power of two above browser window size - for ( mAppTextureWidth = 1; mAppTextureWidth < mBrowserWindowWidth; mAppTextureWidth <<= 1 ) - { - }; + virtual void sendPointerEvent(int x, int y, int buttonMask); - for ( mAppTextureHeight = 1; mAppTextureHeight < mBrowserWindowHeight; mAppTextureHeight <<= 1 ) - { - }; + virtual void sendKeyEvent(int key, bool keyDown); - // create the texture used to display the browser data - glGenTextures( 1, &mAppTexture ); - glBindTexture( GL_TEXTURE_2D, mAppTexture ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - glTexImage2D( GL_TEXTURE_2D, 0, - GL_RGB, - mAppTextureWidth, mAppTextureHeight, - 0, GL_RGB, GL_UNSIGNED_BYTE, 0 ); + void navigateTo(const std::string& page); + - // create a single browser window and set things up. - std::string applicationDir = osgDB::getFilePath(arg0); - if (applicationDir.empty()) applicationDir = osgDB::getRealPath("."); - else applicationDir = osgDB::getRealPath(applicationDir); - - std::string componentDir = "/usr/lib/xulrunner"; - std::string profileDir = applicationDir + "/" + "testGL_profile"; - LLMozLib::getInstance()->init( applicationDir, componentDir, profileDir, getNativeWindowHandle() ); - - - mBrowserWindowId = LLMozLib::getInstance()->createBrowserWindow( mBrowserWindowWidth, mBrowserWindowHeight ); - - std::cout<<"after createBrowserWindow("<addObserver( mBrowserWindowId, this ); + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onNavigateComplete( const EventType& eventIn ) + { + osg::notify(osg::NOTICE) << "Event: end navigation to " << eventIn.getEventUri() << " with response status of " << eventIn.getIntValue() << std::endl; + }; - // append details to agent string - LLMozLib::getInstance()->setBrowserAgentId( mAppWindowName ); + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onUpdateProgress( const EventType& eventIn ) + { + osg::notify(osg::NOTICE) << "Event: progress value updated to " << eventIn.getIntValue() << std::endl; + }; - // don't flip bitmap - LLMozLib::getInstance()->flipWindow( mBrowserWindowId, false ); + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onStatusTextChange( const EventType& eventIn ) + { + osg::notify(osg::NOTICE) << "Event: status updated to " << eventIn.getStringValue() << std::endl; + }; - // go to the "home page" - LLMozLib::getInstance()->navigateTo( mBrowserWindowId, mHomeUrl ); - }; + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onLocationChange( const EventType& eventIn ) + { + osg::notify(osg::NOTICE) << "Event: location changed to " << eventIn.getStringValue() << std::endl; + }; - //////////////////////////////////////////////////////////////////////////////// - // - void reset( void ) - { - // unhook observer - LLMozLib::getInstance()->remObserver( mBrowserWindowId, this ); + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onClickLinkHref( const EventType& eventIn ) + { + osg::notify(osg::NOTICE) << "Event: clicked on link to " << eventIn.getStringValue() << std::endl; + }; - // clean up - LLMozLib::getInstance()->reset(); - }; + void update(); - //////////////////////////////////////////////////////////////////////////////// - // - void reshape( int widthIn, int heightIn ) - { - if ( heightIn == 0 ) - heightIn = 1; + void* getNativeWindowHandle(); - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); + protected: - glViewport( 0, 0, widthIn, heightIn ); - glOrtho( 0.0f, widthIn, heightIn, 0.0f, -1.0f, 1.0f ); + virtual ~UBrowserImage(); + + void setUpKeyMap(); + + int convertToXULKey(int key) const; - // we use these elsewhere so save - mAppWindowWidth = widthIn; - mAppWindowHeight = heightIn; - - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - - glutPostRedisplay(); - }; - - void idle(); - - //////////////////////////////////////////////////////////////////////////////// - // - void display() - { - //std::cout<<"display() mBrowserWindowId = "<getBrowserWindowPixels( mBrowserWindowId ); - if ( pixels ) - { - - //std::cout<<"Texture subload "<getBrowserRowSpan( mBrowserWindowId ) / LLMozLib::getInstance()->getBrowserDepth( mBrowserWindowId )<<", "<getBrowserRowSpan( mBrowserWindowId ) / LLMozLib::getInstance()->getBrowserDepth( mBrowserWindowId ), - mBrowserWindowHeight, - LLMozLib::getInstance()->getBrowserDepth( mBrowserWindowId ) == 3 ? GL_BGR_EXT : GL_BGRA_EXT, - GL_UNSIGNED_BYTE, - pixels ); - } - else - { - std::cout<<"No data to subload"<mouseDown( mBrowserWindowId, xIn, yIn ); - } - else - if ( state == GLUT_UP ) - { - // send event to LLMozLib - LLMozLib::getInstance()->mouseUp( mBrowserWindowId, xIn, yIn ); - - // this seems better than sending focus on mouse down (still need to improve this) - LLMozLib::getInstance()->focusBrowser( mBrowserWindowId, true ); - }; - }; - - // force a GLUT update - glutPostRedisplay(); - } - - //////////////////////////////////////////////////////////////////////////////// - // - void mouseMove( int xIn , int yIn ) - { - // texture is scaled to fit the screen so we scale mouse coords in the same way - xIn = ( xIn * mBrowserWindowWidth ) / mAppWindowWidth; - yIn = ( yIn * mBrowserWindowHeight ) / mAppWindowHeight; - - // send event to LLMozLib - LLMozLib::getInstance()->mouseMove( mBrowserWindowId, xIn, yIn ); - - // force a GLUT update - glutPostRedisplay(); - }; - - //////////////////////////////////////////////////////////////////////////////// - // - void keyboard( unsigned char keyIn, int xIn, int yIn ) - { - // ESC key exits - if ( keyIn == 27 ) - { - reset(); - - exit( 0 ); - }; - - // send event to LLMozLib - if (keyIn<32) LLMozLib::getInstance()->keyPress( mBrowserWindowId, keyIn ); - else LLMozLib::getInstance()->unicodeInput( mBrowserWindowId, keyIn ); - }; - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onPageChanged( const EventType& eventIn ) - { - // flag that an update is required - page grab happens in idle() so we don't stall - mNeedsUpdate = true; - }; - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onNavigateBegin( const EventType& eventIn ) - { - std::cout << "Event: begin navigation to " << eventIn.getEventUri() << std::endl; - }; - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onNavigateComplete( const EventType& eventIn ) - { - std::cout << "Event: end navigation to " << eventIn.getEventUri() << " with response status of " << eventIn.getIntValue() << std::endl; - }; - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onUpdateProgress( const EventType& eventIn ) - { - std::cout << "Event: progress value updated to " << eventIn.getIntValue() << std::endl; - }; - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onStatusTextChange( const EventType& eventIn ) - { - std::cout << "Event: status updated to " << eventIn.getStringValue() << std::endl; - }; - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onLocationChange( const EventType& eventIn ) - { - std::cout << "Event: location changed to " << eventIn.getStringValue() << std::endl; - }; - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onClickLinkHref( const EventType& eventIn ) - { - std::cout << "Event: clicked on link to " << eventIn.getStringValue() << std::endl; - }; - - //////////////////////////////////////////////////////////////////////////////// - // - int getAppWindowWidth() - { - return mAppWindowWidth; - }; - - //////////////////////////////////////////////////////////////////////////////// - // - int getAppWindowHeight() - { - return mAppWindowHeight; - }; - - //////////////////////////////////////////////////////////////////////////////// - // - std::string getAppWindowName() - { - return mAppWindowName; - }; - - //////////////////////////////////////////////////////////////////////////////// - // - void* getNativeWindowHandle(); - - private: - int mAppWindowWidth; - int mAppWindowHeight; - int mBrowserWindowWidth; - int mBrowserWindowHeight; - int mAppTextureWidth; - int mAppTextureHeight; - GLuint mAppTexture; - int mBrowserWindowId; - std::string mAppWindowName; - std::string mHomeUrl; - bool mNeedsUpdate; + int _browserWindowId; + void* _nativeWindowHandle; + + int _previousButtonMask; + bool _needsUpdate; + + typedef std::map KeyMap; + KeyMap _keyMap; }; -testGL* theApp; -//////////////////////////////////////////////////////////////////////////////// -// + +UBrowserImage::UBrowserImage(const std::string& appWindowName,int width, int height): + _nativeWindowHandle(0), + _browserWindowId(0), + _previousButtonMask(0), + _needsUpdate(true) +{ + setUpKeyMap(); + + // create a single browser window and set things up. + std::string applicationDir = osgDB::getFilePath(appWindowName); + if (applicationDir.empty()) applicationDir = osgDB::getRealPath("."); + else applicationDir = osgDB::getRealPath(applicationDir); + + std::string componentDir = "/usr/lib/xulrunner"; + std::string profileDir = applicationDir + "/" + "testGL_profile"; + LLMozLib::getInstance()->init( applicationDir, componentDir, profileDir, getNativeWindowHandle() ); + + _browserWindowId = LLMozLib::getInstance()->createBrowserWindow( width, height ); + + // tell LLMozLib about the size of the browser window + LLMozLib::getInstance()->setSize( _browserWindowId, width, height ); + + // observer events that LLMozLib emits + LLMozLib::getInstance()->addObserver( _browserWindowId, this ); + + // append details to agent string + LLMozLib::getInstance()->setBrowserAgentId( appWindowName ); + + // don't flip bitmap + LLMozLib::getInstance()->flipWindow( _browserWindowId, false ); + + LLMozLib::getInstance()->setBackgroundColor( _browserWindowId, 0, 255, 0); + + navigateTo("http://www.google.com"); + + GLint internalFormat = LLMozLib::getInstance()->getBrowserDepth( _browserWindowId ) == 3 ? GL_RGB : GL_RGBA; + GLenum pixelFormat = LLMozLib::getInstance()->getBrowserDepth( _browserWindowId ) == 3 ? GL_BGR_EXT : GL_BGRA_EXT; + + setImage(width,height,1, internalFormat, pixelFormat, GL_UNSIGNED_BYTE, + (unsigned char*)LLMozLib::getInstance()->getBrowserWindowPixels( _browserWindowId ), + osg::Image::NO_DELETE); + + setDataVariance(osg::Object::DYNAMIC); + setOrigin(osg::Image::TOP_LEFT); +} + +UBrowserImage::~UBrowserImage() +{ +} + +void UBrowserImage::sendPointerEvent(int x, int y, int buttonMask) +{ + int deltaButton = (buttonMask&1) - (_previousButtonMask&1); + _previousButtonMask = buttonMask; + + if (deltaButton>0) + { + // send event to LLMozLib + LLMozLib::getInstance()->mouseDown( _browserWindowId, x, y ); + } + else if (deltaButton<0) + { + // send event to LLMozLib + LLMozLib::getInstance()->mouseUp( _browserWindowId, x, y ); + + // this seems better than sending focus on mouse down (still need to improve this) + LLMozLib::getInstance()->focusBrowser( _browserWindowId, true ); + } else + { + // send event to LLMozLib + LLMozLib::getInstance()->mouseMove( _browserWindowId, x, y ); + } +} + +void UBrowserImage::sendKeyEvent(int key, bool keyDown) +{ + if (!keyDown) return; + + KeyMap::const_iterator itr = _keyMap.find(key); + if (_keyMap.find(key)==_keyMap.end()) LLMozLib::getInstance()->unicodeInput( _browserWindowId, key ); + else LLMozLib::getInstance()->keyPress( _browserWindowId, itr->second ); +} + +void UBrowserImage::navigateTo(const std::string& url) +{ + // go to the "home page" + LLMozLib::getInstance()->navigateTo( _browserWindowId, url ); +} + + +void UBrowserImage::update() +{ + //if ( _needsUpdate ) + { + // grab a page but don't reset 'needs update' flag until we've written it to the texture in display() + LLMozLib::getInstance()->grabBrowserWindow( _browserWindowId ); + + int width = LLMozLib::getInstance()->getBrowserRowSpan( _browserWindowId ) / LLMozLib::getInstance()->getBrowserDepth( _browserWindowId ); + int height = LLMozLib::getInstance()->getBrowserHeight( _browserWindowId ); + + GLint internalFormat = LLMozLib::getInstance()->getBrowserDepth( _browserWindowId ) == 3 ? GL_RGB : GL_RGBA; + GLenum pixelFormat = LLMozLib::getInstance()->getBrowserDepth( _browserWindowId ) == 3 ? GL_BGR_EXT : GL_BGRA_EXT; + + setImage(width,height,1, internalFormat, pixelFormat, GL_UNSIGNED_BYTE, + (unsigned char*)LLMozLib::getInstance()->getBrowserWindowPixels( _browserWindowId ), + osg::Image::NO_DELETE); + + // osg::notify(osg::NOTICE)<<"Image updated "<<(void*)data()<<", "<grabBrowserWindow( mBrowserWindowId ); - - // lots of updates for smooth motion - glutPostRedisplay(); -}; - - -void* testGL::getNativeWindowHandle() +void* UBrowserImage::getNativeWindowHandle() { + if (_nativeWindowHandle) return _nativeWindowHandle; + // My implementation of the embedded browser needs a native window handle // Can't get this via GLUT so had to use this hack - return FindWindow( NULL, mAppWindowName.c_str() ); + _nativeWindowHandle = FindWindow( NULL, _appWindowName.c_str() ); + + return _nativeWindowHandle; } + #else #include -//////////////////////////////////////////////////////////////////////////////// -// -void testGL::idle() +void* UBrowserImage::getNativeWindowHandle() { - // pump the GTK+Gecko event queue for a (limited) while. this should - // be done so that the Gecko event queue doesn't starve, and done - // *here* so that mNeedsUpdate[] can be populated by callbacks - // from Gecko. - gtk_main_iteration_do(0); - for (int iter=0; iter<10; ++iter) - if (gtk_events_pending()) - gtk_main_iteration(); + if (_nativeWindowHandle) return _nativeWindowHandle; + gtk_disable_setlocale(); + gtk_init(NULL, NULL); - //std::cout<<"idle()"<grabBrowserWindow( mBrowserWindowId ); - - // lots of updates for smooth motion - glutPostRedisplay(); -}; - - -void* testGL::getNativeWindowHandle() -{ - gtk_disable_setlocale(); - gtk_init(NULL, NULL); - - GtkWidget *win = gtk_window_new(GTK_WINDOW_POPUP); - // Why a layout widget? A MozContainer would be ideal, but - // it involves exposing Mozilla headers to mozlib-using apps. - // A layout widget with a GtkWindow parent has the desired - // properties of being plain GTK, having a window, and being - // derived from a GtkContainer. - GtkWidget *rtnw = gtk_layout_new(NULL, NULL); - gtk_container_add(GTK_CONTAINER(win), rtnw); - gtk_widget_realize(rtnw); - GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(rtnw), GTK_NO_WINDOW); - - return rtnw; -}; + _nativeWindowHandle = rtnw; + + return _nativeWindowHandle; +} #endif -//////////////////////////////////////////////////////////////////////////////// -// -void glutReshape( int widthIn, int heightIn ) +void UBrowserImage::setUpKeyMap() { - if ( theApp ) - theApp->reshape( widthIn, heightIn ); -}; + _keyMap[osgGA::GUIEventAdapter::KEY_BackSpace] = nsIDOMKeyEvent::DOM_VK_BACK_SPACE; + _keyMap[osgGA::GUIEventAdapter::KEY_Tab] = nsIDOMKeyEvent::DOM_VK_TAB; + _keyMap[osgGA::GUIEventAdapter::KEY_Linefeed] = nsIDOMKeyEvent::DOM_VK_ENTER; + _keyMap[osgGA::GUIEventAdapter::KEY_Clear] = nsIDOMKeyEvent::DOM_VK_CLEAR; + _keyMap[osgGA::GUIEventAdapter::KEY_Return] = nsIDOMKeyEvent::DOM_VK_RETURN; + _keyMap[osgGA::GUIEventAdapter::KEY_Pause] = nsIDOMKeyEvent::DOM_VK_PAUSE; + _keyMap[osgGA::GUIEventAdapter::KEY_Scroll_Lock] = nsIDOMKeyEvent::DOM_VK_SCROLL_LOCK; + _keyMap[osgGA::GUIEventAdapter::KEY_Escape] = nsIDOMKeyEvent::DOM_VK_ESCAPE; + _keyMap[osgGA::GUIEventAdapter::KEY_Delete] = nsIDOMKeyEvent::DOM_VK_DELETE; -//////////////////////////////////////////////////////////////////////////////// -// -void glutDisplay() -{ - if ( theApp ) - theApp->display(); -}; + /* Cursor control & motion */ + _keyMap[osgGA::GUIEventAdapter::KEY_Home] = nsIDOMKeyEvent::DOM_VK_HOME; + _keyMap[osgGA::GUIEventAdapter::KEY_Left] = nsIDOMKeyEvent::DOM_VK_LEFT; + _keyMap[osgGA::GUIEventAdapter::KEY_Up] = nsIDOMKeyEvent::DOM_VK_UP; + _keyMap[osgGA::GUIEventAdapter::KEY_Right] = nsIDOMKeyEvent::DOM_VK_RIGHT; + _keyMap[osgGA::GUIEventAdapter::KEY_Down] = nsIDOMKeyEvent::DOM_VK_DOWN; + _keyMap[osgGA::GUIEventAdapter::KEY_Page_Up] = nsIDOMKeyEvent::DOM_VK_PAGE_UP; + _keyMap[osgGA::GUIEventAdapter::KEY_Page_Down] = nsIDOMKeyEvent::DOM_VK_PAGE_DOWN; + _keyMap[osgGA::GUIEventAdapter::KEY_End] = nsIDOMKeyEvent::DOM_VK_END; -//////////////////////////////////////////////////////////////////////////////// -// -void glutIdle() -{ - if ( theApp ) - theApp->idle(); -}; + /* Misc Functions */ + _keyMap[osgGA::GUIEventAdapter::KEY_Print] = nsIDOMKeyEvent::DOM_VK_PRINTSCREEN; + _keyMap[osgGA::GUIEventAdapter::KEY_Insert] = nsIDOMKeyEvent::DOM_VK_INSERT; + _keyMap[osgGA::GUIEventAdapter::KEY_Cancel] = nsIDOMKeyEvent::DOM_VK_CANCEL; + _keyMap[osgGA::GUIEventAdapter::KEY_Num_Lock] = nsIDOMKeyEvent::DOM_VK_NUM_LOCK; + -//////////////////////////////////////////////////////////////////////////////// -// -void glutKeyboard( unsigned char keyIn, int xIn, int yIn ) -{ - if ( keyIn == 27 ) - { - if ( theApp ) - theApp->reset(); + /* Keypad Functions, keypad numbers cleverly chosen to map to ascii */ + _keyMap[osgGA::GUIEventAdapter::KEY_KP_Space] = nsIDOMKeyEvent::DOM_VK_SPACE; + _keyMap[osgGA::GUIEventAdapter::KEY_KP_Tab] = nsIDOMKeyEvent::DOM_VK_TAB; + _keyMap[osgGA::GUIEventAdapter::KEY_KP_Enter] = nsIDOMKeyEvent::DOM_VK_ENTER; + _keyMap[osgGA::GUIEventAdapter::KEY_KP_Home] = nsIDOMKeyEvent::DOM_VK_HOME; + _keyMap[osgGA::GUIEventAdapter::KEY_KP_Left] = nsIDOMKeyEvent::DOM_VK_LEFT; + _keyMap[osgGA::GUIEventAdapter::KEY_KP_Up] = nsIDOMKeyEvent::DOM_VK_UP; + _keyMap[osgGA::GUIEventAdapter::KEY_KP_Right] = nsIDOMKeyEvent::DOM_VK_RIGHT; + _keyMap[osgGA::GUIEventAdapter::KEY_KP_Down] = nsIDOMKeyEvent::DOM_VK_DOWN; + _keyMap[osgGA::GUIEventAdapter::KEY_KP_Page_Up] = nsIDOMKeyEvent::DOM_VK_PAGE_UP; + _keyMap[osgGA::GUIEventAdapter::KEY_KP_Page_Down] = nsIDOMKeyEvent::DOM_VK_PAGE_DOWN; + _keyMap[osgGA::GUIEventAdapter::KEY_KP_End] = nsIDOMKeyEvent::DOM_VK_END; + _keyMap[osgGA::GUIEventAdapter::KEY_KP_Insert] = nsIDOMKeyEvent::DOM_VK_INSERT; + _keyMap[osgGA::GUIEventAdapter::KEY_KP_Delete] = nsIDOMKeyEvent::DOM_VK_DELETE; + _keyMap[osgGA::GUIEventAdapter::KEY_KP_Equal] = nsIDOMKeyEvent::DOM_VK_EQUALS; + _keyMap[osgGA::GUIEventAdapter::KEY_KP_Multiply] = nsIDOMKeyEvent::DOM_VK_MULTIPLY; + _keyMap[osgGA::GUIEventAdapter::KEY_KP_Add] = nsIDOMKeyEvent::DOM_VK_ADD; + _keyMap[osgGA::GUIEventAdapter::KEY_KP_Separator] = nsIDOMKeyEvent::DOM_VK_SEPARATOR; + _keyMap[osgGA::GUIEventAdapter::KEY_KP_Subtract] = nsIDOMKeyEvent::DOM_VK_SUBTRACT; + _keyMap[osgGA::GUIEventAdapter::KEY_KP_Decimal] = nsIDOMKeyEvent::DOM_VK_DECIMAL; + _keyMap[osgGA::GUIEventAdapter::KEY_KP_Divide] = nsIDOMKeyEvent::DOM_VK_DIVIDE; - exit( 0 ); - }; + _keyMap[osgGA::GUIEventAdapter::KEY_KP_0] = nsIDOMKeyEvent::DOM_VK_NUMPAD0; + _keyMap[osgGA::GUIEventAdapter::KEY_KP_1] = nsIDOMKeyEvent::DOM_VK_NUMPAD1; + _keyMap[osgGA::GUIEventAdapter::KEY_KP_2] = nsIDOMKeyEvent::DOM_VK_NUMPAD2; + _keyMap[osgGA::GUIEventAdapter::KEY_KP_3] = nsIDOMKeyEvent::DOM_VK_NUMPAD3; + _keyMap[osgGA::GUIEventAdapter::KEY_KP_4] = nsIDOMKeyEvent::DOM_VK_NUMPAD4; + _keyMap[osgGA::GUIEventAdapter::KEY_KP_5] = nsIDOMKeyEvent::DOM_VK_NUMPAD5; + _keyMap[osgGA::GUIEventAdapter::KEY_KP_6] = nsIDOMKeyEvent::DOM_VK_NUMPAD6; + _keyMap[osgGA::GUIEventAdapter::KEY_KP_7] = nsIDOMKeyEvent::DOM_VK_NUMPAD7; + _keyMap[osgGA::GUIEventAdapter::KEY_KP_8] = nsIDOMKeyEvent::DOM_VK_NUMPAD8; + _keyMap[osgGA::GUIEventAdapter::KEY_KP_9] = nsIDOMKeyEvent::DOM_VK_NUMPAD9; - if ( theApp ) - theApp->keyboard( keyIn, xIn, yIn ); -}; + /* + * Auxiliary Functions; note the duplicate definitions for left and right + * function keys; Sun keyboards and a few other manufactures have such + * function key groups on the left and/or right sides of the keyboard. + * We've not found a keyboard with more than 35 function keys total. + */ -//////////////////////////////////////////////////////////////////////////////// -// -void glutMouseMove( int xIn , int yIn ) -{ - if ( theApp ) - theApp->mouseMove( xIn, yIn ); + _keyMap[osgGA::GUIEventAdapter::KEY_F1] = nsIDOMKeyEvent::DOM_VK_F1; + _keyMap[osgGA::GUIEventAdapter::KEY_F2] = nsIDOMKeyEvent::DOM_VK_F2; + _keyMap[osgGA::GUIEventAdapter::KEY_F3] = nsIDOMKeyEvent::DOM_VK_F3; + _keyMap[osgGA::GUIEventAdapter::KEY_F4] = nsIDOMKeyEvent::DOM_VK_F4; + _keyMap[osgGA::GUIEventAdapter::KEY_F5] = nsIDOMKeyEvent::DOM_VK_F5; + _keyMap[osgGA::GUIEventAdapter::KEY_F6] = nsIDOMKeyEvent::DOM_VK_F6; + _keyMap[osgGA::GUIEventAdapter::KEY_F7] = nsIDOMKeyEvent::DOM_VK_F7; + _keyMap[osgGA::GUIEventAdapter::KEY_F8] = nsIDOMKeyEvent::DOM_VK_F8; + _keyMap[osgGA::GUIEventAdapter::KEY_F9] = nsIDOMKeyEvent::DOM_VK_F9; + _keyMap[osgGA::GUIEventAdapter::KEY_F10] = nsIDOMKeyEvent::DOM_VK_F10; + _keyMap[osgGA::GUIEventAdapter::KEY_F11] = nsIDOMKeyEvent::DOM_VK_F12; + _keyMap[osgGA::GUIEventAdapter::KEY_F12] = nsIDOMKeyEvent::DOM_VK_F13; + _keyMap[osgGA::GUIEventAdapter::KEY_F13] = nsIDOMKeyEvent::DOM_VK_F13; + _keyMap[osgGA::GUIEventAdapter::KEY_F14] = nsIDOMKeyEvent::DOM_VK_F14; + _keyMap[osgGA::GUIEventAdapter::KEY_F15] = nsIDOMKeyEvent::DOM_VK_F15; + _keyMap[osgGA::GUIEventAdapter::KEY_F16] = nsIDOMKeyEvent::DOM_VK_F16; + _keyMap[osgGA::GUIEventAdapter::KEY_F17] = nsIDOMKeyEvent::DOM_VK_F17; + _keyMap[osgGA::GUIEventAdapter::KEY_F18] = nsIDOMKeyEvent::DOM_VK_F18; + _keyMap[osgGA::GUIEventAdapter::KEY_F19] = nsIDOMKeyEvent::DOM_VK_F19; + _keyMap[osgGA::GUIEventAdapter::KEY_F20] = nsIDOMKeyEvent::DOM_VK_F20; + _keyMap[osgGA::GUIEventAdapter::KEY_F21] = nsIDOMKeyEvent::DOM_VK_F21; + _keyMap[osgGA::GUIEventAdapter::KEY_F22] = nsIDOMKeyEvent::DOM_VK_F22; + _keyMap[osgGA::GUIEventAdapter::KEY_F23] = nsIDOMKeyEvent::DOM_VK_F23; + _keyMap[osgGA::GUIEventAdapter::KEY_F24] = nsIDOMKeyEvent::DOM_VK_F24; + + + /* Modifiers */ + _keyMap[osgGA::GUIEventAdapter::KEY_Meta_L] = nsIDOMKeyEvent::DOM_VK_META; + _keyMap[osgGA::GUIEventAdapter::KEY_Meta_R] = nsIDOMKeyEvent::DOM_VK_META; + + _keyMap[osgGA::GUIEventAdapter::KEY_Control_L] = nsIDOMKeyEvent::DOM_VK_CONTROL; + _keyMap[osgGA::GUIEventAdapter::KEY_Control_R] = nsIDOMKeyEvent::DOM_VK_CONTROL; + _keyMap[osgGA::GUIEventAdapter::KEY_Shift_L] = nsIDOMKeyEvent::DOM_VK_SHIFT; + _keyMap[osgGA::GUIEventAdapter::KEY_Shift_R] = nsIDOMKeyEvent::DOM_VK_SHIFT; + _keyMap[osgGA::GUIEventAdapter::KEY_Alt_R] = nsIDOMKeyEvent::DOM_VK_ALT; + _keyMap[osgGA::GUIEventAdapter::KEY_Alt_L] = nsIDOMKeyEvent::DOM_VK_ALT; + + _keyMap[osgGA::GUIEventAdapter::KEY_Caps_Lock] = nsIDOMKeyEvent::DOM_VK_CAPS_LOCK; } -//////////////////////////////////////////////////////////////////////////////// -// -void glutMouseButton( int buttonIn, int stateIn, int xIn, int yIn ) +int UBrowserImage::convertToXULKey(int key) const { - if ( theApp ) - theApp->mouseButton( buttonIn, stateIn, xIn, yIn ); + KeyMap::const_iterator itr = _keyMap.find(key); + if (_keyMap.find(key)==_keyMap.end()) return key; + else return itr->second; + } -static void on_destroy(GtkWidget * widget, gpointer data) { - gtk_main_quit (); +osg::Node* createInteractiveQuad(const osg::Vec3& origin, osg::Vec3& widthAxis, osg::Vec3& heightAxis, + osg::Image* image) +{ + bool flip = image->getOrigin()==osg::Image::TOP_LEFT; -} + osg::Geometry* pictureQuad = osg::createTexturedQuadGeometry(origin, widthAxis, heightAxis, + 0.0f, flip ? 1.0f : 0.0f , 1.0f, flip ? 0.0f : 1.0f); + + osg::Texture2D* texture = new osg::Texture2D(image); + texture->setResizeNonPowerOfTwoHint(false); + texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR); + texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + + pictureQuad->getOrCreateStateSet()->setTextureAttributeAndModes(0, + texture, + osg::StateAttribute::ON); + + pictureQuad->setEventCallback(new osgViewer::InteractiveImageHandler(image)); + + osg::Geode* geode = new osg::Geode; + geode->addDrawable(pictureQuad); + + return geode; +} -//////////////////////////////////////////////////////////////////////////////// -// int main( int argc, char* argv[] ) { + osg::ArgumentParser arguments(&argc, argv); - // implementation in a class so we can observer events - // means we need this painful GLUT <--> class shim... - theApp = new testGL; + osgViewer::Viewer viewer(arguments); - if ( theApp ) - { - glutInit( &argc, argv ); - glutInitDisplayMode( GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB ); + typedef std::list< osg::ref_ptr > Images; + Images images; - glutInitWindowPosition( 80, 0 ); - glutInitWindowSize( theApp->getAppWindowWidth(), theApp->getAppWindowHeight() ); + for(int i=1; i browserImage= new UBrowserImage(arguments[0], 768, 1024); + browserImage->navigateTo(arguments[i]); + images.push_back(browserImage.get()); + } + } - glutCreateWindow( theApp->getAppWindowName().c_str() ); + bool xyPlane = false; - theApp->init( argv[ 0 ] ); + osg::Group* group = new osg::Group; - glutKeyboardFunc( glutKeyboard ); + osg::Vec3 origin = osg::Vec3(0.0f,0.0f,0.0f); + for(Images::iterator itr = images.begin(); + itr != images.end(); + ++itr) + { + osg::Image* image = itr->get(); + float width = 1.0; + float height = float(image->t())/float(image->s()); + + osg::Vec3 widthAxis = osg::Vec3(width,0.0f,0.0f); + osg::Vec3 heightAxis = xyPlane ? osg::Vec3(0.0f,height,0.0f) : osg::Vec3(0.0f,0.0f,height); + + group->addChild(createInteractiveQuad(origin, widthAxis, heightAxis, image)); + + origin += widthAxis*1.1f; + } + + viewer.setSceneData(group); - glutMouseFunc( glutMouseButton ); - glutPassiveMotionFunc( glutMouseMove ); - glutMotionFunc( glutMouseMove ); + viewer.addEventHandler(new osgViewer::StatsHandler); + + viewer.setCameraManipulator(new osgGA::TrackballManipulator()); - glutDisplayFunc( glutDisplay ); - glutReshapeFunc( glutReshape ); + viewer.realize(); + + while(!viewer.done()) + { - glutIdleFunc( glutIdle ); +#ifndef _WINDOWS + // pump the GTK+Gecko event queue for a (limited) while. this should + // be done so that the Gecko event queue doesn't starve, and done + // *here* so that mNeedsUpdate[] can be populated by callbacks + // from Gecko. + gtk_main_iteration_do(0); + for (int iter=0; iter<10; ++iter) + { + if (gtk_events_pending()) + gtk_main_iteration(); + } +#endif - glutMainLoop(); - delete theApp; - }; + for(Images::iterator itr = images.begin(); + itr != images.end(); + ++itr) + { + osg::ref_ptr browser = *(itr); + if (browser.valid()) + { + browser->update(); + } + } - return 0; + viewer.frame(); + } }