/indra/test_apps/llplugintest/llmediaplugintest.cpp

https://bitbucket.org/lindenlab/viewer-beta/ · C++ · 2066 lines · 1501 code · 261 blank · 304 comment · 292 complexity · 3e3a1c057ed9ed7a8b0717f5ee1c9d14 MD5 · raw file

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