PageRenderTime 62ms CodeModel.GetById 16ms 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
Possible License(s): LGPL-2.1
  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. ////////////////////////////////////////////////////////////////////////////////
  1398. //
  1399. mediaPanel* LLMediaPluginTest::addMediaPanel( std::string url )
  1400. {
  1401. // Get the plugin filename using the URL
  1402. std::string mime_type = mimeTypeFromUrl( url );
  1403. std::string plugin_name = pluginNameFromMimeType( mime_type );
  1404. // create a random size for the new media
  1405. int media_width;
  1406. int media_height;
  1407. getRandomMediaSize( media_width, media_height, mime_type );
  1408. // make a new plugin
  1409. LLPluginClassMedia* media_source = new LLPluginClassMedia(this);
  1410. // tell the plugin what size we asked for
  1411. media_source->setSize( media_width, media_height );
  1412. // Use the launcher start and initialize the plugin
  1413. #if LL_DARWIN || LL_LINUX
  1414. std::string launcher_name( "SLPlugin" );
  1415. #elif LL_WINDOWS
  1416. std::string launcher_name( "SLPlugin.exe" );
  1417. #endif
  1418. // for this test app, use the cwd as the user data path (ugh).
  1419. #if LL_WINDOWS
  1420. std::string user_data_path = ".\\";
  1421. #else
  1422. char cwd[ FILENAME_MAX ];
  1423. if (NULL == getcwd( cwd, FILENAME_MAX - 1 ))
  1424. {
  1425. std::cerr << "Couldn't get cwd - probably too long - failing to init." << std::endl;
  1426. return NULL;
  1427. }
  1428. std::string user_data_path = std::string( cwd ) + "/";
  1429. #endif
  1430. media_source->setUserDataPath(user_data_path);
  1431. media_source->init( launcher_name, user_data_path, plugin_name, false );
  1432. media_source->setDisableTimeout(mDisableTimeout);
  1433. // make a new panel and save parameters
  1434. mediaPanel* panel = new mediaPanel;
  1435. panel->mMediaSource = media_source;
  1436. panel->mStartUrl = url;
  1437. panel->mMimeType = mime_type;
  1438. panel->mMediaWidth = media_width;
  1439. panel->mMediaHeight = media_height;
  1440. panel->mTextureWidth = 0;
  1441. panel->mTextureHeight = 0;
  1442. panel->mTextureScaleX = 0;
  1443. panel->mTextureScaleY = 0;
  1444. panel->mMediaTextureHandle = 0;
  1445. panel->mPickTextureHandle = 0;
  1446. panel->mAppTextureCoordsOpenGL = false; // really need an 'undefined' state here too
  1447. panel->mReadyToRender = false;
  1448. // look through current media panels to find an unused index number
  1449. bool id_exists = true;
  1450. for( int nid = 0; nid < mMaxPanels; ++nid )
  1451. {
  1452. // does this id exist already?
  1453. id_exists = false;
  1454. for( int pid = 0; pid < (int)mMediaPanels.size(); ++pid )
  1455. {
  1456. if ( nid == mMediaPanels[ pid ]->mId )
  1457. {
  1458. id_exists = true;
  1459. break;
  1460. };
  1461. };
  1462. // id wasn't found so we can use it
  1463. if ( ! id_exists )
  1464. {
  1465. panel->mId = nid;
  1466. break;
  1467. };
  1468. };
  1469. // if we get here and this flag is set, there is no room for any more panels
  1470. if ( id_exists )
  1471. {
  1472. std::cout << "No room for any more panels" << std::endl;
  1473. }
  1474. else
  1475. {
  1476. // now we have the ID we can use it to make the
  1477. // pick texture (id is baked into texture pixels)
  1478. makePickTexture( panel->mId, &panel->mPickTextureHandle, &panel->mPickTexturePixels );
  1479. // save this in the list of panels
  1480. mMediaPanels.push_back( panel );
  1481. // select the panel that was just created
  1482. selectPanel( panel );
  1483. // load and start the URL
  1484. panel->mMediaSource->loadURI( url );
  1485. panel->mMediaSource->start();
  1486. std::cout << "Adding new media panel for " << url << "(" << media_width << "x" << media_height << ") with index " << panel->mId << " - total panels = " << mMediaPanels.size() << std::endl;
  1487. }
  1488. return panel;
  1489. }
  1490. ////////////////////////////////////////////////////////////////////////////////
  1491. //
  1492. void LLMediaPluginTest::updateMediaPanel( mediaPanel* panel )
  1493. {
  1494. // checkGLError("LLMediaPluginTest::updateMediaPanel");
  1495. if ( ! panel )
  1496. return;
  1497. if(!panel->mMediaSource || !panel->mMediaSource->textureValid())
  1498. {
  1499. panel->mReadyToRender = false;
  1500. return;
  1501. }
  1502. // take a reference copy of the plugin values since they
  1503. // might change during this lifetime of this function
  1504. int plugin_media_width = panel->mMediaSource->getWidth();
  1505. int plugin_media_height = panel->mMediaSource->getHeight();
  1506. int plugin_texture_width = panel->mMediaSource->getBitsWidth();
  1507. int plugin_texture_height = panel->mMediaSource->getBitsHeight();
  1508. // If the texture isn't created or the media or texture dimensions changed AND
  1509. // the sizes are valid then we need to delete the old media texture (if necessary)
  1510. // then make a new one.
  1511. if ((panel->mMediaTextureHandle == 0 ||
  1512. panel->mMediaWidth != plugin_media_width ||
  1513. panel->mMediaHeight != plugin_media_height ||
  1514. panel->mTextureWidth != plugin_texture_width ||
  1515. panel->mTextureHeight != plugin_texture_height) &&
  1516. ( plugin_media_width > 0 && plugin_media_height > 0 &&
  1517. plugin_texture_width > 0 && plugin_texture_height > 0 ) )
  1518. {
  1519. std::cout << "Valid media size (" << plugin_media_width << " x " << plugin_media_height
  1520. << ") and texture size (" << plugin_texture_width << " x " << plugin_texture_height
  1521. << ") for panel with ID=" << panel->mId << " - making texture" << std::endl;
  1522. // delete old GL texture
  1523. if ( isTexture( panel->mMediaTextureHandle ) )
  1524. {
  1525. std::cerr << "updateMediaPanel: deleting texture " << panel->mMediaTextureHandle << std::endl;
  1526. glDeleteTextures( 1, &panel->mMediaTextureHandle );
  1527. panel->mMediaTextureHandle = 0;
  1528. }
  1529. std::cerr << "before: pick texture is " << panel->mPickTextureHandle << ", media texture is " << panel->mMediaTextureHandle << std::endl;
  1530. // make a GL texture based on the dimensions the plugin told us
  1531. GLuint new_texture = 0;
  1532. glGenTextures( 1, &new_texture );
  1533. checkGLError("glGenTextures");
  1534. std::cout << "glGenTextures returned " << new_texture << std::endl;
  1535. panel->mMediaTextureHandle = new_texture;
  1536. bindTexture( panel->mMediaTextureHandle );
  1537. std::cout << "Setting texture size to " << plugin_texture_width << " x " << plugin_texture_height << std::endl;
  1538. glTexImage2D( GL_TEXTURE_2D, 0,
  1539. GL_RGB,
  1540. plugin_texture_width, plugin_texture_height,
  1541. 0, GL_RGB, GL_UNSIGNED_BYTE,
  1542. 0 );
  1543. std::cerr << "after: pick texture is " << panel->mPickTextureHandle << ", media texture is " << panel->mMediaTextureHandle << std::endl;
  1544. };
  1545. // update our record of the media and texture dimensions
  1546. // NOTE: do this after we we check for sizes changes
  1547. panel->mMediaWidth = plugin_media_width;
  1548. panel->mMediaHeight = plugin_media_height;
  1549. panel->mTextureWidth = plugin_texture_width;
  1550. panel->mTextureHeight = plugin_texture_height;
  1551. if ( plugin_texture_width > 0 )
  1552. {
  1553. panel->mTextureScaleX = (double)panel->mMediaWidth / (double)panel->mTextureWidth;
  1554. };
  1555. if ( plugin_texture_height > 0 )
  1556. {
  1557. panel->mTextureScaleY = (double)panel->mMediaHeight / (double)panel->mTextureHeight;
  1558. };
  1559. // update the flag which tells us if the media source uses OprnGL coords or not.
  1560. panel->mAppTextureCoordsOpenGL = panel->mMediaSource->getTextureCoordsOpenGL();
  1561. // Check to see if we have enough to render this panel.
  1562. // If we do, set a flag that the display functions use so
  1563. // they only render a panel with media if it's ready.
  1564. if ( panel->mMediaWidth < 0 ||
  1565. panel->mMediaHeight < 0 ||
  1566. panel->mTextureWidth < 1 ||
  1567. panel->mTextureHeight < 1 ||
  1568. panel->mMediaTextureHandle == 0 )
  1569. {
  1570. panel->mReadyToRender = false;
  1571. };
  1572. }
  1573. ////////////////////////////////////////////////////////////////////////////////
  1574. //
  1575. mediaPanel* LLMediaPluginTest::replaceMediaPanel( mediaPanel* panel, std::string url )
  1576. {
  1577. // no media panels so we can't change anything - have to add
  1578. if ( mMediaPanels.size() == 0 )
  1579. return NULL;
  1580. // sanity check
  1581. if ( ! panel )
  1582. return NULL;
  1583. int index;
  1584. for(index = 0; index < (int)mMediaPanels.size(); index++)
  1585. {
  1586. if(mMediaPanels[index] == panel)
  1587. break;
  1588. }
  1589. if(index >= (int)mMediaPanels.size())
  1590. {
  1591. // panel isn't in mMediaPanels
  1592. return NULL;
  1593. }
  1594. std::cout << "Replacing media panel with index " << panel->mId << std::endl;
  1595. int panel_id = panel->mId;
  1596. if(mSelectedPanel == panel)
  1597. mSelectedPanel = NULL;
  1598. delete panel;
  1599. // Get the plugin filename using the URL
  1600. std::string mime_type = mimeTypeFromUrl( url );
  1601. std::string plugin_name = pluginNameFromMimeType( mime_type );
  1602. // create a random size for the new media
  1603. int media_width;
  1604. int media_height;
  1605. getRandomMediaSize( media_width, media_height, mime_type );
  1606. // make a new plugin
  1607. LLPluginClassMedia* media_source = new LLPluginClassMedia(this);
  1608. // tell the plugin what size we asked for
  1609. media_source->setSize( media_width, media_height );
  1610. // Use the launcher start and initialize the plugin
  1611. #if LL_DARWIN || LL_LINUX
  1612. std::string launcher_name( "SLPlugin" );
  1613. #elif LL_WINDOWS
  1614. std::string launcher_name( "SLPlugin.exe" );
  1615. #endif
  1616. // for this test app, use the cwd as the user data path (ugh).
  1617. #if LL_WINDOWS
  1618. std::string user_data_path = ".\\";
  1619. #else
  1620. char cwd[ FILENAME_MAX ];
  1621. if (NULL == getcwd( cwd, FILENAME_MAX - 1 ))
  1622. {
  1623. std::cerr << "Couldn't get cwd - probably too long - failing to init." << std::endl;
  1624. return NULL;
  1625. }
  1626. std::string user_data_path = std::string( cwd ) + "/";
  1627. #endif
  1628. media_source->setUserDataPath(user_data_path);
  1629. media_source->init( launcher_name, user_data_path, plugin_name, false );
  1630. media_source->setDisableTimeout(mDisableTimeout);
  1631. // make a new panel and save parameters
  1632. panel = new mediaPanel;
  1633. panel->mMediaSource = media_source;
  1634. panel->mStartUrl = url;
  1635. panel->mMimeType = mime_type;
  1636. panel->mMediaWidth = media_width;
  1637. panel->mMediaHeight = media_height;
  1638. panel->mTextureWidth = 0;
  1639. panel->mTextureHeight = 0;
  1640. panel->mTextureScaleX = 0;
  1641. panel->mTextureScaleY = 0;
  1642. panel->mMediaTextureHandle = 0;
  1643. panel->mPickTextureHandle = 0;
  1644. panel->mAppTextureCoordsOpenGL = false; // really need an 'undefined' state here too
  1645. panel->mReadyToRender = false;
  1646. panel->mId = panel_id;
  1647. // Replace the entry in the panels array
  1648. mMediaPanels[index] = panel;
  1649. // now we have the ID we can use it to make the
  1650. // pick texture (id is baked into texture pixels)
  1651. makePickTexture( panel->mId, &panel->mPickTextureHandle, &panel->mPickTexturePixels );
  1652. // select the panel that was just created
  1653. selectPanel( panel );
  1654. // load and start the URL
  1655. panel->mMediaSource->loadURI( url );
  1656. panel->mMediaSource->start();
  1657. return panel;
  1658. }
  1659. ////////////////////////////////////////////////////////////////////////////////
  1660. //
  1661. void LLMediaPluginTest::getRandomMediaSize( int& width, int& height, std::string mime_type )
  1662. {
  1663. // Make a new media source with a random size which we'll either
  1664. // directly or the media plugin will tell us what it wants later.
  1665. // Use a random size so we can test support for weird media sizes.
  1666. // (Almost everything else will get filled in later once the
  1667. // plugin responds)
  1668. // NB. Do we need to enforce that width is on 4 pixel boundary?
  1669. width = ( ( rand() % 170 ) + 30 ) * 4;
  1670. height = ( ( rand() % 170 ) + 30 ) * 4;
  1671. // adjust this random size if it's a browser so we get
  1672. // a more useful size for testing..
  1673. if ( mime_type == "text/html" || mime_type == "example/example" )
  1674. {
  1675. width = ( ( rand() % 100 ) + 100 ) * 4;
  1676. height = ( width * ( ( rand() % 400 ) + 1000 ) ) / 1000;
  1677. };
  1678. }
  1679. ////////////////////////////////////////////////////////////////////////////////
  1680. //
  1681. void LLMediaPluginTest::remMediaPanel( mediaPanel* panel )
  1682. {
  1683. // always leave one panel
  1684. if ( mMediaPanels.size() == 1 )
  1685. return;
  1686. // sanity check - don't think this can happen but see above for a case where it might...
  1687. if ( ! panel )
  1688. return;
  1689. std::cout << "Removing media panel with index " << panel->mId << " - total panels = " << mMediaPanels.size() - 1 << std::endl;
  1690. if(mSelectedPanel == panel)
  1691. mSelectedPanel = NULL;
  1692. delete panel;
  1693. // remove from storage list
  1694. for( int i = 0; i < (int)mMediaPanels.size(); ++i )
  1695. {
  1696. if ( mMediaPanels[ i ] == panel )
  1697. {
  1698. mMediaPanels.erase( mMediaPanels.begin() + i );
  1699. break;
  1700. };
  1701. };
  1702. // select the first panel
  1703. selectPanel( mMediaPanels[ 0 ] );
  1704. }
  1705. ////////////////////////////////////////////////////////////////////////////////
  1706. //
  1707. void LLMediaPluginTest::updateStatusBar()
  1708. {
  1709. if ( ! mSelectedPanel )
  1710. return;
  1711. // cache results - this is a very slow function
  1712. static int cached_id = -1;
  1713. static int cached_media_width = -1;
  1714. static int cached_media_height = -1;
  1715. static int cached_texture_width = -1;
  1716. static int cached_texture_height = -1;
  1717. static bool cached_supports_browser_media = true;
  1718. static bool cached_supports_time_media = false;
  1719. static int cached_movie_time = -1;
  1720. static GLfloat cached_distance = -1.0f;
  1721. static std::string cached_plugin_version = "";
  1722. if (
  1723. cached_id == mSelectedPanel->mId &&
  1724. cached_media_width == mSelectedPanel->mMediaWidth &&
  1725. cached_media_height == mSelectedPanel->mMediaHeight &&
  1726. cached_texture_width == mSelectedPanel->mTextureWidth &&
  1727. cached_texture_height == mSelectedPanel->mTextureHeight &&
  1728. cached_supports_browser_media == mSelectedPanel->mMediaSource->pluginSupportsMediaBrowser() &&
  1729. cached_supports_time_media == mSelectedPanel->mMediaSource->pluginSupportsMediaTime() &&
  1730. cached_plugin_version == mSelectedPanel->mMediaSource->getPluginVersion() &&
  1731. cached_movie_time == (int)mSelectedPanel->mMediaSource->getCurrentTime() &&
  1732. cached_distance == mDistanceCameraToSelectedGeometry
  1733. )
  1734. {
  1735. // nothing changed so don't spend time here
  1736. return;
  1737. };
  1738. std::ostringstream stream( "" );
  1739. stream.str( "" );
  1740. stream.clear();
  1741. stream << "Id: ";
  1742. stream << std::setw( 2 ) << std::setfill( '0' );
  1743. stream << mSelectedPanel->mId;
  1744. stream << " | ";
  1745. stream << "Media: ";
  1746. stream << std::setw( 3 ) << std::setfill( '0' );
  1747. stream << mSelectedPanel->mMediaWidth;
  1748. stream << " x ";
  1749. stream << std::setw( 3 ) << std::setfill( '0' );
  1750. stream << mSelectedPanel->mMediaHeight;
  1751. stream << " | ";
  1752. stream << "Texture: ";
  1753. stream << std::setw( 4 ) << std::setfill( '0' );
  1754. stream << mSelectedPanel->mTextureWidth;
  1755. stream << " x ";
  1756. stream << std::setw( 4 ) << std::setfill( '0' );
  1757. stream << mSelectedPanel->mTextureHeight;
  1758. stream << " | ";
  1759. stream << "Distance: ";
  1760. stream << std::setw( 6 );
  1761. stream << std::setprecision( 3 );
  1762. stream << std::setprecision( 3 );
  1763. stream << mDistanceCameraToSelectedGeometry;
  1764. stream << " | ";
  1765. if ( mSelectedPanel->mMediaSource->pluginSupportsMediaBrowser() )
  1766. stream << "BROWSER";
  1767. else
  1768. if ( mSelectedPanel->mMediaSource->pluginSupportsMediaTime() )
  1769. stream << "TIME ";
  1770. stream << " | ";
  1771. stream << mSelectedPanel->mMediaSource->getPluginVersion();
  1772. stream << " | ";
  1773. if ( mSelectedPanel->mMediaSource->pluginSupportsMediaTime() )
  1774. {
  1775. stream << std::setw( 3 ) << std::setfill( '0' );
  1776. stream << (int)mSelectedPanel->mMediaSource->getCurrentTime();
  1777. stream << " / ";
  1778. stream << std::setw( 3 ) << std::setfill( '0' );
  1779. stream << (int)mSelectedPanel->mMediaSource->getDuration();
  1780. stream << " @ ";
  1781. stream << (int)mSelectedPanel->mMediaSource->getCurrentPlayRate();
  1782. stream << " | ";
  1783. };
  1784. glutSetWindow( mBottomGLUIWindow->get_glut_window_id() );
  1785. mStatusText->set_text( const_cast< char*>( stream.str().c_str() ) );
  1786. glutSetWindow( mAppWindow );
  1787. // caching
  1788. cached_id = mSelectedPanel->mId;
  1789. cached_media_width = mSelectedPanel->mMediaWidth;
  1790. cached_media_height = mSelectedPanel->mMediaHeight;
  1791. cached_texture_width = mSelectedPanel->mTextureWidth;
  1792. cached_texture_height = mSelectedPanel->mTextureHeight;
  1793. cached_supports_browser_media = mSelectedPanel->mMediaSource->pluginSupportsMediaBrowser();
  1794. cached_supports_time_media = mSelectedPanel->mMediaSource->pluginSupportsMediaTime();
  1795. cached_plugin_version = mSelectedPanel->mMediaSource->getPluginVersion();
  1796. cached_movie_time = (int)mSelectedPanel->mMediaSource->getCurrentTime();
  1797. }
  1798. ////////////////////////////////////////////////////////////////////////////////
  1799. //
  1800. void LLMediaPluginTest::dumpPanelInfo()
  1801. {
  1802. std::cout << std::endl << "===== Media Panels =====" << std::endl;
  1803. for( int i = 0; i < (int)mMediaPanels.size(); ++i )
  1804. {
  1805. std::cout << std::setw( 2 )