PageRenderTime 149ms CodeModel.GetById 17ms app.highlight 120ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/test_apps/llplugintest/llmediaplugintest.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 2066 lines | 1579 code | 220 blank | 267 comment | 260 complexity | 3e3a1c057ed9ed7a8b0717f5ee1c9d14 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/**
   2 * @file LLMediaPluginTest.cpp
   3 * @brief Primary test application for LLMedia (Separate Process) Plugin system
   4 *
   5 * $LicenseInfo:firstyear=2008&license=viewerlgpl$
   6 * Second Life Viewer Source Code
   7 * Copyright (C) 2011, Linden Research, Inc.
   8 * 
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation;
  12 * version 2.1 of the License only.
  13 * 
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 * 
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22 * 
  23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  24 * $/LicenseInfo$
  25 */
  26
  27#include "linden_common.h"
  28#include "indra_constants.h"
  29
  30#include "llapr.h"
  31#include "llerrorcontrol.h"
  32
  33#include <math.h>
  34#include <iomanip>
  35#include <sstream>
  36#include <ctime>
  37
  38#include "llmediaplugintest.h"
  39
  40#if __APPLE__
  41	#include <GLUT/glut.h>
  42	#include <CoreFoundation/CoreFoundation.h>
  43#else
  44	#define FREEGLUT_STATIC
  45	#include "GL/freeglut.h"
  46	#define GLUI_FREEGLUT
  47#endif
  48
  49#if LL_WINDOWS
  50#pragma warning(disable: 4263)
  51#pragma warning(disable: 4264)
  52#endif
  53#include "glui.h"
  54
  55
  56LLMediaPluginTest* gApplication = 0;
  57static void gluiCallbackWrapper( int control_id );
  58
  59////////////////////////////////////////////////////////////////////////////////
  60//
  61static bool isTexture( GLuint texture )
  62{
  63	bool result = false;
  64
  65	// glIsTexture will sometimes return false for real textures... do this instead.
  66	if(texture != 0)
  67		result = true;
  68
  69	return result;
  70}
  71
  72////////////////////////////////////////////////////////////////////////////////
  73//
  74mediaPanel::mediaPanel()
  75{
  76	mMediaTextureHandle = 0;
  77	mPickTextureHandle = 0;
  78	mMediaSource = NULL;
  79	mPickTexturePixels = NULL;
  80}
  81
  82////////////////////////////////////////////////////////////////////////////////
  83//
  84mediaPanel::~mediaPanel()
  85{
  86	// delete OpenGL texture handles
  87	if ( isTexture( mPickTextureHandle ) )
  88	{
  89		std::cerr << "remMediaPanel: deleting pick texture " << mPickTextureHandle << std::endl;
  90		glDeleteTextures( 1, &mPickTextureHandle );
  91		mPickTextureHandle = 0;
  92	}
  93
  94	if ( isTexture( mMediaTextureHandle ) )
  95	{
  96		std::cerr << "remMediaPanel: deleting media texture " << mMediaTextureHandle << std::endl;
  97		glDeleteTextures( 1, &mMediaTextureHandle );
  98		mMediaTextureHandle = 0;
  99	}
 100
 101	if(mPickTexturePixels)
 102	{
 103		delete mPickTexturePixels;
 104	}
 105
 106	if(mMediaSource)
 107	{
 108		delete mMediaSource;
 109	}
 110
 111}
 112
 113////////////////////////////////////////////////////////////////////////////////
 114//
 115LLMediaPluginTest::LLMediaPluginTest( int app_window, int window_width, int window_height ) :
 116	mVersionMajor( 2 ),
 117	mVersionMinor( 0 ),
 118	mVersionPatch( 0 ),
 119	mMaxPanels( 25 ),
 120	mViewportAspect( 0 ),
 121	mAppWindow( app_window ),
 122	mCurMouseX( 0 ),
 123	mCurMouseY( 0 ),
 124	mFuzzyMedia( true ),
 125	mSelectedPanel( 0 ),
 126	mDistanceCameraToSelectedGeometry( 0.0f ),
 127	mMediaBrowserControlEnableCookies( 0 ),
 128	mMediaBrowserControlBackButton( 0 ),
 129	mMediaBrowserControlForwardButton( 0 ),
 130	mMediaTimeControlVolume( 100 ),
 131	mMediaTimeControlSeekSeconds( 0 ),
 132	mGluiMediaTimeControlWindowFlag( true ),
 133	mGluiMediaBrowserControlWindowFlag( true ),
 134	mMediaBrowserControlBackButtonFlag( true ),
 135	mMediaBrowserControlForwardButtonFlag( true ),
 136	mHomeWebUrl( "http://www.google.com/" )
 137{
 138	// debugging spam
 139	std::cout << std::endl << "             GLUT version: " << "3.7.6" << std::endl;	// no way to get real version from GLUT
 140	std::cout << std::endl << "             GLUI version: " << GLUI_Master.get_version() << std::endl;
 141	std::cout << std::endl << "Media Plugin Test version: " << mVersionMajor << "." << mVersionMinor << "." << mVersionPatch << std::endl;
 142
 143	// bookmark title
 144	mBookmarks.push_back( std::pair< std::string, std::string >( "--- Bookmarks ---", "" ) );
 145
 146	// insert hardcoded URLs here as required for testing
 147	//mBookmarks.push_back( std::pair< std::string, std::string >( "description", "url" ) );
 148
 149	// read bookmarks from file.
 150	// note: uses command in ./CmakeLists.txt which copies bookmmarks file from source directory
 151	//       to app directory (WITHOUT build configuration dir) (this is cwd in Windows within MSVC)
 152	//		 For example, test_apps\llplugintest and not test_apps\llplugintest\Release
 153	//		 This may need to be changed for Mac/Linux builds.
 154	// See https://jira.lindenlab.com/browse/DEV-31350 for large list of media URLs from AGNI
 155	const std::string bookmarks_filename( "bookmarks.txt" );
 156	std::ifstream file_handle( bookmarks_filename.c_str() );
 157	if ( file_handle.is_open() )
 158	{
 159		std::cout << "Reading bookmarks for test" << std::endl;
 160		while( ! file_handle.eof() )
 161		{
 162			std::string line;
 163			std::getline( file_handle, line );
 164			if ( file_handle.eof() )
 165				break;
 166
 167			if ( line.substr( 0, 1 ) != "#" )
 168			{
 169				size_t comma_pos = line.find_first_of( ',' );
 170				if ( comma_pos != std::string::npos )
 171				{
 172					std::string description = line.substr( 0, comma_pos );
 173					std::string url = line.substr( comma_pos + 1 );
 174					mBookmarks.push_back( std::pair< std::string, std::string >( description, url ) );
 175				}
 176				else
 177				{
 178					mBookmarks.push_back( std::pair< std::string, std::string >( line, line ) );
 179				};
 180			};
 181		};
 182		std::cout << "Read " << mBookmarks.size() << " bookmarks" << std::endl;
 183	}
 184	else
 185	{
 186		std::cout << "Unable to read bookmarks from file: " << bookmarks_filename << std::endl;
 187	};
 188
 189	// initialize linden lab APR module
 190	ll_init_apr();
 191
 192	// Set up llerror logging
 193	{
 194		LLError::initForApplication(".");
 195		LLError::setDefaultLevel(LLError::LEVEL_INFO);
 196		//LLError::setTagLevel("Plugin", LLError::LEVEL_DEBUG);
 197	}
 198
 199	// lots of randomness in this app
 200	srand( ( unsigned int )time( 0 ) );
 201
 202	// build GUI
 203	makeChrome();
 204
 205	// OpenGL initialilzation
 206	glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
 207	glClearDepth( 1.0f );
 208	glEnable( GL_DEPTH_TEST );
 209	glEnable( GL_COLOR_MATERIAL );
 210	glColorMaterial( GL_FRONT, GL_AMBIENT_AND_DIFFUSE );
 211	glDepthFunc( GL_LEQUAL );
 212	glEnable( GL_TEXTURE_2D );
 213	glDisable( GL_BLEND );
 214	glColor3f( 1.0f, 1.0f, 1.0f );
 215	glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
 216	glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
 217
 218	// start with a sane view
 219	resetView();
 220
 221	// initial media panel
 222	const int num_initial_panels = 1;
 223	for( int i = 0; i < num_initial_panels; ++i )
 224	{
 225		//addMediaPanel( mBookmarks[ rand() % ( mBookmarks.size() - 1 ) + 1 ].second );
 226		addMediaPanel( mHomeWebUrl );
 227	};
 228}
 229
 230////////////////////////////////////////////////////////////////////////////////
 231//
 232LLMediaPluginTest::~LLMediaPluginTest()
 233{
 234	// delete all media panels
 235	for( int i = 0; i < (int)mMediaPanels.size(); ++i )
 236	{
 237		remMediaPanel( mMediaPanels[ i ] );
 238	};
 239	
 240	// Stop the plugin read thread if it's running.
 241	LLPluginProcessParent::setUseReadThread(false);
 242}
 243
 244////////////////////////////////////////////////////////////////////////////////
 245//
 246void LLMediaPluginTest::reshape( int width, int height )
 247{
 248	// update viewport (the active window inside the chrome)
 249	int viewport_x, viewport_y;
 250	int viewport_height, viewport_width;
 251	GLUI_Master.get_viewport_area( &viewport_x, &viewport_y, &viewport_width, &viewport_height );
 252	mViewportAspect = (float)( viewport_width ) / (float)( viewport_height );
 253	glViewport( viewport_x, viewport_y, viewport_width, viewport_height );
 254
 255	// save these as we'll need them later
 256	mWindowWidth = width;
 257	mWindowHeight = height;
 258
 259	// adjust size of URL bar so it doesn't get clipped
 260	mUrlEdit->set_w( mWindowWidth - 360 );
 261
 262	// GLUI requires this
 263	if ( glutGetWindow() != mAppWindow )
 264		glutSetWindow( mAppWindow );
 265
 266	// trigger re-display
 267	glutPostRedisplay();
 268};
 269
 270////////////////////////////////////////////////////////////////////////////////
 271//
 272void LLMediaPluginTest::bindTexture(GLuint texture, GLint row_length, GLint alignment)
 273{
 274	glEnable( GL_TEXTURE_2D );
 275
 276	glBindTexture( GL_TEXTURE_2D, texture );
 277	glPixelStorei( GL_UNPACK_ROW_LENGTH, row_length );
 278	glPixelStorei( GL_UNPACK_ALIGNMENT, alignment );
 279}
 280
 281////////////////////////////////////////////////////////////////////////////////
 282//
 283bool LLMediaPluginTest::checkGLError(const char *name)
 284{
 285	bool result = false;
 286	GLenum error = glGetError();
 287
 288	if(error != GL_NO_ERROR)
 289	{
 290		// For some reason, glGenTextures is returning GL_INVALID_VALUE...
 291		std::cout << name << " ERROR 0x" << std::hex << error << std::dec << std::endl;
 292		result = true;
 293	}
 294
 295	return result;
 296}
 297
 298////////////////////////////////////////////////////////////////////////////////
 299//
 300GLfloat LLMediaPluginTest::distanceToCamera( GLfloat point_x, GLfloat point_y, GLfloat point_z )
 301{
 302	GLdouble camera_pos_x = 0.0f;
 303	GLdouble camera_pos_y = 0.0f;
 304	GLdouble camera_pos_z = 0.0f;
 305
 306	GLdouble modelMatrix[16];
 307	GLdouble projMatrix[16];
 308	GLint viewport[4];
 309
 310	glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
 311	glGetDoublev(GL_PROJECTION_MATRIX, projMatrix);
 312	glGetIntegerv(GL_VIEWPORT, viewport);
 313
 314	gluUnProject(
 315		(viewport[2]-viewport[0])/2 , (viewport[3]-viewport[1])/2,
 316		0.0,
 317		modelMatrix, projMatrix, viewport,
 318		&camera_pos_x, &camera_pos_y, &camera_pos_z );
 319
 320	GLfloat distance =
 321		sqrt( ( camera_pos_x - point_x ) * ( camera_pos_x - point_x ) +
 322			  ( camera_pos_y - point_y ) * ( camera_pos_y - point_y ) +
 323			  ( camera_pos_z - point_z ) * ( camera_pos_z - point_z ) );
 324
 325	return distance;
 326}
 327
 328////////////////////////////////////////////////////////////////////////////////
 329//
 330void LLMediaPluginTest::drawGeometry( int panel, bool selected )
 331{
 332	// texture coordinates for each panel
 333	GLfloat non_opengl_texture_coords[ 8 ] = { 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f };
 334	GLfloat opengl_texture_coords[ 8 ] =     { 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f };
 335
 336	GLfloat *texture_coords = mMediaPanels[ panel ]->mAppTextureCoordsOpenGL?opengl_texture_coords:non_opengl_texture_coords;
 337
 338	// base coordinates for each panel
 339	GLfloat base_vertex_pos[ 8 ] = { 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f };
 340
 341	// calculate posiitons
 342	const int num_panels = (int)mMediaPanels.size();
 343	const int num_rows = (int)sqrt( (float)num_panels );
 344	const int num_cols = num_panels / num_rows;
 345	const int panel_x = ( panel / num_rows );
 346	const int panel_y = ( panel % num_rows );
 347
 348	// default spacing is small - make it larger if checkbox set - for testing positional audio
 349	float spacing = 0.1f;
 350	if ( mLargePanelSpacing )
 351		spacing = 2.0f;
 352
 353	const GLfloat offset_x = num_cols * ( 1.0 + spacing ) / 2;
 354	const GLfloat offset_y = num_rows * ( 1.0 + spacing ) / 2;
 355
 356	// Adjust for media aspect ratios
 357	{
 358		float aspect = 1.0f;
 359
 360		if(mMediaPanels[ panel ]->mMediaHeight != 0)
 361		{
 362			aspect = (float)mMediaPanels[ panel ]->mMediaWidth / (float)mMediaPanels[ panel ]->mMediaHeight;
 363		}
 364
 365		if(aspect > 1.0f)
 366		{
 367			// media is wider than it is high -- adjust the top and bottom in
 368			for( int corner = 0; corner < 4; ++corner )
 369			{
 370				float temp = base_vertex_pos[corner * 2 + 1];
 371
 372				if(temp < 0.5f)
 373					temp += 0.5 - (0.5f / aspect);
 374				else
 375					temp -= 0.5 - (0.5f / aspect);
 376
 377				base_vertex_pos[corner * 2 + 1] = temp;
 378			}
 379		}
 380		else if(aspect < 1.0f)
 381		{
 382			// media is higher than it is wide -- adjust the left and right sides in
 383			for( int corner = 0; corner < 4; ++corner )
 384			{
 385				float temp = base_vertex_pos[corner * 2];
 386
 387				if(temp < 0.5f)
 388					temp += 0.5f - (0.5f * aspect);
 389				else
 390					temp -= 0.5f - (0.5f * aspect);
 391
 392				base_vertex_pos[corner * 2] = temp;
 393			}
 394		}
 395	}
 396
 397	glBegin( GL_QUADS );
 398	for( int corner = 0; corner < 4; ++corner )
 399	{
 400		glTexCoord2f( texture_coords[ corner * 2 ], texture_coords[ corner * 2 + 1 ] );
 401		GLfloat x = base_vertex_pos[ corner * 2 ] + panel_x * ( 1.0 + spacing ) - offset_x + spacing / 2.0f;
 402		GLfloat y = base_vertex_pos[ corner * 2 + 1 ] + panel_y * ( 1.0 + spacing ) - offset_y + spacing / 2.0f;
 403
 404		glVertex3f( x, y, 0.0f );
 405	};
 406	glEnd();
 407
 408	// calculate distance to this panel if it's selected
 409	if ( selected )
 410	{
 411		GLfloat point_x = base_vertex_pos[ 0 ] + panel_x * ( 1.0 + spacing ) - offset_x + spacing / 2.0f;
 412		GLfloat point_y = base_vertex_pos[ 0 + 1 ] + panel_y * ( 1.0 + spacing ) - offset_y + spacing / 2.0f;
 413		GLfloat point_z = 0.0f;
 414		mDistanceCameraToSelectedGeometry = distanceToCamera( point_x, point_y, point_z );
 415	};
 416}
 417
 418//////////////////////////////////////////////////////////////////////////////
 419//
 420void LLMediaPluginTest::startPanelHighlight( float red, float green, float blue, float line_width )
 421{
 422	glPushAttrib( GL_ALL_ATTRIB_BITS );
 423	glEnable( GL_POLYGON_OFFSET_FILL );
 424	glPolygonOffset( -2.5f, -2.5f );
 425	glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
 426	glLineWidth( line_width );
 427	glColor3f( red, green, blue );
 428	glDisable( GL_TEXTURE_2D );
 429}
 430
 431//////////////////////////////////////////////////////////////////////////////
 432//
 433void LLMediaPluginTest::endPanelHighlight()
 434{
 435	glPopAttrib();
 436}
 437
 438////////////////////////////////////////////////////////////////////////////////
 439//
 440void LLMediaPluginTest::draw( int draw_type )
 441{
 442	for( int panel = 0; panel < (int)mMediaPanels.size(); ++panel )
 443	{
 444		// drawing pick texture
 445		if ( draw_type == DrawTypePickTexture )
 446		{
 447			// only bother with pick if we have something to render
 448			// Actually, we need to pick even if we're not ready to render.
 449			// Otherwise you can't select and remove a panel which has gone bad.
 450			//if ( mMediaPanels[ panel ]->mReadyToRender )
 451			{
 452				glMatrixMode( GL_TEXTURE );
 453				glPushMatrix();
 454
 455				// pick texture is a power of 2 so no need to scale
 456				glLoadIdentity();
 457
 458				// bind to media texture
 459				glLoadIdentity();
 460				bindTexture( mMediaPanels[ panel ]->mPickTextureHandle );
 461				glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
 462				glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
 463
 464				// draw geometry using pick texture
 465				drawGeometry( panel, false );
 466
 467				glMatrixMode( GL_TEXTURE );
 468				glPopMatrix();
 469			};
 470		}
 471		else
 472		if ( draw_type == DrawTypeMediaTexture )
 473		{
 474			bool texture_valid = false;
 475			bool plugin_exited = false;
 476
 477			if(mMediaPanels[ panel ]->mMediaSource)
 478			{
 479				texture_valid = mMediaPanels[ panel ]->mMediaSource->textureValid();
 480				plugin_exited = mMediaPanels[ panel ]->mMediaSource->isPluginExited();
 481			}
 482
 483			// save texture matrix (changes for each panel)
 484			glMatrixMode( GL_TEXTURE );
 485			glPushMatrix();
 486
 487			// only process texture if the media is ready to draw
 488			// (we still want to draw the geometry)
 489			if ( mMediaPanels[ panel ]->mReadyToRender && texture_valid )
 490			{
 491				// bind to media texture
 492				bindTexture( mMediaPanels[ panel ]->mMediaTextureHandle );
 493
 494				if ( mFuzzyMedia )
 495				{
 496					glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
 497					glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
 498				}
 499				else
 500				{
 501					glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
 502					glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
 503				}
 504
 505				// scale to fit panel
 506				glScalef( mMediaPanels[ panel ]->mTextureScaleX,
 507							mMediaPanels[ panel ]->mTextureScaleY,
 508								1.0f );
 509			};
 510
 511			float intensity = plugin_exited?0.25f:1.0f;
 512
 513			// highlight the selected panel
 514			if ( mSelectedPanel && ( mMediaPanels[ panel ]->mId == mSelectedPanel->mId ) )
 515			{
 516				startPanelHighlight( intensity, intensity, 0.0f, 5.0f );
 517				drawGeometry( panel, true );
 518				endPanelHighlight();
 519			}
 520			else
 521			// this panel not able to render yet since it
 522			// doesn't have enough information
 523			if ( !mMediaPanels[ panel ]->mReadyToRender )
 524			{
 525				startPanelHighlight( intensity, 0.0f, 0.0f, 2.0f );
 526				drawGeometry( panel, false );
 527				endPanelHighlight();
 528			}
 529			else
 530			// just display a border around the media
 531			{
 532				startPanelHighlight( 0.0f, intensity, 0.0f, 2.0f );
 533				drawGeometry( panel, false );
 534				endPanelHighlight();
 535			};
 536
 537			if ( mMediaPanels[ panel ]->mReadyToRender && texture_valid )
 538			{
 539				// draw visual geometry
 540				drawGeometry( panel, false );
 541			}
 542
 543			// restore texture matrix (changes for each panel)
 544			glMatrixMode( GL_TEXTURE );
 545			glPopMatrix();
 546		};
 547	};
 548}
 549
 550////////////////////////////////////////////////////////////////////////////////
 551//
 552void LLMediaPluginTest::display()
 553{
 554	// GLUI requires this
 555	if ( glutGetWindow() != mAppWindow )
 556		glutSetWindow( mAppWindow );
 557
 558	// start with a clean slate
 559	glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
 560	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
 561
 562	// set up OpenGL view
 563	glMatrixMode( GL_PROJECTION );
 564	glLoadIdentity();
 565	glFrustum( -mViewportAspect * 0.04f, mViewportAspect * 0.04f, -0.04f, 0.04f, 0.1f, 50.0f );
 566	glMatrixMode( GL_MODELVIEW );
 567	glLoadIdentity();
 568	glTranslatef( 0.0, 0.0, 0.0f );
 569	glTranslatef( mViewPos[ 0 ], mViewPos[ 1 ], -mViewPos[ 2 ] );
 570	glMultMatrixf( mViewRotation );
 571
 572	// draw pick texture
 573	draw( DrawTypePickTexture );
 574
 575	// read colors and get coordinate values
 576	glReadPixels( mCurMouseX, mCurMouseY, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, mPixelReadColor );
 577
 578	// clear the pick render (otherwise it may depth-fight with the textures rendered later)
 579	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
 580
 581	// draw visible geometry
 582	draw( DrawTypeMediaTexture );
 583
 584	glutSwapBuffers();
 585}
 586
 587////////////////////////////////////////////////////////////////////////////////
 588//
 589void LLMediaPluginTest::idle()
 590{
 591//	checkGLError("LLMediaPluginTest::idle");
 592
 593	// GLUI requires this
 594	if ( glutGetWindow() != mAppWindow )
 595		glutSetWindow( mAppWindow );
 596
 597	// random creation/destruction of panels enabled?
 598	const time_t panel_timeout_time = 5;
 599	if ( mRandomPanelCount )
 600	{
 601		// time for a change
 602		static time_t last_panel_time = 0;
 603		if ( time( NULL ) - last_panel_time > panel_timeout_time )
 604		{
 605			if ( rand() % 2 == 0 )
 606			{
 607				if ( mMediaPanels.size() < 16 )
 608				{
 609					std::cout << "Randomly adding new panel" << std::endl;
 610					addMediaPanel( mBookmarks[ rand() % ( mBookmarks.size() - 1 ) + 1 ].second );
 611				};
 612			}
 613			else
 614			{
 615				if ( mMediaPanels.size() > 0 )
 616				{
 617					std::cout << "Deleting selected panel" << std::endl;
 618					remMediaPanel( mSelectedPanel );
 619				};
 620			};
 621			time( &last_panel_time );
 622		};
 623	};
 624
 625	// random selection of bookmarks enabled?
 626	const time_t bookmark_timeout_time = 5;
 627	if ( mRandomBookmarks )
 628	{
 629		// time for a change
 630		static time_t last_bookmark_time = 0;
 631		if ( time( NULL ) - last_bookmark_time > bookmark_timeout_time )
 632		{
 633			// go to a different random bookmark on each panel
 634			for( int panel = 0; panel < (int)mMediaPanels.size(); ++panel )
 635			{
 636				std::string uri = mBookmarks[ rand() % ( mBookmarks.size() - 1 ) + 1 ].second;
 637
 638				std::cout << "Random: navigating to : " << uri << std::endl;
 639
 640				std::string mime_type = mimeTypeFromUrl( uri );
 641
 642				if ( mime_type != mMediaPanels[ panel ]->mMimeType )
 643				{
 644					replaceMediaPanel( mMediaPanels[ panel ], uri );
 645				}
 646				else
 647				{
 648					mMediaPanels[ panel ]->mMediaSource->loadURI( uri );
 649					mMediaPanels[ panel ]->mMediaSource->start();
 650				};
 651			};
 652
 653			time( &last_bookmark_time );
 654		};
 655	};
 656
 657	// update UI
 658	if ( mSelectedPanel )
 659	{
 660		// set volume based on slider if we have time media
 661		//if ( mGluiMediaTimeControlWindowFlag )
 662		//{
 663		//	mSelectedPanel->mMediaSource->setVolume( (float)mMediaTimeControlVolume / 100.0f );
 664		//};
 665
 666		// NOTE: it is absurd that we need cache the state of GLUI controls
 667		//       but enabling/disabling controls drags framerate from 500+
 668		//		 down to 15. Not a problem for plugin system - only this test
 669		// enable/disable time based UI controls based on type of plugin
 670		if ( mSelectedPanel->mMediaSource->pluginSupportsMediaTime() )
 671		{
 672			if ( ! mGluiMediaTimeControlWindowFlag )
 673			{
 674				mGluiMediaTimeControlWindow->enable();
 675				mGluiMediaTimeControlWindowFlag = true;
 676			};
 677		}
 678		else
 679		{
 680			if ( mGluiMediaTimeControlWindowFlag )
 681			{
 682				mGluiMediaTimeControlWindow->disable();
 683				mGluiMediaTimeControlWindowFlag = false;
 684			};
 685		};
 686
 687		// enable/disable browser based UI controls based on type of plugin
 688		if ( mSelectedPanel->mMediaSource->pluginSupportsMediaBrowser() )
 689		{
 690			if ( ! mGluiMediaBrowserControlWindowFlag )
 691			{
 692				mGluiMediaBrowserControlWindow->enable();
 693				mGluiMediaBrowserControlWindowFlag = true;
 694			};
 695		}
 696		else
 697		{
 698			if ( mGluiMediaBrowserControlWindowFlag )
 699			{
 700				mGluiMediaBrowserControlWindow->disable();
 701				mGluiMediaBrowserControlWindowFlag = false;
 702			};
 703		};
 704
 705		// enable/disable browser back button depending on browser history
 706		if ( mSelectedPanel->mMediaSource->getHistoryBackAvailable()  )
 707		{
 708			if ( ! mMediaBrowserControlBackButtonFlag )
 709			{
 710				mMediaBrowserControlBackButton->enable();
 711				mMediaBrowserControlBackButtonFlag = true;
 712			};
 713		}
 714		else
 715		{
 716			if ( mMediaBrowserControlBackButtonFlag )
 717			{
 718				mMediaBrowserControlBackButton->disable();
 719				mMediaBrowserControlBackButtonFlag = false;
 720			};
 721		};
 722
 723		// enable/disable browser forward button depending on browser history
 724		if ( mSelectedPanel->mMediaSource->getHistoryForwardAvailable()  )
 725		{
 726			if ( ! mMediaBrowserControlForwardButtonFlag )
 727			{
 728				mMediaBrowserControlForwardButton->enable();
 729				mMediaBrowserControlForwardButtonFlag = true;
 730			};
 731		}
 732		else
 733		{
 734			if ( mMediaBrowserControlForwardButtonFlag )
 735			{
 736				mMediaBrowserControlForwardButton->disable();
 737				mMediaBrowserControlForwardButtonFlag = false;
 738			};
 739		};
 740
 741		// NOTE: This is *very* slow and not worth optimising
 742		updateStatusBar();
 743	};
 744
 745	// update all the panels
 746	for( int panel_index = 0; panel_index < (int)mMediaPanels.size(); ++panel_index )
 747	{
 748		mediaPanel *panel = mMediaPanels[ panel_index ];
 749
 750		// call plugins idle function so it can potentially update itself
 751		panel->mMediaSource->idle();
 752
 753		// update each media panel
 754		updateMediaPanel( panel );
 755
 756		LLRect dirty_rect;
 757		if ( ! panel->mMediaSource->textureValid() )
 758		{
 759			//std::cout << "texture invalid, skipping update..." << std::endl;
 760		}
 761		else
 762		if ( panel &&
 763			 ( panel->mMediaWidth != panel->mMediaSource->getWidth() ||
 764			   panel->mMediaHeight != panel->mMediaSource->getHeight() ) )
 765		{
 766			//std::cout << "Resize in progress, skipping update..." << std::endl;
 767		}
 768		else
 769		if ( panel->mMediaSource->getDirty( &dirty_rect ) )
 770		{
 771			const unsigned char* pixels = panel->mMediaSource->getBitsData();
 772			if ( pixels && isTexture(panel->mMediaTextureHandle))
 773			{
 774				int x_offset = dirty_rect.mLeft;
 775				int y_offset = dirty_rect.mBottom;
 776				int width = dirty_rect.mRight - dirty_rect.mLeft;
 777				int height = dirty_rect.mTop - dirty_rect.mBottom;
 778
 779				if((dirty_rect.mRight <= panel->mTextureWidth) && (dirty_rect.mTop <= panel->mTextureHeight))
 780				{
 781					// Offset the pixels pointer properly
 782					pixels += ( y_offset * panel->mMediaSource->getTextureDepth() * panel->mMediaSource->getBitsWidth() );
 783					pixels += ( x_offset * panel->mMediaSource->getTextureDepth() );
 784
 785					// set up texture
 786					bindTexture( panel->mMediaTextureHandle, panel->mMediaSource->getBitsWidth() );
 787					if ( mFuzzyMedia )
 788					{
 789						glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
 790						glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
 791					}
 792					else
 793					{
 794						glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
 795						glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
 796					};
 797
 798					checkGLError("glTexParameteri");
 799
 800					if(panel->mMediaSource->getTextureFormatSwapBytes())
 801					{
 802						glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
 803						checkGLError("glPixelStorei");
 804					}
 805
 806					// draw portion that changes into texture
 807					glTexSubImage2D( GL_TEXTURE_2D, 0,
 808						x_offset,
 809						y_offset,
 810						width,
 811						height,
 812						panel->mMediaSource->getTextureFormatPrimary(),
 813						panel->mMediaSource->getTextureFormatType(),
 814						pixels );
 815
 816					if(checkGLError("glTexSubImage2D"))
 817					{
 818						std::cerr << "    panel ID=" << panel->mId << std::endl;
 819						std::cerr << "    texture size = " << panel->mTextureWidth << " x " << panel->mTextureHeight << std::endl;
 820						std::cerr << "    media size = " << panel->mMediaWidth << " x " << panel->mMediaHeight << std::endl;
 821						std::cerr << "    dirty rect = " << dirty_rect.mLeft << ", " << dirty_rect.mBottom << ", " << dirty_rect.mRight << ", " << dirty_rect.mTop << std::endl;
 822						std::cerr << "    texture width = " << panel->mMediaSource->getBitsWidth() << std::endl;
 823						std::cerr << "    format primary = 0x" << std::hex << panel->mMediaSource->getTextureFormatPrimary() << std::dec << std::endl;
 824						std::cerr << "    format type = 0x" << std::hex << panel->mMediaSource->getTextureFormatType() << std::dec << std::endl;
 825						std::cerr << "    pixels = " << (void*)pixels << std::endl;
 826					}
 827
 828					if(panel->mMediaSource->getTextureFormatSwapBytes())
 829					{
 830						glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
 831						checkGLError("glPixelStorei");
 832					}
 833
 834					panel->mMediaSource->resetDirty();
 835
 836					panel->mReadyToRender = true;
 837				}
 838				else
 839				{
 840					std::cerr << "dirty rect is outside current media size, skipping update" << std::endl;
 841				}
 842			};
 843		};
 844	};
 845
 846	// GLUI requires this
 847	if ( glutGetWindow() != mAppWindow )
 848		glutSetWindow( mAppWindow );
 849
 850	// trigger re-display
 851	glutPostRedisplay();
 852}
 853
 854////////////////////////////////////////////////////////////////////////////////
 855//
 856void LLMediaPluginTest::windowPosToTexturePos( int window_x, int window_y,
 857											   int& media_x, int& media_y,
 858											   int& id )
 859{
 860	if ( ! mSelectedPanel )
 861	{
 862		media_x = 0;
 863		media_y = 0;
 864		id = 0;
 865		return;
 866	};
 867
 868	// record cursor poisiton for a readback next frame
 869	mCurMouseX = window_x;
 870	// OpenGL app == coordinate system this way
 871	// NOTE: unrelated to settings in plugin - this
 872	// is just for this app
 873	mCurMouseY = mWindowHeight - window_y;
 874
 875	// extract x (0..1023, y (0..1023) and id (0..15) from RGB components
 876	unsigned long pixel_read_color_bits = ( mPixelReadColor[ 0 ] << 16 ) | ( mPixelReadColor[ 1 ] << 8 ) | mPixelReadColor[ 2 ];
 877	int texture_x = pixel_read_color_bits & 0x3ff;
 878	int texture_y = ( pixel_read_color_bits >> 10 ) & 0x3ff;
 879	id = ( pixel_read_color_bits >> 20 ) & 0x0f;
 880
 881	// scale to size of media (1024 because we use 10 bits for X and Y from 24)
 882	media_x = (int)( ( (float)mSelectedPanel->mMediaWidth * (float)texture_x ) / 1024.0f );
 883	media_y = (int)( ( (float)mSelectedPanel->mMediaHeight * (float)texture_y ) / 1024.0f );
 884
 885	// we assume the plugin uses an inverted coordinate scheme like OpenGL
 886	// if not, the plugin code inverts the Y coordinate for us - we don't need to
 887	media_y = mSelectedPanel->mMediaHeight - media_y;
 888
 889	if ( media_x > 0 && media_y > 0 )
 890	{
 891		//std::cout << "      mouse coords: " << mCurMouseX << " x " << mCurMouseY << " and id = " << id  << std::endl;
 892		//std::cout << "raw texture coords: " << texture_x << " x " << texture_y << " and id = " << id  << std::endl;
 893		//std::cout << "      media coords: " << media_x << " x " << media_y << " and id = " << id  << std::endl;
 894		//std::cout << std::endl;
 895	};
 896}
 897
 898////////////////////////////////////////////////////////////////////////////////
 899//
 900void LLMediaPluginTest::selectPanelById( int id )
 901{
 902	for( int panel = 0; panel < (int)mMediaPanels.size(); ++panel )
 903	{
 904		if ( mMediaPanels[ panel ]->mId == id )
 905		{
 906			selectPanel(mMediaPanels[ panel ]);
 907			return;
 908		};
 909	};
 910}
 911
 912////////////////////////////////////////////////////////////////////////////////
 913//
 914void LLMediaPluginTest::selectPanel( mediaPanel* panel )
 915{
 916	if( mSelectedPanel == panel )
 917		return;
 918
 919	// turn off volume before we delete it
 920	if( mSelectedPanel && mSelectedPanel->mMediaSource )
 921	{
 922		mSelectedPanel->mMediaSource->setVolume( 0.0f );
 923		mSelectedPanel->mMediaSource->setPriority( LLPluginClassMedia::PRIORITY_LOW );
 924	};
 925
 926	mSelectedPanel = panel;
 927
 928	if( mSelectedPanel && mSelectedPanel->mMediaSource )
 929	{
 930		mSelectedPanel->mMediaSource->setVolume( (float)mMediaTimeControlVolume / 100.0f );
 931		mSelectedPanel->mMediaSource->setPriority( LLPluginClassMedia::PRIORITY_NORMAL );
 932
 933		if(!mSelectedPanel->mStartUrl.empty())
 934		{
 935			mUrlEdit->set_text(const_cast<char*>(mSelectedPanel->mStartUrl.c_str()) );
 936		}
 937	};
 938}
 939
 940////////////////////////////////////////////////////////////////////////////////
 941//
 942mediaPanel*  LLMediaPluginTest::findMediaPanel( LLPluginClassMedia* source )
 943{
 944	mediaPanel *result = NULL;
 945
 946	for( int panel = 0; panel < (int)mMediaPanels.size(); ++panel )
 947	{
 948		if ( mMediaPanels[ panel ]->mMediaSource == source )
 949		{
 950			result = mMediaPanels[ panel ];
 951		}
 952	}
 953
 954	return result;
 955}
 956
 957////////////////////////////////////////////////////////////////////////////////
 958//
 959mediaPanel* LLMediaPluginTest::findMediaPanel( const std::string &target_name )
 960{
 961	mediaPanel *result = NULL;
 962
 963	for( int panel = 0; panel < (int)mMediaPanels.size(); ++panel )
 964	{
 965		if ( mMediaPanels[ panel ]->mTarget == target_name )
 966		{
 967			result = mMediaPanels[ panel ];
 968		}
 969	}
 970
 971	return result;
 972}
 973
 974////////////////////////////////////////////////////////////////////////////////
 975//
 976void LLMediaPluginTest::navigateToNewURI( std::string uri )
 977{
 978	if ( uri.length() )
 979	{
 980		std::string mime_type = mimeTypeFromUrl( uri );
 981
 982		if ( !mSelectedPanel->mMediaSource->isPluginExited() && (mime_type == mSelectedPanel->mMimeType) )
 983		{
 984			std::cout << "MIME type is the same" << std::endl;
 985			mSelectedPanel->mMediaSource->loadURI( uri );
 986			mSelectedPanel->mMediaSource->start();
 987			mBookmarkList->do_selection( 0 );
 988		}
 989		else
 990		{
 991			std::cout << "MIME type changed or plugin had exited" << std::endl;
 992			replaceMediaPanel( mSelectedPanel, uri );
 993			mBookmarkList->do_selection( 0 );
 994		}
 995	};
 996}
 997
 998////////////////////////////////////////////////////////////////////////////////
 999//
