home *** CD-ROM | disk | FTP | other *** search
/ Chip 2006 June / CHIP 2006-06.2.iso / program / freeware / ubrowser.exe / ubrowser / ubrowser.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-02-21  |  33.0 KB  |  951 lines

  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. //  uBrowser - a program that illustrates one way of embedding the
  4. //  Mozilla Gecko (tm) Rendering Engine in an application, grabbing the
  5. //  rendered output and displaying it on the surface of a 3D polygon as
  6. //  texture in an OpenGL (tm) application.
  7. //
  8. //  uBrowser is free software; you can redistribute it and/or modify
  9. //  it under the terms of the GNU General Public License as published by
  10. //  the Free Software Foundation; either version 2 of the License, or
  11. //  (at your option) any later version.
  12. //
  13. //  uBrowser is distributed in the hope that it will be useful,
  14. //  but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. //  GNU General Public License for more details.
  17. //
  18. //  You should have received a copy of the GNU General Public License
  19. //  along with uBrowser; if not, write to the Free Software
  20. //  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  21. //
  22. //  Original code:  Copyright 2005 Linden Research Inc.
  23. //                  http://www.lindenlab.com
  24. //
  25. //  Primary author and site maintainer: Callum Prentice (callum@ubrowser.com)
  26. //
  27. //  See contributors.txt or http://ubrowser.com for a list of contributors
  28. //  without whose generous donation of time and effort, this application
  29. //  would not have been possible.
  30. //
  31. ////////////////////////////////////////////////////////////////////////////////
  32. #include "ubrowser.h"
  33.  
  34. #ifdef _WINDOWS
  35. #include <windows.h>
  36. #endif
  37.  
  38. #include <iostream>
  39. #include <sstream>
  40. #include <time.h>
  41.  
  42. // connects GLUI callbacks to the app class
  43. uBrowser* gInstance = 0;
  44.  
  45. ////////////////////////////////////////////////////////////////////////////////
  46. //
  47. uBrowser::uBrowser() :
  48.     mName( "uBrowser - version 1.0.4" ),
  49.     mBrowserWindowWidth( 800 ),
  50.     mBrowserWindowHeight( 800 ),
  51.     mTextureWidth( 0 ),
  52.     mTextureHeight( 0 ),
  53.     mTextureScaleX( 0.0f ),
  54.     mTextureScaleY( 0.0f ),
  55.     mViewportAspect( 0.0f ),
  56.     mIdReset( 0x0010 ),
  57.     mIdBookmarks( 0x0011 ),
  58.     mIdExit( 0x0012 ),
  59.     mIdTypeNull( 0x0013 ),
  60.     mIdTypeFlat( 0x0014 ),
  61.     mIdTypeBall( 0x0015 ),
  62.     mIdTypeCube( 0x0016 ),
  63.     mIdTypeFlag( 0x0017 ),
  64.     mIdUrlEdit( 0x0018 ),
  65.     mIdNavBack( 0x0019 ),
  66.     mIdNavStop( 0x001a ),
  67.     mIdNavHome( 0x001b ),
  68.     mIdNavForward( 0x001c ),
  69.     mIdBrowserSmall( 0x001d ),
  70.     mIdBrowserMedium( 0x001e ),
  71.     mIdBrowserLarge( 0x001f ),
  72.     mFocusUrlEdit( 0x0020 ),
  73.     mStatusText( 0 ),
  74.     mProgressText( 0 ),
  75.     mHomeUrl( "http://www.secondlife.com" )
  76. {
  77.     // use this to connect GLUI callbacks to this class
  78.     gInstance = this;
  79.  
  80.     // list of bookmarks that demonstrate cool stuff!
  81.     mBookmarks.push_back( std::pair< std::string, std::string >( "Select a bookmark", "" ) );
  82.     mBookmarks.push_back( std::pair< std::string, std::string >( "Second Life Home Page", "http://www.secondlife.com" ) );
  83.     mBookmarks.push_back( std::pair< std::string, std::string >( "Mozilla Home Page", "http://www.mozilla.org" ) );
  84.     mBookmarks.push_back( std::pair< std::string, std::string >( "Google Home", "http://www.google.com" ) );
  85.     mBookmarks.push_back( std::pair< std::string, std::string >( "Google Maps", "http://maps.google.com" ) );
  86.     mBookmarks.push_back( std::pair< std::string, std::string >( "Boing Boing", "http://www.boingboing.net" ) );
  87.     mBookmarks.push_back( std::pair< std::string, std::string >( "Digg", "http://www.digg.com" ) );
  88.     mBookmarks.push_back( std::pair< std::string, std::string >( "Yahoo! User Interface Library slider", "http://developer.yahoo.net/yui/slider/examples/slider.html" ) );
  89.     mBookmarks.push_back( std::pair< std::string, std::string >( "Canvascape", "http://www.abrahamjoffe.com.au/ben/canvascape/" ) );
  90.     mBookmarks.push_back( std::pair< std::string, std::string >( "SVG Tetris (arrow keys and spacebar)", "http://www.croczilla.com/svg/samples/svgtetris/svgtetris.svg" ) );
  91.     mBookmarks.push_back( std::pair< std::string, std::string >( "SVG Opacity & Hover", "http://www.croczilla.com/svg/samples/opacity1/opacity1.xml" ) );
  92.     mBookmarks.push_back( std::pair< std::string, std::string >( "SVG Interactive lines", "http://www.croczilla.com/svg/samples/xbl-shapes2/xbl-shapes2.xml" ) );
  93.     mBookmarks.push_back( std::pair< std::string, std::string >( "SVG Interactive shapes", "http://www.croczilla.com/svg/samples/xbl1/xbl1.xml" ) );
  94.     mBookmarks.push_back( std::pair< std::string, std::string >( "XUL SQL Viewer", "http://www.georgenava.com/xul/dineros/dineros.php" ) );
  95.     mBookmarks.push_back( std::pair< std::string, std::string >( "XUL Email App", "http://www.georgenava.com/xul/gmail/gmail.php" ) );
  96.     mBookmarks.push_back( std::pair< std::string, std::string >( "XUL Outliner App", "http://www.georgenava.com/xul/outliner/outliner.php" ) );
  97.     mBookmarks.push_back( std::pair< std::string, std::string >( "XUL Video Poker", "http://www.georgenava.com/xul/poker/videopoker.php" ) );
  98.     mBookmarks.push_back( std::pair< std::string, std::string >( "XUL Visual Designer Studio", "http://www.georgenava.com/xul/studio/visualdesigner.php" ) );
  99.     mBookmarks.push_back( std::pair< std::string, std::string >( "XUL Photo Viewer", "http://www.georgenava.com/xul/photo/photoviewer.php" ) );
  100.     mBookmarks.push_back( std::pair< std::string, std::string >( "XUL Widgets", "http://www.hevanet.com/acorbin/xul/top.xul" ) );
  101.     mBookmarks.push_back( std::pair< std::string, std::string >( "XUL Mozilla Amazon Browser (MAB)", "http://www.faser.net/mab/chrome/content/mab.xul" ) );
  102.     mBookmarks.push_back( std::pair< std::string, std::string >( "DHTML Lemmings!", "http://www.funnygames.nl/host/games/lemmings/" ) );
  103.     mBookmarks.push_back( std::pair< std::string, std::string >( "DHTML Demos", "http://www.dhteumeuleu.com/" ) );
  104.     mBookmarks.push_back( std::pair< std::string, std::string >( "about:config", "about:config" ) );
  105. }
  106.  
  107. ////////////////////////////////////////////////////////////////////////////////
  108. //
  109. uBrowser::~uBrowser()
  110. {
  111.     // clean up - don't generally get here since we quit from a GLUT app with exit..!!
  112.     if ( mEmbeddedBrowser )
  113.     {
  114.         mEmbeddedBrowser->getBrowserWindow()->remObserver( this );
  115.         delete mEmbeddedBrowser;
  116.     };
  117. }
  118.  
  119. ////////////////////////////////////////////////////////////////////////////////
  120. //
  121. bool uBrowser::init( const char* arg0, int appWindowIn )
  122. {
  123.     // save the GLUT window handle since we need to reset it sometimes.
  124.     // (GLUT/GLUI dependency)
  125.     mAppWindow = appWindowIn;
  126.  
  127.     // build GUI
  128.     makeChrome();
  129.  
  130.     glClearColor( 0.0f, 0.0f, 0.0f, 0.5f );
  131.     glClearDepth( 1.0f );
  132.     glEnable( GL_DEPTH_TEST );
  133.     glDepthFunc( GL_LEQUAL );
  134.     glEnable( GL_TEXTURE_2D );
  135.  
  136.     // create the red/blue texture used in picking
  137.     glGenTextures( 1, &mRedBlueTexture );
  138.     for( int y = 0; y < 256; ++y )
  139.     {
  140.         for( int x = 0; x < 256 * 3 ; x += 3 )
  141.         {
  142.             mRedBlueTexturePixels[ y * 256 * 3 + x + 0 ] = ( x / 3 );
  143.             mRedBlueTexturePixels[ y * 256 * 3 + x + 1 ] = 0;
  144.             mRedBlueTexturePixels[ y * 256 * 3 + x + 2 ] = y;
  145.         };
  146.     }
  147.     glBindTexture( GL_TEXTURE_2D, mRedBlueTexture );
  148.     glTexImage2D( GL_TEXTURE_2D, 0,
  149.         GL_RGB,
  150.             256, 256,
  151.                 0, GL_RGB, GL_UNSIGNED_BYTE, mRedBlueTexturePixels );
  152.  
  153.     // create the green texture used in picking
  154.     glGenTextures( 1, &mGreenTexture );
  155.     for( int i = 0; i < 16 * 16 * 3; i += 3 )
  156.     {
  157.         mGreenTexturePixels[ i + 0 ] = 0;
  158.         mGreenTexturePixels[ i + 1 ] = ( unsigned char )( i / 3 );
  159.         mGreenTexturePixels[ i + 2 ] = 0;
  160.     }
  161.     glBindTexture( GL_TEXTURE_2D, mGreenTexture );
  162.     glTexImage2D( GL_TEXTURE_2D, 0,
  163.         GL_RGB,
  164.             16, 16,
  165.                 0, GL_RGB, GL_UNSIGNED_BYTE, mGreenTexturePixels );
  166.  
  167.     // create the texture used to display the browser data
  168.     glGenTextures( 1, &mAppTexture );
  169.     glBindTexture( GL_TEXTURE_2D, mAppTexture );
  170.     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  171.     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  172.     glTexImage2D( GL_TEXTURE_2D, 0,
  173.         GL_RGB,
  174.             mTextureWidth, mTextureHeight,
  175.                 0, GL_RGB, GL_UNSIGNED_BYTE, 0 );
  176.  
  177.     resetView();
  178.  
  179.     // start with the flat rectangle so we don't freak people out :)
  180.     mCurObjType = mIdTypeFlat;
  181.  
  182.     // make and initialise the embedded browser
  183.     mEmbeddedBrowser = new embeddedBrowser;
  184.     if ( mEmbeddedBrowser )
  185.     {
  186.         // need a native window handle
  187.         void* nativeWindow = getNativeWindowHandle();
  188.  
  189.         // in the example, pass in the value of argv[ 0 ] as the base dir
  190.         std::string appBaseDir = std::string( arg0 ).substr( 0, std::string( arg0 ).find_last_of("\\/") );
  191.  
  192.         if ( mEmbeddedBrowser->init( appBaseDir, mBrowserWindowWidth, mBrowserWindowHeight ) )
  193.         {
  194.             mEmbeddedBrowser->createWindow( nativeWindow );
  195.  
  196.             // observer events on it like status text changes and progress
  197.             if ( mEmbeddedBrowser->getBrowserWindow() )
  198.                 mEmbeddedBrowser->getBrowserWindow()->addObserver( this );
  199.  
  200.             setSize( mBrowserWindowWidth, mBrowserWindowHeight );
  201.  
  202.             mEmbeddedBrowser->navigateTo( mHomeUrl.c_str() );
  203.         }
  204.         else
  205.         {
  206.             return false;
  207.         };
  208.     }
  209.     else
  210.     {
  211.         return false;
  212.     };
  213.  
  214.     return true;
  215. }
  216.  
  217. ////////////////////////////////////////////////////////////////////////////////
  218. //
  219. bool uBrowser::reset()
  220. {
  221.     return true;
  222. }
  223.  
  224. ////////////////////////////////////////////////////////////////////////////////
  225. //
  226. void uBrowser::reshape( int widthIn, int heightIn )
  227. {
  228.     // save these as we'll need them later
  229.     mWindowWidth = widthIn;
  230.     mWindowHeight = heightIn;
  231.  
  232.     // just a rough calculation
  233.     mUrlEdit->set_w( mWindowWidth - 400 );
  234.     mStatusText->set_w( mWindowWidth - 100 );
  235.  
  236.     // update viewport (the active window inside the chrome stuff)
  237.     int viewportX, viewportY;
  238.     int viewportHeight, viewportWidth;
  239.     GLUI_Master.get_viewport_area( &viewportX, &viewportY, &viewportWidth, &viewportHeight );
  240.     glViewport( viewportX, viewportY, viewportWidth, viewportHeight );
  241.  
  242.     // need this when we come to display
  243.     mViewportAspect = ( float )( viewportWidth )  / ( float)( viewportHeight );
  244.  
  245.     // GLUI requires this
  246.     if ( glutGetWindow() != mAppWindow )
  247.         glutSetWindow( mAppWindow );
  248.  
  249.     // trigger re-display
  250.     glutPostRedisplay();
  251. };
  252.  
  253. ////////////////////////////////////////////////////////////////////////////////
  254. //
  255. void uBrowser::drawGeometry( int typeIn )
  256. {
  257.     // plain old flat rectangle
  258.     if ( typeIn == mIdTypeFlat )
  259.     {
  260.         glColor3f( 1.0f, 1.0f, 1.0f );
  261.         glBegin( GL_QUADS );
  262.             glTexCoord2f( 0.0f, 0.0f ); glVertex3f( -1.0f, -1.0f,  0.0f );
  263.             glTexCoord2f( 1.0f, 0.0f ); glVertex3f(  1.0f, -1.0f,  0.0f );
  264.             glTexCoord2f( 1.0f, 1.0f ); glVertex3f(  1.0f,  1.0f,  0.0f );
  265.             glTexCoord2f( 0.0f, 1.0f ); glVertex3f( -1.0f,  1.0f,  0.0f );
  266.         glEnd();
  267.     }
  268.     else
  269.     // a ball - just because you can :) draw my own ball since the glu/glut ones don't get me
  270.     // enough control over the texture coordinate details
  271.     if ( typeIn == mIdTypeBall )
  272.     {
  273.         // this is based on some code from here: http://astronomy.swin.edu.au/~pbourke/opengl/sphere/
  274.         const int numElems = 40;
  275.         const GLfloat  piDiv2 = 1.57079632679489661923f;
  276.         const GLfloat piMul2 = 6.28318530717958647692f;
  277.  
  278.         for( int j = 0; j < numElems / 2; ++j )
  279.         {
  280.             GLfloat theta1 = j * ( piMul2 ) / numElems - piDiv2;
  281.             GLfloat theta2 = ( j + 1 ) * ( piMul2 ) / numElems - piDiv2;
  282.  
  283.             glBegin( GL_TRIANGLE_STRIP );
  284.  
  285.             for( int i = 0; i <= numElems; i++ )
  286.             {
  287.                 GLfloat theta3 = i * piMul2 / numElems;
  288.  
  289.                 GLfloat pointX = cos( theta2 ) * cos( theta3 );
  290.                 GLfloat pointY = sin( theta2 );
  291.                 GLfloat pointZ = cos( theta2 ) * sin( theta3 );
  292.  
  293.                 glNormal3f( pointX, pointY, pointZ );
  294.                 glTexCoord2f( i / ( GLfloat )numElems, 2 * ( j + 1 ) / ( GLfloat )numElems );
  295.                 glVertex3f( pointX, pointY, pointZ );
  296.  
  297.                 pointX = cos( theta1 ) * cos( theta3 );
  298.                 pointY = sin( theta1 );
  299.                 pointZ = cos( theta1 ) * sin( theta3 );
  300.  
  301.                 glNormal3f( pointX, pointY, pointZ );
  302.                 glTexCoord2f( i / ( GLfloat )numElems, 2 * j / ( GLfloat )numElems);
  303.                 glVertex3f( pointX, pointY, pointZ );
  304.             };
  305.             glEnd();
  306.         };
  307.     }
  308.     else
  309.     // same browser on all six faces - of course, what really should happen is one on each face
  310.     // but that's for later
  311.     if ( typeIn == mIdTypeCube )
  312.     {
  313.         const GLfloat delta = 0.75f;
  314.  
  315.         glColor3f( 1.0f, 1.0f, 1.0f );
  316.         glBegin( GL_QUADS );
  317.             glTexCoord2f( 0.0f, 0.0f ); glVertex3f( -delta, -delta,  -delta );
  318.             glTexCoord2f( 1.0f, 0.0f ); glVertex3f(  delta, -delta,  -delta );
  319.             glTexCoord2f( 1.0f, 1.0f ); glVertex3f(  delta,  delta,  -delta );
  320.             glTexCoord2f( 0.0f, 1.0f ); glVertex3f( -delta,  delta,  -delta );
  321.  
  322.             glTexCoord2f( 0.0f, 0.0f ); glVertex3f( -delta, -delta,  delta );
  323.             glTexCoord2f( 0.0f, 1.0f ); glVertex3f(  delta, -delta,  delta );
  324.             glTexCoord2f( 1.0f, 1.0f ); glVertex3f(  delta,  delta,  delta );
  325.             glTexCoord2f( 1.0f, 0.0f ); glVertex3f( -delta,  delta,  delta );
  326.  
  327.             glTexCoord2f( 0.0f, 0.0f ); glVertex3f( -delta,  -delta, -delta );
  328.             glTexCoord2f( 1.0f, 0.0f ); glVertex3f( -delta,  -delta,  delta );
  329.             glTexCoord2f( 1.0f, 1.0f ); glVertex3f(  delta,  -delta,  delta );
  330.             glTexCoord2f( 0.0f, 1.0f ); glVertex3f(  delta,  -delta, -delta );
  331.  
  332.             glTexCoord2f( 0.0f, 0.0f ); glVertex3f( -delta,  delta, -delta );
  333.             glTexCoord2f( 0.0f, 1.0f ); glVertex3f( -delta,  delta,  delta );
  334.             glTexCoord2f( 1.0f, 1.0f ); glVertex3f(  delta,  delta,  delta );
  335.             glTexCoord2f( 1.0f, 0.0f ); glVertex3f(  delta,  delta, -delta );
  336.  
  337.             glTexCoord2f( 0.0f, 0.0f ); glVertex3f( -delta, -delta, -delta );
  338.             glTexCoord2f( 1.0f, 0.0f ); glVertex3f( -delta,  delta, -delta );
  339.             glTexCoord2f( 1.0f, 1.0f ); glVertex3f( -delta,  delta,  delta );
  340.             glTexCoord2f( 0.0f, 1.0f ); glVertex3f( -delta, -delta,  delta );
  341.  
  342.             glTexCoord2f( 0.0f, 0.0f ); glVertex3f( delta, -delta, -delta );
  343.             glTexCoord2f( 0.0f, 1.0f ); glVertex3f( delta,  delta, -delta );
  344.             glTexCoord2f( 1.0f, 1.0f ); glVertex3f( delta,  delta,  delta );
  345.             glTexCoord2f( 1.0f, 0.0f ); glVertex3f( delta, -delta,  delta );
  346.         glEnd();
  347.     }
  348.     else
  349.     // waving flag - again - not useful but it looks great..
  350.     if ( typeIn == mIdTypeFlag )
  351.     {
  352.         // this is based on some code from here: http://nehe.gamedev.net
  353.         const int resolution = 45;
  354.         static GLfloat points[ resolution ][ resolution ][ 3 ];
  355.         static int wiggle = 0;
  356.         static bool init = false;
  357.  
  358.         if ( ! init )
  359.         {
  360.             for( int x = 0; x < resolution; x++ )
  361.             {
  362.                 for( int y = 0; y < resolution; y++ )
  363.                 {
  364.                     points[ x ][ y ][ 0 ] = ( GLfloat )( ( x / ( ( GLfloat )( resolution ) / 2.0f ) ) - 1.0f );
  365.                     points[ x ][ y ][ 1 ] = ( GLfloat )( ( y / ( ( GLfloat )( resolution ) / 2.0f ) ) - 1.0f );
  366.                     points[ x ][ y ][ 2 ] = ( GLfloat )( cos ( ( ( ( ( x + y ) / 5.0f ) * 40.0f ) / 360.0f ) * 3.141592654 * 2.0f ) * 0.1f );
  367.                 };
  368.             };
  369.             init = true;
  370.         };
  371.  
  372.         glColor3f( 1.0f, 1.0f, 1.0f );
  373.         glBegin( GL_QUADS );
  374.         for( int x = 0; x < resolution - 1; x++ )
  375.         {
  376.             for( int y = resolution - 2; y > -1; --y )
  377.             {
  378.                 int xCoord1 = x;
  379.                 int yCoord1 = y;
  380.  
  381.                 int xCoord2 = x;
  382.                 int yCoord2 = y + 1;
  383.  
  384.                 int xCoord3 = x + 1;
  385.                 int yCoord3 = y + 1;
  386.  
  387.                 int xCoord4 = x + 1;
  388.                 int yCoord4 = y;
  389.  
  390.                 glTexCoord2f( ( GLfloat )( xCoord1 ) / ( GLfloat )( resolution - 1 ),
  391.                     ( GLfloat )( yCoord1 ) / ( GLfloat )( resolution - 1 ) );
  392.                 glVertex3f( points[ xCoord1 ][ yCoord1 ][ 0 ], points[ xCoord1 ][ yCoord1 ][ 1 ], points[ xCoord1 ][ yCoord1 ][ 2 ] );
  393.  
  394.                 glTexCoord2f( ( GLfloat )( xCoord2 ) / ( GLfloat )( resolution - 1 ),
  395.                     ( GLfloat )( yCoord2 ) / ( GLfloat )( resolution - 1 ) );
  396.                 glVertex3f( points[ xCoord2 ][ yCoord2 ][ 0 ], points[ xCoord2 ][ yCoord2 ][ 1 ], points[ xCoord2 ][ yCoord2 ][ 2 ] );
  397.  
  398.                 glTexCoord2f( ( GLfloat )( xCoord3 ) / ( GLfloat )( resolution - 1 ),
  399.                     ( GLfloat )( yCoord3 ) / ( GLfloat )( resolution - 1 ) );
  400.                 glVertex3f( points[ xCoord3 ][ yCoord3 ][ 0 ], points[ xCoord3 ][ yCoord3 ][ 1 ], points[ xCoord3 ][ yCoord3 ][ 2 ] );
  401.  
  402.                 glTexCoord2f( ( GLfloat )( xCoord4 ) / ( GLfloat )( resolution - 1 ),
  403.                     ( GLfloat )( yCoord4 ) / ( GLfloat )( resolution - 1 ) );
  404.                 glVertex3f( points[ xCoord4 ][ yCoord4 ][ 0 ], points[ xCoord4 ][ yCoord4 ][ 1 ], points[ xCoord4 ][ yCoord4 ][ 2 ] );
  405.             };
  406.         };
  407.         glEnd();
  408.  
  409.         if ( ++wiggle == 3 )
  410.         {
  411.             for( int y = 0; y < resolution; ++y )
  412.             {
  413.                 GLfloat swap = points[ 0 ][ y ][ 2 ];
  414.                 for( int x = 0; x < ( resolution - 1 ); ++x )
  415.                 {
  416.                     points[ x ][ y ][ 2 ] = points[ x + 1 ][ y ][ 2 ];
  417.                 };
  418.                 points[ resolution - 1 ][ y ][ 2 ] =swap;
  419.             };
  420.             wiggle = 0;
  421.         };
  422.     };
  423. }
  424.  
  425. ////////////////////////////////////////////////////////////////////////////////
  426. //
  427. void uBrowser::display()
  428. {
  429.     // let's start with a clean slate
  430.     glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
  431.     glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
  432.  
  433.     // scale all texture so that they fit the geometry exactly
  434.     glMatrixMode( GL_TEXTURE );
  435.     glPushMatrix();
  436.     glScalef( mTextureScaleX, mTextureScaleY, 1.0f );
  437.  
  438.     // set up OpenGL view
  439.     glMatrixMode( GL_PROJECTION );
  440.     glLoadIdentity();
  441.     glFrustum( -mViewportAspect * 0.04f, mViewportAspect * 0.04f, -0.04f, 0.04f, 0.1f, 50.0f );
  442.     glMatrixMode( GL_MODELVIEW );
  443.     glLoadIdentity();
  444.     glTranslatef( 0.0, 0.0, -3.0f );
  445.     glTranslatef( mViewPos[ 0 ], mViewPos[ 1 ], -mViewPos[ 2 ] );
  446.     glMultMatrixf( mViewRotation );
  447.     glRotatef( 180.0f, 1.0f, 0.0f, 0.0f );
  448.     glScalef( 1.0f, 1.0f, 1.0f );
  449.  
  450.     // red blue pattern
  451.     glBindTexture( GL_TEXTURE_2D, mRedBlueTexture );
  452.     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
  453.     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
  454.     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
  455.     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
  456.     drawGeometry( mCurObjType );
  457.  
  458.     // read colors and get red/blue value
  459.     glReadPixels( mCurMouseX, mCurMouseY, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, mPixelColorRB );
  460.  
  461.     // green texture mask
  462.     glBindTexture( GL_TEXTURE_2D, mGreenTexture );
  463.     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
  464.     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
  465.     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
  466.     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
  467.     glMatrixMode( GL_TEXTURE );
  468.     glPushMatrix();
  469.     glScalef( mTextureScaleX * 256.0f, mTextureScaleX * 256.0f, 1.0f );   // scale the scale by the scale :)
  470.     drawGeometry( mCurObjType );
  471.     glPopMatrix();
  472.     glMatrixMode( GL_MODELVIEW );
  473.  
  474.     // read colors and get green value
  475.     glReadPixels( mCurMouseX, mCurMouseY, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, mPixelColorG );
  476.  
  477.     // draw the browser texture
  478.     glBindTexture( GL_TEXTURE_2D, mAppTexture );
  479.  
  480.     if ( mEmbeddedBrowser )
  481.     {
  482.         if ( mEmbeddedBrowser->getPageBuffer() )
  483.         {
  484.             glTexSubImage2D( GL_TEXTURE_2D, 0,
  485.                 0, 0,
  486.                     // because sometimes the rowspan != width * bytes per pixel (mBrowserWindowWidth)
  487.                     mEmbeddedBrowser->getBrowserRowSpan() / mEmbeddedBrowser->getBrowserDepth(),
  488.                         mBrowserWindowHeight,
  489.                             mEmbeddedBrowser->getBrowserDepth() == 3 ? GL_BGR_EXT : GL_BGRA_EXT,
  490.                                 GL_UNSIGNED_BYTE,
  491.                                     mEmbeddedBrowser->getPageBuffer() );
  492.         };
  493.     };
  494.     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  495.     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  496.     drawGeometry( mCurObjType );
  497.  
  498.     // restore matrix after texture scale
  499.     glMatrixMode( GL_TEXTURE );
  500.     glPopMatrix();
  501.  
  502.     glutSwapBuffers();
  503. }
  504.  
  505. ////////////////////////////////////////////////////////////////////////////////
  506. //
  507. void uBrowser::idle()
  508. {
  509.     // use this to throttle updates
  510.     clock_t currentTime = clock();
  511.     static clock_t startTime = currentTime;
  512.  
  513.     // time to update page
  514.     if ( ( currentTime - startTime ) > ( CLOCKS_PER_SEC / 50 ) )
  515.     {
  516.         // grab the contents of the rendered page
  517.         mEmbeddedBrowser->grabWindow();
  518.  
  519.         // enable/disable back button depending on whether we can go back or not
  520.         if ( mEmbeddedBrowser->canNavigateBack() )
  521.             mNavBackButton->enable();
  522.         else
  523.             mNavBackButton->disable();
  524.  
  525.         // enable/disable back button depending on whether we can go back or not
  526.         if ( mEmbeddedBrowser->canNavigateForward() )
  527.             mNavForwardButton->enable();
  528.         else
  529.             mNavForwardButton->disable();
  530.  
  531.         // reset timer
  532.         startTime = currentTime;
  533.     };
  534.  
  535.     // GLUI needs this
  536.     if ( glutGetWindow() != mAppWindow )
  537.         glutSetWindow( mAppWindow );
  538.  
  539.     // lots of updates for smooth motion
  540.     glutPostRedisplay();
  541. }
  542.  
  543. ////////////////////////////////////////////////////////////////////////////////
  544. //
  545. void uBrowser::resetView()
  546. {
  547.     mViewRotationCtrl->reset();
  548.  
  549.     mViewScaleCtrl->set_x( 0.0f );
  550.     mViewScaleCtrl->set_y( 0.0f );
  551.     mViewScaleCtrl->set_z( 0.0f );
  552.  
  553.     mViewTranslationCtrl->set_x( 0.0f );
  554.     mViewTranslationCtrl->set_y( 0.0f );
  555.     mViewTranslationCtrl->set_z( 0.0f );
  556. }
  557.  
  558. ////////////////////////////////////////////////////////////////////////////////
  559. //
  560. void uBrowser::makeChrome()
  561. {
  562.     // top UI bar
  563.     mTopGLUIWindow = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_TOP );
  564.  
  565.     mNavBackButton = mTopGLUIWindow->add_button( "<<<", mIdNavBack, gluiCallbackWrapper );
  566.     mNavBackButton->set_w( 56 );
  567.  
  568.     mTopGLUIWindow->add_column( false );
  569.     GLUI_Button* button = mTopGLUIWindow->add_button( "STOP", mIdNavStop, gluiCallbackWrapper );
  570.     button->set_w( 56 );
  571.  
  572.     mTopGLUIWindow->add_column( false );
  573.     button = mTopGLUIWindow->add_button( "HOME", mIdNavHome, gluiCallbackWrapper );
  574.     button->set_w( 56 );
  575.  
  576.     mTopGLUIWindow->add_column( false );
  577.     mNavForwardButton = mTopGLUIWindow->add_button( ">>>", mIdNavForward, gluiCallbackWrapper );
  578.     mNavForwardButton->set_w( 56 );
  579.  
  580.     mTopGLUIWindow->add_column( false );
  581.     mUrlEdit = mTopGLUIWindow->add_edittext( "Url:", GLUI_EDITTEXT_TEXT, mNavUrl, mIdUrlEdit, gluiCallbackWrapper );
  582.  
  583.     mTopGLUIWindow->add_column( false );
  584.     mTopGLUIWindow->add_button( "Focus", mFocusUrlEdit, gluiCallbackWrapper );
  585.  
  586.     mTopGLUIWindow->set_main_gfx_window( mAppWindow );
  587.  
  588.     // top UI bar (second part)
  589.     mTop2GLUIWindow = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_TOP );
  590.  
  591.     mTop2GLUIWindow->add_column( false );
  592.     GLUI_Listbox* bookmarkList = mTop2GLUIWindow->add_listbox( "Bookmarks", &mSelBookmark, mIdBookmarks, gluiCallbackWrapper );
  593.     for( unsigned int each = 0; each < mBookmarks.size(); ++each )
  594.     {
  595.         bookmarkList->add_item( each, const_cast< char* >( mBookmarks[ each ].first.c_str() ) );
  596.     };
  597.     mTop2GLUIWindow->set_main_gfx_window( mAppWindow );
  598.  
  599.     // bottom UI bar
  600.     mBottomGLUIWindow = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_BOTTOM );
  601.  
  602.     mStatusText = mBottomGLUIWindow->add_statictext( "" );
  603.  
  604.     mBottomGLUIWindow->add_column( false );
  605.     mProgressText = mBottomGLUIWindow->add_statictext( "" );
  606.     mProgressText->set_alignment( GLUI_ALIGN_RIGHT );
  607.  
  608.     mBottomGLUIWindow->set_main_gfx_window( mAppWindow );
  609.  
  610.     // right side UI bar
  611.     mRightGLUIWindow = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_RIGHT );
  612.  
  613.     GLUI_Listbox* objTypelist = mRightGLUIWindow->add_listbox( "Type", &mCurObjType );
  614.     objTypelist->add_item( mIdTypeFlat, "Flat" );
  615.     objTypelist->add_item( mIdTypeCube, "Cube" );
  616.     objTypelist->add_item( mIdTypeBall, "Ball" );
  617.     objTypelist->add_item( mIdTypeFlag, "Flag" );
  618.     mRightGLUIWindow->add_statictext( "" );
  619.  
  620.     mViewRotationCtrl = mRightGLUIWindow->add_rotation( "Rotation", mViewRotation );
  621.  
  622.     mViewTranslationCtrl = mRightGLUIWindow->add_translation( "Translate", GLUI_TRANSLATION_XY, mViewPos );
  623.     mViewTranslationCtrl->set_speed( 0.01f );
  624.  
  625.     mViewScaleCtrl = mRightGLUIWindow->add_translation( "Scale", GLUI_TRANSLATION_Z, &mViewPos[ 2 ] );
  626.     mViewScaleCtrl->set_speed( 0.05f );
  627.  
  628.     mRightGLUIWindow->add_statictext( "" );
  629.  
  630.     mRightGLUIWindow->add_statictext( "" );
  631.     button = mRightGLUIWindow->add_button( "Small", mIdBrowserSmall, gluiCallbackWrapper );
  632.     button->set_w( 64 );
  633.  
  634.     button = mRightGLUIWindow->add_button( "Medium", mIdBrowserMedium, gluiCallbackWrapper );
  635.     button->set_w( 64 );
  636.  
  637.     button = mRightGLUIWindow->add_button( "Large", mIdBrowserLarge, gluiCallbackWrapper );
  638.     button->set_w( 64 );
  639.  
  640.     GLUI_StaticText* text = mRightGLUIWindow->add_statictext( "Browser window size" );
  641.     text->set_alignment( GLUI_ALIGN_CENTER );
  642.     mRightGLUIWindow->add_statictext( "" );
  643.  
  644.     mRightGLUIWindow->add_statictext( "" );
  645.     button = mRightGLUIWindow->add_button( "Reset", mIdReset, gluiCallbackWrapper );
  646.     button->set_w( 64 );
  647.  
  648.     mRightGLUIWindow->add_statictext( "" );
  649.     button = mRightGLUIWindow->add_button( "Exit", mIdExit, gluiCallbackWrapper );
  650.     button->set_w( 64 );
  651.  
  652.     mRightGLUIWindow->set_main_gfx_window( mAppWindow );
  653. }
  654.  
  655. ////////////////////////////////////////////////////////////////////////////////
  656. //
  657. void uBrowser::windowPosToTexturePos( int winXIn, int winYIn, int& texXOut, int& texYOut )
  658. {
  659.     // this is how we convert from the color in the textures draw in the first 2 passes to an
  660.     // XY location in the coordinate space of the texture
  661.     mCurMouseX = winXIn;
  662.     mCurMouseY = mWindowHeight - winYIn;    // opposite Ycoordinate systems..
  663.  
  664.     // red gives 0..255 on X and blue value gives 0.255 on Y
  665.     // green divides each distrete value by 16 giving 256 * 16 (4096) resolution in each of X & Y
  666.     texXOut = ( mPixelColorRB[ 0 ] * 16 + ( mPixelColorG[ 1 ] & 0x0f ) ) / ( 4096 / mTextureWidth );
  667.     texYOut = ( mPixelColorRB[ 2 ] * 16 + ( mPixelColorG[ 1 ] >> 4 ) ) / ( 4096 / mTextureHeight  );
  668. }
  669.  
  670. ////////////////////////////////////////////////////////////////////////////////
  671. //
  672. void uBrowser::keyboard( unsigned char keyIn, int xIn, int yIn )
  673. {
  674.     // pass on the keypress to Mozilla - will need something more sophisticated here one day
  675.     if ( mEmbeddedBrowser )
  676.         mEmbeddedBrowser->keyPress( keyIn );
  677. };
  678.  
  679. ////////////////////////////////////////////////////////////////////////////////
  680. //
  681. void uBrowser::passiveMouse( int xIn, int yIn )
  682. {
  683.     // called when the mouse is moving and button isn't pressed
  684.     int x, y;
  685.     windowPosToTexturePos( xIn, yIn, x, y );
  686.  
  687.     if ( mEmbeddedBrowser )
  688.         mEmbeddedBrowser->mouseMove( x, y );
  689. }
  690.  
  691. ////////////////////////////////////////////////////////////////////////////////
  692. //
  693. void uBrowser::mouseButton( int button, int state, int xIn, int yIn )
  694. {
  695.     int x, y;
  696.     windowPosToTexturePos( xIn, yIn, x, y );
  697.  
  698.     if ( button == GLUT_LEFT_BUTTON )
  699.     {
  700.         if ( state == GLUT_DOWN )
  701.         {
  702.             // send event to mozilla
  703.             mEmbeddedBrowser->mouseDown( x, y );
  704.         }
  705.         else
  706.         if ( state == GLUT_UP )
  707.         {
  708.             // send event to mozilla
  709.             mEmbeddedBrowser->mouseUp( x, y );
  710.  
  711.             // this seems better than sending focus on mouse down (still need to improve this)
  712.             mEmbeddedBrowser->mouseUp( x, y );
  713.             mEmbeddedBrowser->focusBrowser( true );
  714.  
  715.             // turn off the URL edit widget so it's "obvious" that you need to press focus to reenable it.
  716.             // (focus restriction in GLUI i wasn't able to work around)
  717.             mUrlEdit->disable();
  718.         };
  719.     };
  720. }
  721.  
  722. ////////////////////////////////////////////////////////////////////////////////
  723. //
  724. void uBrowser::mouseMove( int xIn , int yIn )
  725. {
  726.     // called when mouse moves and button is down
  727.     int x, y;
  728.     windowPosToTexturePos( xIn, yIn, x, y );
  729.  
  730.     if ( mEmbeddedBrowser )
  731.         mEmbeddedBrowser->mouseMove( x, y );
  732. }
  733.  
  734. ////////////////////////////////////////////////////////////////////////////////
  735. //
  736. void uBrowser::setSize( int widthIn , int heightIn )
  737. {
  738.     // text the embedded browser that things changed
  739.     if ( mEmbeddedBrowser )
  740.         mEmbeddedBrowser->setSize( widthIn, heightIn, true );
  741.  
  742.     // calculate the next power of 2 bigger than reqquested size for width and height
  743.     for ( mTextureWidth = 1; mTextureWidth < widthIn; mTextureWidth <<= 1 )
  744.     {
  745.     };
  746.  
  747.     for ( mTextureHeight = 1; mTextureHeight < heightIn; mTextureHeight <<= 1 )
  748.     {
  749.     };
  750.  
  751.     // save the height and width
  752.     mBrowserWindowWidth = widthIn;
  753.     mBrowserWindowHeight = heightIn;
  754.  
  755.     // we scale all textures by this much so that they fit the geometry
  756.     mTextureScaleX = ( GLfloat )mBrowserWindowWidth / ( GLfloat )mTextureWidth;
  757.     mTextureScaleY = ( GLfloat )mBrowserWindowHeight / ( GLfloat )mTextureHeight;
  758.  
  759.     // delete the old texture handle and create a new one
  760.     glBindTexture( GL_TEXTURE_2D, 0 );
  761.     glDeleteTextures( 1, &mAppTexture );
  762.     glGenTextures( 1, &mAppTexture );
  763.     glBindTexture( GL_TEXTURE_2D, mAppTexture );
  764.     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  765.     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  766.     glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, mTextureWidth, mTextureHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, 0 );
  767. }
  768.  
  769. ////////////////////////////////////////////////////////////////////////////////
  770. //
  771. void uBrowser::gluiCallback( int controlIdIn )
  772. {
  773.     if ( controlIdIn == mIdExit )
  774.     {
  775.         // clean up code - since GLUT doesn't let us exit the event loop, we'll do it here
  776.         // to make sure it works (deleting the browser instance was a major problem before)
  777.         if ( mEmbeddedBrowser )
  778.         {
  779.             mEmbeddedBrowser->getBrowserWindow()->remObserver( this );
  780.             delete mEmbeddedBrowser;
  781.         };
  782.  
  783.         // write something out to the GLUT console to indicate we're all done
  784.         std::cout << "Application finished. Buh-bye!" << std::endl;
  785.  
  786.         // only way out with GLUT
  787.         exit( 0 );
  788.     }
  789.     else
  790.     if ( controlIdIn == mIdReset )
  791.     {
  792.         if ( glutGetWindow() != mAppWindow )
  793.             glutSetWindow( mAppWindow );
  794.  
  795.         resetView();
  796.  
  797.         glutPostRedisplay();
  798.     }
  799.     else
  800.     if ( controlIdIn == mIdBrowserSmall )
  801.     {
  802.         setSize( 400, 400 );
  803.  
  804.         if ( glutGetWindow() != mAppWindow )
  805.             glutSetWindow( mAppWindow );
  806.  
  807.         glutPostRedisplay();
  808.     }
  809.     else
  810.     if ( controlIdIn == mIdBrowserMedium )
  811.     {
  812.         setSize( 800, 800 );
  813.  
  814.         if ( glutGetWindow() != mAppWindow )
  815.             glutSetWindow( mAppWindow );
  816.  
  817.         glutPostRedisplay();
  818.     }
  819.     else
  820.     if ( controlIdIn == mIdBrowserLarge )
  821.     {
  822.         setSize( 1024, 1024 );
  823.  
  824.         if ( glutGetWindow() != mAppWindow )
  825.             glutSetWindow( mAppWindow );
  826.  
  827.         glutPostRedisplay();
  828.     }
  829.     else
  830.     if ( controlIdIn == mIdNavBack )
  831.     {
  832.         mEmbeddedBrowser->navigateBack();
  833.     }
  834.     else
  835.     if ( controlIdIn == mIdNavStop )
  836.     {
  837.         mEmbeddedBrowser->navigateStop();
  838.     }
  839.     else
  840.     if ( controlIdIn == mIdNavHome )
  841.     {
  842.         mEmbeddedBrowser->navigateTo( mHomeUrl.c_str() );
  843.     }
  844.     else
  845.     if ( controlIdIn == mIdNavForward )
  846.     {
  847.         mEmbeddedBrowser->navigateForward();
  848.     }
  849.     else
  850.     if ( controlIdIn == mIdUrlEdit )
  851.     {
  852.         mEmbeddedBrowser->navigateTo( mUrlEdit->get_text() );
  853.     }
  854.     else
  855.     if ( controlIdIn == mIdBookmarks )
  856.     {
  857.         mEmbeddedBrowser->navigateTo( mBookmarks[ mSelBookmark ].second.c_str() );
  858.     }
  859.     else
  860.     // silly hack needed to get around a limitation of GLUI
  861.     // I really need a callback when caret enters the edit field so I can do this automatically
  862.     if ( controlIdIn == mFocusUrlEdit )
  863.     {
  864.         mUrlEdit->enable();
  865.         mEmbeddedBrowser->focusBrowser( false );
  866.         setFocusNativeWindow();
  867.     };
  868. }
  869.  
  870. ////////////////////////////////////////////////////////////////////////////////
  871. //
  872. void uBrowser::onNavigateBegin( const EventType& eventIn )
  873. {
  874.     // could do something here like start a throbber :)
  875. }
  876.  
  877. ////////////////////////////////////////////////////////////////////////////////
  878. //
  879. void uBrowser::onNavigateComplete( const EventType& eventIn )
  880. {
  881.     // could do something here like stop a throbber :)
  882. }
  883.  
  884. ////////////////////////////////////////////////////////////////////////////////
  885. //
  886. void uBrowser::onUpdateProgress( const EventType& eventIn )
  887. {
  888.     // observed event - page progress changes
  889.     glutSetWindow( mBottomGLUIWindow->get_glut_window_id() );
  890.  
  891.     std::ostringstream conv;
  892.     conv << "[" << eventIn.getPayload()->getPercentComplete() << "% loaded]";
  893.     mProgressText->set_text( const_cast< char* >( conv.str().c_str() ) );
  894. }
  895.  
  896. ////////////////////////////////////////////////////////////////////////////////
  897. //
  898. void uBrowser::onStatusTextChange( const EventType& eventIn )
  899. {
  900.     // observed event - status text changes, either during load or when you mouse over a link or a script does it
  901.     glutSetWindow( mBottomGLUIWindow->get_glut_window_id() );
  902.  
  903.     // NOTE: only display the first 100 chars since anything longer breaks the display of percent loaded
  904.     // on the right hand side - normally, you'd want to use the whole thing.
  905.     mStatusText->set_text( const_cast< char*>( eventIn.getPayload()->getStatusMsg().substr( 0, 100 ).c_str() ) );
  906. }
  907.  
  908. ////////////////////////////////////////////////////////////////////////////////
  909. //
  910. void uBrowser::onLocationChange( const EventType& eventIn )
  911. {
  912.     // observed event - URL location changes - e.g. when a site redirects somewhere else
  913.     // (ought to check that this is the top frame or this will be wrong)
  914.     glutSetWindow( mTopGLUIWindow->get_glut_window_id() );
  915.  
  916.     mUrlEdit->set_text( const_cast< char*>( eventIn.getPayload()->getCurrentUri().c_str() ) );
  917. }
  918.  
  919. ////////////////////////////////////////////////////////////////////////////////
  920. //
  921. void* uBrowser::getNativeWindowHandle()
  922. {
  923.     // My implementation of the embedded browser needs a native window handle
  924.     // Can't get this via GLUT so had to use this hack
  925.     #ifdef _WINDOWS
  926.     return FindWindow( NULL, mName.c_str() );
  927.     #else
  928.     return 0;
  929.     #endif
  930. }
  931.  
  932. ////////////////////////////////////////////////////////////////////////////////
  933. //
  934. void uBrowser::setFocusNativeWindow()
  935. {
  936.     // need to set focus to the browser window so that keyboard events work
  937.     #ifdef _WINDOWS
  938.     SetFocus( FindWindow( NULL, mName.c_str() ) );
  939.     #else
  940.     return;
  941.     #endif
  942. }
  943.  
  944. ////////////////////////////////////////////////////////////////////////////////
  945. //
  946. static void gluiCallbackWrapper( int controlIdIn )
  947. {
  948.     // dispatch GLUI callbacks into my class cos I like it that way :)
  949.     if ( gInstance )
  950.         gInstance->gluiCallback( controlIdIn );
  951. }