1000void LLMediaPluginTest::initUrlHistory( std::string uris )
1001{
1002	if ( uris.length() > 0 )
1003	{
1004		std::cout << "init URL : " << uris << std::endl;
1005		LLSD historySD;
1006
1007		char *cstr, *p;
1008		cstr = new char[uris.size()+1];
1009		strcpy(cstr, uris.c_str());
1010		const char *DELIMS = " ,;";
1011		p = strtok(cstr, DELIMS);
1012		while (p != NULL) {
1013			historySD.insert(0, p);
1014			p = strtok(NULL, DELIMS);
1015		}
1016		mSelectedPanel->mMediaSource->initializeUrlHistory(historySD);
1017		delete[] cstr;
1018	}
1019}
1020
1021////////////////////////////////////////////////////////////////////////////////
1022//
1023void LLMediaPluginTest::gluiCallback( int control_id )
1024{
1025	if ( control_id == mIdBookmarks )
1026	{
1027		std::string uri = mBookmarks[ mSelBookmark ].second;
1028
1029		navigateToNewURI( uri );
1030	}
1031	else
1032    if ( control_id == mIdUrlEdit)
1033	{
1034		std::string uri = mUrlEdit->get_text();
1035
1036		navigateToNewURI( uri );
1037	}
1038	else
1039	if ( control_id == mIdUrlInitHistoryEdit )
1040	{
1041		std::string uri = mUrlInitHistoryEdit->get_text();
1042
1043		initUrlHistory( uri );
1044	}
1045	else
1046	if ( control_id == mIdControlAddPanel )
1047	{
1048		addMediaPanel( mBookmarks[ rand() % ( mBookmarks.size() - 1 ) + 1 ].second );
1049	}
1050	else
1051	if ( control_id == mIdControlRemPanel )
1052	{
1053		remMediaPanel( mSelectedPanel );
1054	}
1055	else
1056	if ( control_id == mIdDisableTimeout )
1057	{
1058		// Set the "disable timeout" flag for all active plugins.
1059		for( int i = 0; i < (int)mMediaPanels.size(); ++i )
1060		{
1061			mMediaPanels[ i ]->mMediaSource->setDisableTimeout(mDisableTimeout);
1062		}
1063	}
1064	else
1065	if ( control_id == mIdUsePluginReadThread )
1066	{
1067		LLPluginProcessParent::setUseReadThread(mUsePluginReadThread);
1068	}
1069	else
1070	if ( control_id == mIdControlCrashPlugin )
1071	{
1072		// send message to plugin and ask it to crash
1073		// (switch out for ReleaseCandidate version :) )
1074		if(mSelectedPanel && mSelectedPanel->mMediaSource)
1075		{
1076			mSelectedPanel->mMediaSource->crashPlugin();
1077		}
1078	}
1079	else
1080	if ( control_id == mIdControlHangPlugin )
1081	{
1082		// send message to plugin and ask it to hang
1083		// (switch out for ReleaseCandidate version :) )
1084		if(mSelectedPanel && mSelectedPanel->mMediaSource)
1085		{
1086			mSelectedPanel->mMediaSource->hangPlugin();
1087		}
1088	}
1089	else
1090	if ( control_id == mIdControlExitApp )
1091	{
1092		// text for exiting plugin system cleanly
1093		delete this;	// clean up
1094		exit( 0 );
1095	}
1096	else
1097	if ( control_id == mIdMediaTimeControlPlay )
1098	{
1099		if ( mSelectedPanel )
1100		{
1101			mSelectedPanel->mMediaSource->setLoop( false );
1102			mSelectedPanel->mMediaSource->start();
1103		};
1104	}
1105	else
1106	if ( control_id == mIdMediaTimeControlLoop )
1107	{
1108		if ( mSelectedPanel )
1109		{
1110			mSelectedPanel->mMediaSource->setLoop( true );
1111			mSelectedPanel->mMediaSource->start();
1112		};
1113	}
1114	else
1115	if ( control_id == mIdMediaTimeControlPause )
1116	{
1117		if ( mSelectedPanel )
1118			mSelectedPanel->mMediaSource->pause();
1119	}
1120	else
1121	if ( control_id == mIdMediaTimeControlStop )
1122	{
1123		if ( mSelectedPanel )
1124		{
1125			mSelectedPanel->mMediaSource->stop();
1126		};
1127	}
1128	else
1129	if ( control_id == mIdMediaTimeControlSeek )
1130	{
1131		if ( mSelectedPanel )
1132		{
1133			// get value from spinner
1134			float seconds_to_seek = mMediaTimeControlSeekSeconds;
1135			mSelectedPanel->mMediaSource->seek( seconds_to_seek );
1136			mSelectedPanel->mMediaSource->start();
1137		};
1138	}
1139	else
1140	if ( control_id == mIdMediaTimeControlRewind )
1141	{
1142		if ( mSelectedPanel )
1143		{
1144			mSelectedPanel->mMediaSource->setLoop( false );
1145			mSelectedPanel->mMediaSource->start(-2.0f);
1146		};
1147	}
1148	else
1149	if ( control_id == mIdMediaTimeControlFastForward )
1150	{
1151		if ( mSelectedPanel )
1152		{
1153			mSelectedPanel->mMediaSource->setLoop( false );
1154			mSelectedPanel->mMediaSource->start(2.0f);
1155		};
1156	}
1157	else
1158	if ( control_id == mIdMediaBrowserControlBack )
1159	{
1160		if ( mSelectedPanel )
1161			mSelectedPanel->mMediaSource->browse_back();
1162	}
1163	else
1164	if ( control_id == mIdMediaBrowserControlStop )
1165	{
1166		if ( mSelectedPanel )
1167			mSelectedPanel->mMediaSource->browse_stop();
1168	}
1169	else
1170	if ( control_id == mIdMediaBrowserControlForward )
1171	{
1172		if ( mSelectedPanel )
1173			mSelectedPanel->mMediaSource->browse_forward();
1174	}
1175	else
1176	if ( control_id == mIdMediaBrowserControlHome )
1177	{
1178		if ( mSelectedPanel )
1179			mSelectedPanel->mMediaSource->loadURI( mHomeWebUrl );
1180	}
1181	else
1182	if ( control_id == mIdMediaBrowserControlReload )
1183	{
1184		if ( mSelectedPanel )
1185			mSelectedPanel->mMediaSource->browse_reload( true );
1186	}
1187	else
1188	if ( control_id == mIdMediaBrowserControlClearCache )
1189	{
1190		if ( mSelectedPanel )
1191			mSelectedPanel->mMediaSource->clear_cache();
1192	}
1193	else
1194	if ( control_id == mIdMediaBrowserControlClearCookies )
1195	{
1196		if ( mSelectedPanel )
1197			mSelectedPanel->mMediaSource->clear_cookies();
1198	}
1199	else
1200	if ( control_id == mIdMediaBrowserControlEnableCookies )
1201	{
1202		if ( mSelectedPanel )
1203		{
1204			if ( mMediaBrowserControlEnableCookies )
1205			{
1206				mSelectedPanel->mMediaSource->enable_cookies( true );
1207			}
1208			else
1209			{
1210				mSelectedPanel->mMediaSource->enable_cookies( false );
1211			}
1212		};
1213	};
1214}
1215
1216////////////////////////////////////////////////////////////////////////////////
1217//
1218void LLMediaPluginTest::keyboard( int key )
1219{
1220	//if ( key == 'a' || key == 'A' )
1221	//	addMediaPanel( mBookmarks[ rand() % ( mBookmarks.size() - 1 ) + 1 ].second );
1222	//else
1223	//if ( key == 'r' || key == 'R' )
1224	//	remMediaPanel( mSelectedPanel );
1225	//else
1226	//if ( key == 'd' || key == 'D' )
1227	//	dumpPanelInfo();
1228	//else
1229	if ( key == 27 )
1230	{
1231		std::cout << "Application finished - exiting..." << std::endl;
1232		delete this;
1233		exit( 0 );
1234	};
1235
1236	mSelectedPanel->mMediaSource->keyEvent( LLPluginClassMedia::KEY_EVENT_DOWN, key, 0 , LLSD());
1237	mSelectedPanel->mMediaSource->keyEvent( LLPluginClassMedia::KEY_EVENT_UP, key, 0, LLSD());
1238};
1239
1240////////////////////////////////////////////////////////////////////////////////
1241//
1242void LLMediaPluginTest::mouseButton( int button, int state, int x, int y )
1243{
1244	if ( button == GLUT_LEFT_BUTTON )
1245	{
1246		if ( state == GLUT_DOWN )
1247		{
1248			int media_x, media_y, id;
1249			windowPosToTexturePos( x, y, media_x, media_y, id );
1250
1251			if ( mSelectedPanel )
1252				mSelectedPanel->mMediaSource->mouseEvent( LLPluginClassMedia::MOUSE_EVENT_DOWN, 0, media_x, media_y, 0 );
1253		}
1254		else
1255		if ( state == GLUT_UP )
1256		{
1257			int media_x, media_y, id;
1258			windowPosToTexturePos( x, y, media_x, media_y, id );
1259
1260			// only select a panel if we're on a panel
1261			// (HACK: strictly speaking this rules out clicking on
1262			// the origin of a panel but that's very unlikely)
1263			if ( media_x > 0 && media_y > 0 )
1264			{
1265				selectPanelById( id );
1266
1267				if ( mSelectedPanel )
1268					mSelectedPanel->mMediaSource->mouseEvent( LLPluginClassMedia::MOUSE_EVENT_UP, 0, media_x, media_y, 0 );
1269			};
1270		};
1271	};
1272}
1273
1274////////////////////////////////////////////////////////////////////////////////
1275//
1276void LLMediaPluginTest::mousePassive( int x, int y )
1277{
1278	int media_x, media_y, id;
1279	windowPosToTexturePos( x, y, media_x, media_y, id );
1280
1281	if ( mSelectedPanel )
1282		mSelectedPanel->mMediaSource->mouseEvent( LLPluginClassMedia::MOUSE_EVENT_MOVE, 0, media_x, media_y, 0 );
1283}
1284
1285////////////////////////////////////////////////////////////////////////////////
1286//
1287void LLMediaPluginTest::mouseMove( int x, int y )
1288{
1289	int media_x, media_y, id;
1290	windowPosToTexturePos( x, y, media_x, media_y, id );
1291
1292	if ( mSelectedPanel )
1293		mSelectedPanel->mMediaSource->mouseEvent( LLPluginClassMedia::MOUSE_EVENT_MOVE, 0, media_x, media_y, 0 );
1294}
1295
1296////////////////////////////////////////////////////////////////////////////////
1297//
1298void LLMediaPluginTest::makeChrome()
1299{
1300	// IDs used by GLUI
1301	int start_id = 0x1000;
1302
1303	// right side window - geometry manipulators
1304#if __APPLE__
1305	// the Apple GLUT implementation doesn't seem to set the graphic offset of subwindows correctly when they overlap in certain ways.
1306	// Use a separate controls window in this case.
1307	// GLUI window at right containing manipulation controls and other buttons
1308	int x = glutGet(GLUT_WINDOW_X) + glutGet(GLUT_WINDOW_WIDTH) + 4;
1309	int y = glutGet(GLUT_WINDOW_Y);
1310	GLUI* right_glui_window = GLUI_Master.create_glui( "", 0, x, y );
1311#else
1312	GLUI* right_glui_window = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_RIGHT );
1313#endif
1314	mViewRotationCtrl = right_glui_window->add_rotation( "Rotation", mViewRotation );
1315	mViewTranslationCtrl = right_glui_window->add_translation( "Translate", GLUI_TRANSLATION_XY, mViewPos );
1316	mViewTranslationCtrl->set_speed( 0.01f );
1317	mViewScaleCtrl = right_glui_window->add_translation( "Scale", GLUI_TRANSLATION_Z, &mViewPos[ 2 ] );
1318	mViewScaleCtrl->set_speed( 0.05f );
1319	right_glui_window->set_main_gfx_window( mAppWindow );
1320
1321	// right side window - app controls
1322	mIdControlAddPanel = start_id++;
1323	right_glui_window->add_statictext( "" );
1324	right_glui_window->add_separator();
1325	right_glui_window->add_statictext( "" );
1326	right_glui_window->add_button( "Add panel", mIdControlAddPanel, gluiCallbackWrapper );
1327	right_glui_window->add_statictext( "" );
1328	mIdControlRemPanel = start_id++;
1329	right_glui_window->add_button( "Rem panel", mIdControlRemPanel, gluiCallbackWrapper );
1330	right_glui_window->add_statictext( "" );
1331	right_glui_window->add_separator();
1332	right_glui_window->add_statictext( "" );
1333	mIdControlCrashPlugin = start_id++;
1334	right_glui_window->add_button( "Crash plugin", mIdControlCrashPlugin, gluiCallbackWrapper );
1335	mIdControlHangPlugin = start_id++;
1336	right_glui_window->add_button( "Hang plugin", mIdControlHangPlugin, gluiCallbackWrapper );
1337
1338	right_glui_window->add_statictext( "" );
1339	right_glui_window->add_separator();
1340	right_glui_window->add_statictext( "" );
1341	mIdControlExitApp = start_id++;
1342	right_glui_window->add_button( "Exit app", mIdControlExitApp, gluiCallbackWrapper );
1343
1344	//// top window - holds bookmark UI
1345	mIdBookmarks = start_id++;
1346	mSelBookmark = 0;
1347	GLUI* glui_window_top = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_TOP );
1348	mBookmarkList = glui_window_top->add_listbox( "", &mSelBookmark, mIdBookmarks, gluiCallbackWrapper );
1349	// only add the first 50 bookmarks - list can be very long sometimes (30,000+)
1350	// when testing list of media URLs from AGNI for example
1351	for( unsigned int each = 0; each < mBookmarks.size() && each < 50; ++each )
1352		mBookmarkList->add_item( each, const_cast< char* >( mBookmarks[ each ].first.c_str() ) );
1353	glui_window_top->set_main_gfx_window( mAppWindow );
1354
1355	glui_window_top->add_column( false );
1356	mIdUrlEdit = start_id++;
1357	mUrlEdit = glui_window_top->add_edittext( "Url:", GLUI_EDITTEXT_TEXT, 0, mIdUrlEdit, gluiCallbackWrapper );
1358	mUrlEdit->set_w( 600 );
1359	GLUI* glui_window_top2 = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_TOP );
1360	mIdUrlInitHistoryEdit = start_id++;
1361	mUrlInitHistoryEdit = glui_window_top2->add_edittext( "Init History (separate by commas or semicolons):",
1362		GLUI_EDITTEXT_TEXT, 0, mIdUrlInitHistoryEdit, gluiCallbackWrapper );
1363	mUrlInitHistoryEdit->set_w( 800 );
1364
1365	// top window - media controls for "time" media types (e.g. movies)
1366	mGluiMediaTimeControlWindow = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_TOP );
1367	mGluiMediaTimeControlWindow->set_main_gfx_window( mAppWindow );
1368	mIdMediaTimeControlPlay = start_id++;
1369	mGluiMediaTimeControlWindow->add_button( "PLAY", mIdMediaTimeControlPlay, gluiCallbackWrapper );
1370	mGluiMediaTimeControlWindow->add_column( false );
1371	mIdMediaTimeControlLoop = start_id++;
1372	mGluiMediaTimeControlWindow->add_button( "LOOP", mIdMediaTimeControlLoop, gluiCallbackWrapper );
1373	mGluiMediaTimeControlWindow->add_column( false );
1374	mIdMediaTimeControlPause = start_id++;
1375	mGluiMediaTimeControlWindow->add_button( "PAUSE", mIdMediaTimeControlPause, gluiCallbackWrapper );
1376	mGluiMediaTimeControlWindow->add_column( false );
1377
1378	GLUI_Button  *button;
1379	mIdMediaTimeControlRewind = start_id++;
1380	button = mGluiMediaTimeControlWindow->add_button( "<<", mIdMediaTimeControlRewind, gluiCallbackWrapper );
1381	button->set_w(30);
1382	mGluiMediaTimeControlWindow->add_column( false );
1383	mIdMediaTimeControlFastForward = start_id++;
1384	button = mGluiMediaTimeControlWindow->add_button( ">>", mIdMediaTimeControlFastForward, gluiCallbackWrapper );
1385	button->set_w(30);
1386
1387	mGluiMediaTimeControlWindow->add_column( true );
1388
1389	mIdMediaTimeControlStop = start_id++;
1390	mGluiMediaTimeControlWindow->add_button( "STOP", mIdMediaTimeControlStop, gluiCallbackWrapper );
1391	mGluiMediaTimeControlWindow->add_column( false );
1392	mIdMediaTimeControlVolume = start_id++;
1393	GLUI_Spinner* spinner = mGluiMediaTimeControlWindow->add_spinner( "Volume", 2, &mMediaTimeControlVolume, mIdMediaTimeControlVolume, gluiCallbackWrapper);
1394	spinner->set_float_limits( 0, 100 );
1395	mGluiMediaTimeControlWindow->add_column( true );
1396	mIdMediaTimeControlSeekSeconds = start_id++;
1397	spinner = mGluiMediaTimeControlWindow->add_spinner( "", 2, &mMediaTimeControlSeekSeconds, mIdMediaTimeControlSeekSeconds, gluiCallbackWrapper);
1398	spinner->set_float_limits( 0, 200 );
1399	spinner->set_w( 32 );
1400	spinner->set_speed( 0.025f );
1401	mGluiMediaTimeControlWindow->add_column( false );
1402	mIdMediaTimeControlSeek = start_id++;
1403	mGluiMediaTimeControlWindow->add_button( "SEEK", mIdMediaTimeControlSeek, gluiCallbackWrapper );
1404	mGluiMediaTimeControlWindow->add_column( false );
1405
1406
1407	// top window - media controls for "browser" media types (e.g. web browser)
1408	mGluiMediaBrowserControlWindow = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_TOP );
1409	mGluiMediaBrowserControlWindow->set_main_gfx_window( mAppWindow );
1410	mIdMediaBrowserControlBack = start_id++;
1411	mMediaBrowserControlBackButton = mGluiMediaBrowserControlWindow->add_button( "BACK", mIdMediaBrowserControlBack, gluiCallbackWrapper );
1412	mGluiMediaBrowserControlWindow->add_column( false );
1413	mIdMediaBrowserControlStop = start_id++;
1414	mGluiMediaBrowserControlWindow->add_button( "STOP", mIdMediaBrowserControlStop, gluiCallbackWrapper );
1415	mGluiMediaBrowserControlWindow->add_column( false );
1416	mIdMediaBrowserControlForward = start_id++;
1417	mMediaBrowserControlForwardButton = mGluiMediaBrowserControlWindow->add_button( "FORWARD", mIdMediaBrowserControlForward, gluiCallbackWrapper );
1418	mGluiMediaBrowserControlWindow->add_column( false );
1419	mIdMediaBrowserControlHome = start_id++;
1420	mGluiMediaBrowserControlWindow->add_button( "HOME", mIdMediaBrowserControlHome, gluiCallbackWrapper );
1421	mGluiMediaBrowserControlWindow->add_column( false );
1422	mIdMediaBrowserControlReload = start_id++;
1423	mGluiMediaBrowserControlWindow->add_button( "RELOAD", mIdMediaBrowserControlReload, gluiCallbackWrapper );
1424	mGluiMediaBrowserControlWindow->add_column( false );
1425	mIdMediaBrowserControlClearCache = start_id++;
1426	mGluiMediaBrowserControlWindow->add_button( "CLEAR CACHE", mIdMediaBrowserControlClearCache, gluiCallbackWrapper );
1427	mGluiMediaBrowserControlWindow->add_column( false );
1428	mIdMediaBrowserControlClearCookies = start_id++;
1429	mGluiMediaBrowserControlWindow->add_button( "CLEAR COOKIES", mIdMediaBrowserControlClearCookies, gluiCallbackWrapper );
1430	mGluiMediaBrowserControlWindow->add_column( false );
1431	mIdMediaBrowserControlEnableCookies = start_id++;
1432	mMediaBrowserControlEnableCookies = 0;
1433	mGluiMediaBrowserControlWindow->add_checkbox( "Enable Cookies", &mMediaBrowserControlEnableCookies, mIdMediaBrowserControlEnableCookies, gluiCallbackWrapper );
1434
1435	// top window - misc controls
1436	GLUI* glui_window_misc_control = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_TOP );
1437	mIdRandomPanelCount = start_id++;
1438	mRandomPanelCount = 0;
1439	glui_window_misc_control->add_checkbox( "Randomize panel count", &mRandomPanelCount, mIdRandomPanelCount, gluiCallbackWrapper );
1440	glui_window_misc_control->set_main_gfx_window( mAppWindow );
1441	glui_window_misc_control->add_column( true );
1442	mIdRandomBookmarks = start_id++;
1443	mRandomBookmarks = 0;
1444	glui_window_misc_control->add_checkbox( "Randomize bookmarks", &mRandomBookmarks, mIdRandomBookmarks, gluiCallbackWrapper );
1445	glui_window_misc_control->set_main_gfx_window( mAppWindow );
1446	glui_window_misc_control->add_column( true );
1447
1448	mIdDisableTimeout = start_id++;
1449	mDisableTimeout = 0;
1450	glui_window_misc_control->add_checkbox( "Disable plugin timeout", &mDisableTimeout, mIdDisableTimeout, gluiCallbackWrapper );
1451	glui_window_misc_control->set_main_gfx_window( mAppWindow );
1452	glui_window_misc_control->add_column( true );
1453
1454	mIdUsePluginReadThread = start_id++;
1455	mUsePluginReadThread = 0;
1456	glui_window_misc_control->add_checkbox( "Use plugin read thread", &mUsePluginReadThread, mIdUsePluginReadThread, gluiCallbackWrapper );
1457	glui_window_misc_control->set_main_gfx_window( mAppWindow );
1458	glui_window_misc_control->add_column( true );
1459
1460	mIdLargePanelSpacing = start_id++;
1461	mLargePanelSpacing = 0;
1462	glui_window_misc_control->add_checkbox( "Large Panel Spacing", &mLargePanelSpacing, mIdLargePanelSpacing, gluiCallbackWrapper );
1463	glui_window_misc_control->set_main_gfx_window( mAppWindow );
1464	glui_window_misc_control->add_column( true );
1465
1466	// bottom window - status
1467	mBottomGLUIWindow = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_BOTTOM );
1468	mStatusText = mBottomGLUIWindow->add_statictext( "" );
1469	mBottomGLUIWindow->set_main_gfx_window( mAppWindow );
1470}
1471
1472////////////////////////////////////////////////////////////////////////////////
1473//
1474void LLMediaPluginTest::resetView()
1475{
1476	mViewRotationCtrl->reset();
1477
1478	mViewScaleCtrl->set_x( 0.0f );
1479	mViewScaleCtrl->set_y( 0.0f );
1480	mViewScaleCtrl->set_z( 3.0f );
1481
1482	mViewTranslationCtrl->set_x( 0.0f );
1483	mViewTranslationCtrl->set_y( 0.0f );
1484	mViewTranslationCtrl->set_z( 0.0f );
1485}
1486
1487////////////////////////////////////////////////////////////////////////////////
1488//
1489void LLMediaPluginTest::makePickTexture( int id, GLuint* texture_handle, unsigned char** texture_pixels )
1490{
1491	int pick_texture_width = 1024;
1492	int pick_texture_height = 1024;
1493	int pick_texture_depth = 3;
1494	unsigned char* ptr = new unsigned char[ pick_texture_width * pick_texture_height * pick_texture_depth ];
1495	for( int y = 0; y < pick_texture_height; ++y )
1496	{
1497		for( int x = 0; x < pick_texture_width * pick_texture_depth ; x += pick_texture_depth )
1498		{
1499			unsigned long bits = 0L;
1500			bits |= ( id << 20 ) | ( y << 10 ) | ( x / 3 );
1501			unsigned char r_component = ( bits >> 16 ) & 0xff;
1502			unsigned char g_component = ( bits >> 8 ) & 0xff;
1503			unsigned char b_component = bits & 0xff;
1504
1505			ptr[ y * pick_texture_width * pick_texture_depth + x + 0 ] = r_component;
1506			ptr[ y * pick_texture_width * pick_texture_depth + x + 1 ] = g_component;
1507			ptr[ y * pick_texture_width * pick_texture_depth + x + 2 ] = b_component;
1508		};
1509	};
1510
1511	glGenTextures( 1, texture_handle );
1512
1513	checkGLError("glGenTextures");
1514	std::cout << "glGenTextures returned " << *texture_handle << std::endl;
1515
1516	bindTexture( *texture_handle );
1517	glTexImage2D( GL_TEXTURE_2D, 0,
1518					GL_RGB,
1519						pick_texture_width, pick_texture_height,
1520							0, GL_RGB, GL_UNSIGNED_BYTE, ptr );
1521
1522	*texture_pixels = ptr;
1523}
1524
1525////////////////////////////////////////////////////////////////////////////////
1526//
1527std::string LLMediaPluginTest::mimeTypeFromUrl( std::string& url )
1528{
1529	// default to web
1530	std::string mime_type = "text/html";
1531
1532	// we may need a more advanced MIME type accessor later :-)
1533	if ( url.find( ".mov" ) != std::string::npos )	// Movies
1534		mime_type = "video/quicktime";
1535	else
1536	if ( url.find( ".txt" ) != std::string::npos )	// Apple Text descriptors
1537		mime_type = "video/quicktime";
1538	else
1539	if ( url.find( ".mp3" ) != std::string::npos )	// Apple Text descriptors
1540		mime_type = "video/quicktime";
1541	else
1542	if ( url.find( "example://" ) != std::string::npos )	// Example plugin
1543		mime_type = "example/example";
1544
1545	return mime_type;
1546}
1547
1548////////////////////////////////////////////////////////////////////////////////
1549//
1550std::string LLMediaPluginTest::pluginNameFromMimeType( std::string& mime_type )
1551{
1552#if LL_DARWIN
1553	std::string plugin_name( "media_plugin_null.dylib" );
1554	if ( mime_type == "video/quicktime" )
1555		plugin_name = "media_plugin_quicktime.dylib";
1556	else
1557	if ( mime_type == "text/html" )
1558		plugin_name = "media_plugin_webkit.dylib";
1559
1560#elif LL_WINDOWS
1561	std::string plugin_name( "media_plugin_null.dll" );
1562
1563	if ( mime_type == "video/quicktime" )
1564		plugin_name = "media_plugin_quicktime.dll";
1565	else
1566	if ( mime_type == "text/html" )
1567		plugin_name = "media_plugin_webkit.dll";
1568	else
1569	if ( mime_type == "example/example" )
1570		plugin_name = "media_plugin_example.dll";
1571
1572#elif LL_LINUX
1573	std::string plugin_name( "libmedia_plugin_null.so" );
1574
1575	if ( mime_type == "video/quicktime" )
1576		plugin_name = "libmedia_plugin_quicktime.so";
1577	else
1578	if ( mime_type == "text/html" )
1579		plugin_name = "libmedia_plugin_webkit.so";
1580#endif
1581	return plugin_name;
1582}
1583
1584/////////…

Large files files are truncated, but you can click here to view the full file