aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/test_apps/llplugintest/llmediaplugintest.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--linden/indra/test_apps/llplugintest/llmediaplugintest.cpp2179
1 files changed, 2179 insertions, 0 deletions
diff --git a/linden/indra/test_apps/llplugintest/llmediaplugintest.cpp b/linden/indra/test_apps/llplugintest/llmediaplugintest.cpp
new file mode 100644
index 0000000..27cb52a
--- /dev/null
+++ b/linden/indra/test_apps/llplugintest/llmediaplugintest.cpp
@@ -0,0 +1,2179 @@
1/**
2 * @file LLMediaPluginTest.cpp
3 * @brief Primary test application for LLMedia (Separate Process) Plugin system
4 *
5 * $LicenseInfo:firstyear=2008&license=viewergpl$
6 *
7 * Copyright (c) 2009, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlife.com/developers/opensource/gplv2
16 *
17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlife.com/developers/opensource/flossexception
21 *
22 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above,
24 * and agree to abide by those obligations.
25 *
26 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
27 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
28 * COMPLETENESS OR PERFORMANCE.
29 * $/LicenseInfo$
30 */
31
32#include "linden_common.h"
33#include "indra_constants.h"
34
35#include "llapr.h"
36#include "llerrorcontrol.h"
37
38#include <math.h>
39#include <iomanip>
40#include <sstream>
41#include <ctime>
42
43#include "llmediaplugintest.h"
44
45#if __APPLE__
46 #include <GLUT/glut.h>
47 #include <CoreFoundation/CoreFoundation.h>
48#else
49 #define FREEGLUT_STATIC
50 #include "GL/freeglut.h"
51 #define GLUI_FREEGLUT
52#endif
53
54#if LL_WINDOWS
55#pragma warning(disable: 4263)
56#pragma warning(disable: 4264)
57#endif
58#include "glui.h"
59
60
61LLMediaPluginTest* gApplication = 0;
62static void gluiCallbackWrapper( int control_id );
63
64////////////////////////////////////////////////////////////////////////////////
65//
66static bool isTexture( GLuint texture )
67{
68 bool result = false;
69
70 // glIsTexture will sometimes return false for real textures... do this instead.
71 if(texture != 0)
72 result = true;
73
74 return result;
75}
76
77////////////////////////////////////////////////////////////////////////////////
78//
79mediaPanel::mediaPanel()
80{
81 mMediaTextureHandle = 0;
82 mPickTextureHandle = 0;
83 mMediaSource = NULL;
84 mPickTexturePixels = NULL;
85}
86
87////////////////////////////////////////////////////////////////////////////////
88//
89mediaPanel::~mediaPanel()
90{
91 // delete OpenGL texture handles
92 if ( isTexture( mPickTextureHandle ) )
93 {
94 std::cerr << "remMediaPanel: deleting pick texture " << mPickTextureHandle << std::endl;
95 glDeleteTextures( 1, &mPickTextureHandle );
96 mPickTextureHandle = 0;
97 }
98
99 if ( isTexture( mMediaTextureHandle ) )
100 {
101 std::cerr << "remMediaPanel: deleting media texture " << mMediaTextureHandle << std::endl;
102 glDeleteTextures( 1, &mMediaTextureHandle );
103 mMediaTextureHandle = 0;
104 }
105
106 if(mPickTexturePixels)
107 {
108 delete mPickTexturePixels;
109 }
110
111 if(mMediaSource)
112 {
113 delete mMediaSource;
114 }
115
116}
117
118////////////////////////////////////////////////////////////////////////////////
119//
120LLMediaPluginTest::LLMediaPluginTest( int app_window, int window_width, int window_height ) :
121 mVersionMajor( 2 ),
122 mVersionMinor( 0 ),
123 mVersionPatch( 0 ),
124 mMaxPanels( 25 ),
125 mViewportAspect( 0 ),
126 mAppWindow( app_window ),
127 mCurMouseX( 0 ),
128 mCurMouseY( 0 ),
129 mFuzzyMedia( true ),
130 mSelectedPanel( 0 ),
131 mMediaBrowserControlEnableCookies( 0 ),
132 mMediaBrowserControlBackButton( 0 ),
133 mMediaBrowserControlForwardButton( 0 ),
134 mMediaTimeControlVolume( 100 ),
135 mMediaTimeControlSeekSeconds( 0 ),
136 mGluiMediaTimeControlWindowFlag( true ),
137 mGluiMediaBrowserControlWindowFlag( true ),
138 mMediaBrowserControlBackButtonFlag( true ),
139 mMediaBrowserControlForwardButtonFlag( true ),
140 mHomeWebUrl( "http://www.google.com/" )
141{
142 // debugging spam
143 std::cout << std::endl << " GLUT version: " << "3.7.6" << std::endl; // no way to get real version from GLUT
144 std::cout << std::endl << " GLUI version: " << GLUI_Master.get_version() << std::endl;
145 std::cout << std::endl << "Media Plugin Test version: " << mVersionMajor << "." << mVersionMinor << "." << mVersionPatch << std::endl;
146
147 // bookmark title
148 mBookmarks.push_back( std::pair< std::string, std::string >( "--- Bookmarks ---", "" ) );
149
150 // insert hardcoded URLs here as required for testing
151 //mBookmarks.push_back( std::pair< std::string, std::string >( "description", "url" ) );
152
153 // read bookmarks from file.
154 // note: uses command in ./CmakeLists.txt which copies bookmmarks file from source directory
155 // to app directory (WITHOUT build configuration dir) (this is cwd in Windows within MSVC)
156 // For example, test_apps\llplugintest and not test_apps\llplugintest\Release
157 // This may need to be changed for Mac/Linux builds.
158 // See https://jira.lindenlab.com/browse/DEV-31350 for large list of media URLs from AGNI
159 const std::string bookmarks_filename( "bookmarks.txt" );
160 std::ifstream file_handle( bookmarks_filename.c_str() );
161 if ( file_handle.is_open() )
162 {
163 std::cout << "Reading bookmarks for test" << std::endl;
164 while( ! file_handle.eof() )
165 {
166 std::string line;
167 std::getline( file_handle, line );
168 if ( file_handle.eof() )
169 break;
170
171 if ( line.substr( 0, 1 ) != "#" )
172 {
173 size_t comma_pos = line.find_first_of( ',' );
174 if ( comma_pos != std::string::npos )
175 {
176 std::string description = line.substr( 0, comma_pos );
177 std::string url = line.substr( comma_pos + 1 );
178 mBookmarks.push_back( std::pair< std::string, std::string >( description, url ) );
179 }
180 else
181 {
182 mBookmarks.push_back( std::pair< std::string, std::string >( line, line ) );
183 };
184 };
185 };
186 std::cout << "Read " << mBookmarks.size() << " bookmarks" << std::endl;
187 }
188 else
189 {
190 std::cout << "Unable to read bookmarks from file: " << bookmarks_filename << std::endl;
191 };
192
193 // initialize linden lab APR module
194 ll_init_apr();
195
196 // Set up llerror logging
197 {
198 LLError::initForApplication(".");
199 LLError::setDefaultLevel(LLError::LEVEL_INFO);
200 //LLError::setTagLevel("Plugin", LLError::LEVEL_DEBUG);
201 }
202
203 // lots of randomness in this app
204 srand( ( unsigned int )time( 0 ) );
205
206 // build GUI
207 makeChrome();
208
209 // OpenGL initialilzation
210 glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
211 glClearDepth( 1.0f );
212 glEnable( GL_DEPTH_TEST );
213 glEnable( GL_COLOR_MATERIAL );
214 glColorMaterial( GL_FRONT, GL_AMBIENT_AND_DIFFUSE );
215 glDepthFunc( GL_LEQUAL );
216 glEnable( GL_TEXTURE_2D );
217 glDisable( GL_BLEND );
218 glColor3f( 1.0f, 1.0f, 1.0f );
219 glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
220 glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
221
222 // start with a sane view
223 resetView();
224
225 // initial media panel
226 const int num_initial_panels = 1;
227 for( int i = 0; i < num_initial_panels; ++i )
228 {
229 //addMediaPanel( mBookmarks[ rand() % ( mBookmarks.size() - 1 ) + 1 ].second );
230 addMediaPanel( mHomeWebUrl );
231 };
232}
233
234////////////////////////////////////////////////////////////////////////////////
235//
236LLMediaPluginTest::~LLMediaPluginTest()
237{
238 // delete all media panels
239 for( int i = 0; i < (int)mMediaPanels.size(); ++i )
240 {
241 remMediaPanel( mMediaPanels[ i ] );
242 };
243}
244
245////////////////////////////////////////////////////////////////////////////////
246//
247void LLMediaPluginTest::reshape( int width, int height )
248{
249 // update viewport (the active window inside the chrome)
250 int viewport_x, viewport_y;
251 int viewport_height, viewport_width;
252 GLUI_Master.get_viewport_area( &viewport_x, &viewport_y, &viewport_width, &viewport_height );
253 mViewportAspect = (float)( viewport_width ) / (float)( viewport_height );
254 glViewport( viewport_x, viewport_y, viewport_width, viewport_height );
255
256 // save these as we'll need them later
257 mWindowWidth = width;
258 mWindowHeight = height;
259
260 // adjust size of URL bar so it doesn't get clipped
261 mUrlEdit->set_w( mWindowWidth - 360 );
262
263 // GLUI requires this
264 if ( glutGetWindow() != mAppWindow )
265 glutSetWindow( mAppWindow );
266
267 // trigger re-display
268 glutPostRedisplay();
269};
270
271////////////////////////////////////////////////////////////////////////////////
272//
273void LLMediaPluginTest::bindTexture(GLuint texture, GLint row_length, GLint alignment)
274{
275 glEnable( GL_TEXTURE_2D );
276
277 glBindTexture( GL_TEXTURE_2D, texture );
278 glPixelStorei( GL_UNPACK_ROW_LENGTH, row_length );
279 glPixelStorei( GL_UNPACK_ALIGNMENT, alignment );
280}
281
282////////////////////////////////////////////////////////////////////////////////
283//
284bool LLMediaPluginTest::checkGLError(const char *name)
285{
286 bool result = false;
287 GLenum error = glGetError();
288
289 if(error != GL_NO_ERROR)
290 {
291 // For some reason, glGenTextures is returning GL_INVALID_VALUE...
292 std::cout << name << " ERROR 0x" << std::hex << error << std::dec << std::endl;
293 result = true;
294 }
295
296 return result;
297}
298
299////////////////////////////////////////////////////////////////////////////////
300//
301void LLMediaPluginTest::drawGeometry( int panel )
302{
303 // texture coordinates for each panel
304 GLfloat non_opengl_texture_coords[ 8 ] = { 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f };
305 GLfloat opengl_texture_coords[ 8 ] = { 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f };
306
307 GLfloat *texture_coords = mMediaPanels[ panel ]->mAppTextureCoordsOpenGL?opengl_texture_coords:non_opengl_texture_coords;
308
309 // base coordinates for each panel
310 GLfloat base_vertex_pos[ 8 ] = { 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f };
311
312 // calculate posiitons
313 const int num_panels = (int)mMediaPanels.size();
314 const int num_rows = (int)sqrt( (float)num_panels );
315 const int num_cols = num_panels / num_rows;
316 const int panel_x = ( panel / num_rows );
317 const int panel_y = ( panel % num_rows );
318
319 const float spacing = 0.1f;
320 const GLfloat offset_x = num_cols * ( 1.0 + spacing ) / 2;
321 const GLfloat offset_y = num_rows * ( 1.0 + spacing ) / 2;
322
323 // Adjust for media aspect ratios
324 {
325 float aspect = 1.0f;
326
327 if(mMediaPanels[ panel ]->mMediaHeight != 0)
328 {
329 aspect = (float)mMediaPanels[ panel ]->mMediaWidth / (float)mMediaPanels[ panel ]->mMediaHeight;
330 }
331
332 if(aspect > 1.0f)
333 {
334 // media is wider than it is high -- adjust the top and bottom in
335 for( int corner = 0; corner < 4; ++corner )
336 {
337 float temp = base_vertex_pos[corner * 2 + 1];
338
339 if(temp < 0.5f)
340 temp += 0.5 - (0.5f / aspect);
341 else
342 temp -= 0.5 - (0.5f / aspect);
343
344 base_vertex_pos[corner * 2 + 1] = temp;
345 }
346 }
347 else if(aspect < 1.0f)
348 {
349 // media is higher than it is wide -- adjust the left and right sides in
350 for( int corner = 0; corner < 4; ++corner )
351 {
352 float temp = base_vertex_pos[corner * 2];
353
354 if(temp < 0.5f)
355 temp += 0.5f - (0.5f * aspect);
356 else
357 temp -= 0.5f - (0.5f * aspect);
358
359 base_vertex_pos[corner * 2] = temp;
360 }
361 }
362 }
363
364 glBegin( GL_QUADS );
365 for( int corner = 0; corner < 4; ++corner )
366 {
367 glTexCoord2f( texture_coords[ corner * 2 ], texture_coords[ corner * 2 + 1 ] );
368 GLfloat x = base_vertex_pos[ corner * 2 ] + panel_x * ( 1.0 + spacing ) - offset_x + spacing / 2.0f;
369 GLfloat y = base_vertex_pos[ corner * 2 + 1 ] + panel_y * ( 1.0 + spacing ) - offset_y + spacing / 2.0f;
370
371 glVertex3f( x, y, 0.0f );
372 };
373 glEnd();
374}
375
376//////////////////////////////////////////////////////////////////////////////
377//
378void LLMediaPluginTest::startPanelHighlight( float red, float green, float blue, float line_width )
379{
380 glPushAttrib( GL_ALL_ATTRIB_BITS );
381 glEnable( GL_POLYGON_OFFSET_FILL );
382 glPolygonOffset( -2.5f, -2.5f );
383 glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
384 glLineWidth( line_width );
385 glColor3f( red, green, blue );
386 glDisable( GL_TEXTURE_2D );
387}
388
389//////////////////////////////////////////////////////////////////////////////
390//
391void LLMediaPluginTest::endPanelHighlight()
392{
393 glPopAttrib();
394}
395
396////////////////////////////////////////////////////////////////////////////////
397//
398void LLMediaPluginTest::draw( int draw_type )
399{
400 for( int panel = 0; panel < (int)mMediaPanels.size(); ++panel )
401 {
402 // drawing pick texture
403 if ( draw_type == DrawTypePickTexture )
404 {
405 // only bother with pick if we have something to render
406 // Actually, we need to pick even if we're not ready to render.
407 // Otherwise you can't select and remove a panel which has gone bad.
408 //if ( mMediaPanels[ panel ]->mReadyToRender )
409 {
410 glMatrixMode( GL_TEXTURE );
411 glPushMatrix();
412
413 // pick texture is a power of 2 so no need to scale
414 glLoadIdentity();
415
416 // bind to media texture
417 glLoadIdentity();
418 bindTexture( mMediaPanels[ panel ]->mPickTextureHandle );
419 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
420 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
421
422 // draw geometry using pick texture
423 drawGeometry( panel );
424
425 glMatrixMode( GL_TEXTURE );
426 glPopMatrix();
427 };
428 }
429 else
430 if ( draw_type == DrawTypeMediaTexture )
431 {
432 bool texture_valid = false;
433 bool plugin_exited = false;
434
435 if(mMediaPanels[ panel ]->mMediaSource)
436 {
437 texture_valid = mMediaPanels[ panel ]->mMediaSource->textureValid();
438 plugin_exited = mMediaPanels[ panel ]->mMediaSource->isPluginExited();
439 }
440
441 // save texture matrix (changes for each panel)
442 glMatrixMode( GL_TEXTURE );
443 glPushMatrix();
444
445 // only process texture if the media is ready to draw
446 // (we still want to draw the geometry)
447 if ( mMediaPanels[ panel ]->mReadyToRender && texture_valid )
448 {
449 // bind to media texture
450 bindTexture( mMediaPanels[ panel ]->mMediaTextureHandle );
451
452 if ( mFuzzyMedia )
453 {
454 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
455 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
456 }
457 else
458 {
459 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
460 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
461 }
462
463 // scale to fit panel
464 glScalef( mMediaPanels[ panel ]->mTextureScaleX,
465 mMediaPanels[ panel ]->mTextureScaleY,
466 1.0f );
467 };
468
469 float intensity = plugin_exited?0.25f:1.0f;
470
471 // highlight the selected panel
472 if ( mSelectedPanel && ( mMediaPanels[ panel ]->mId == mSelectedPanel->mId ) )
473 {
474 startPanelHighlight( intensity, intensity, 0.0f, 5.0f );
475 drawGeometry( panel );
476 endPanelHighlight();
477 }
478 else
479 // this panel not able to render yet since it
480 // doesn't have enough information
481 if ( !mMediaPanels[ panel ]->mReadyToRender )
482 {
483 startPanelHighlight( intensity, 0.0f, 0.0f, 2.0f );
484 drawGeometry( panel );
485 endPanelHighlight();
486 }
487 else
488 // just display a border around the media
489 {
490 startPanelHighlight( 0.0f, intensity, 0.0f, 2.0f );
491 drawGeometry( panel );
492 endPanelHighlight();
493 };
494
495 if ( mMediaPanels[ panel ]->mReadyToRender && texture_valid )
496 {
497 // draw visual geometry
498 drawGeometry( panel );
499 }
500
501 // restore texture matrix (changes for each panel)
502 glMatrixMode( GL_TEXTURE );
503 glPopMatrix();
504 };
505 };
506}
507
508////////////////////////////////////////////////////////////////////////////////
509//
510void LLMediaPluginTest::display()
511{
512 // GLUI requires this
513 if ( glutGetWindow() != mAppWindow )
514 glutSetWindow( mAppWindow );
515
516 // start with a clean slate
517 glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
518 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
519
520 // set up OpenGL view
521 glMatrixMode( GL_PROJECTION );
522 glLoadIdentity();
523 glFrustum( -mViewportAspect * 0.04f, mViewportAspect * 0.04f, -0.04f, 0.04f, 0.1f, 50.0f );
524 glMatrixMode( GL_MODELVIEW );
525 glLoadIdentity();
526 glTranslatef( 0.0, 0.0, 0.0f );
527 glTranslatef( mViewPos[ 0 ], mViewPos[ 1 ], -mViewPos[ 2 ] );
528 glMultMatrixf( mViewRotation );
529
530 // draw pick texture
531 draw( DrawTypePickTexture );
532
533 // read colors and get coordinate values
534 glReadPixels( mCurMouseX, mCurMouseY, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, mPixelReadColor );
535
536 // clear the pick render (otherwise it may depth-fight with the textures rendered later)
537 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
538
539 // draw visible geometry
540 draw( DrawTypeMediaTexture );
541
542 glutSwapBuffers();
543}
544
545////////////////////////////////////////////////////////////////////////////////
546//
547void LLMediaPluginTest::idle()
548{
549// checkGLError("LLMediaPluginTest::idle");
550
551 // GLUI requires this
552 if ( glutGetWindow() != mAppWindow )
553 glutSetWindow( mAppWindow );
554
555 // random creation/destruction of panels enabled?
556 const time_t panel_timeout_time = 5;
557 if ( mRandomPanelCount )
558 {
559 // time for a change
560 static time_t last_panel_time = 0;
561 if ( time( NULL ) - last_panel_time > panel_timeout_time )
562 {
563 if ( rand() % 2 == 0 )
564 {
565 if ( mMediaPanels.size() < 16 )
566 {
567 std::cout << "Randomly adding new panel" << std::endl;
568 addMediaPanel( mBookmarks[ rand() % ( mBookmarks.size() - 1 ) + 1 ].second );
569 };
570 }
571 else
572 {
573 if ( mMediaPanels.size() > 0 )
574 {
575 std::cout << "Deleting selected panel" << std::endl;
576 remMediaPanel( mSelectedPanel );
577 };
578 };
579 time( &last_panel_time );
580 };
581 };
582
583 // random selection of bookmarks enabled?
584 const time_t bookmark_timeout_time = 5;
585 if ( mRandomBookmarks )
586 {
587 // time for a change
588 static time_t last_bookmark_time = 0;
589 if ( time( NULL ) - last_bookmark_time > bookmark_timeout_time )
590 {
591 // go to a different random bookmark on each panel
592 for( int panel = 0; panel < (int)mMediaPanels.size(); ++panel )
593 {
594 std::string uri = mBookmarks[ rand() % ( mBookmarks.size() - 1 ) + 1 ].second;
595
596 std::cout << "Random: navigating to : " << uri << std::endl;
597
598 std::string mime_type = mimeTypeFromUrl( uri );
599
600 if ( mime_type != mMediaPanels[ panel ]->mMimeType )
601 {
602 replaceMediaPanel( mMediaPanels[ panel ], uri );
603 }
604 else
605 {
606 mMediaPanels[ panel ]->mMediaSource->loadURI( uri );
607 mMediaPanels[ panel ]->mMediaSource->start();
608 };
609 };
610
611 time( &last_bookmark_time );
612 };
613 };
614
615 // update UI
616 if ( mSelectedPanel )
617 {
618 // set volume based on slider if we have time media
619 //if ( mGluiMediaTimeControlWindowFlag )
620 //{
621 // mSelectedPanel->mMediaSource->setVolume( (float)mMediaTimeControlVolume / 100.0f );
622 //};
623
624 // NOTE: it is absurd that we need cache the state of GLUI controls
625 // but enabling/disabling controls drags framerate from 500+
626 // down to 15. Not a problem for plugin system - only this test
627 // enable/disable time based UI controls based on type of plugin
628 if ( mSelectedPanel->mMediaSource->pluginSupportsMediaTime() )
629 {
630 if ( ! mGluiMediaTimeControlWindowFlag )
631 {
632 mGluiMediaTimeControlWindow->enable();
633 mGluiMediaTimeControlWindowFlag = true;
634 };
635 }
636 else
637 {
638 if ( mGluiMediaTimeControlWindowFlag )
639 {
640 mGluiMediaTimeControlWindow->disable();
641 mGluiMediaTimeControlWindowFlag = false;
642 };
643 };
644
645 // enable/disable browser based UI controls based on type of plugin
646 if ( mSelectedPanel->mMediaSource->pluginSupportsMediaBrowser() )
647 {
648 if ( ! mGluiMediaBrowserControlWindowFlag )
649 {
650 mGluiMediaBrowserControlWindow->enable();
651 mGluiMediaBrowserControlWindowFlag = true;
652 };
653 }
654 else
655 {
656 if ( mGluiMediaBrowserControlWindowFlag )
657 {
658 mGluiMediaBrowserControlWindow->disable();
659 mGluiMediaBrowserControlWindowFlag = false;
660 };
661 };
662
663 // enable/disable browser back button depending on browser history
664 if ( mSelectedPanel->mMediaSource->getHistoryBackAvailable() )
665 {
666 if ( ! mMediaBrowserControlBackButtonFlag )
667 {
668 mMediaBrowserControlBackButton->enable();
669 mMediaBrowserControlBackButtonFlag = true;
670 };
671 }
672 else
673 {
674 if ( mMediaBrowserControlBackButtonFlag )
675 {
676 mMediaBrowserControlBackButton->disable();
677 mMediaBrowserControlBackButtonFlag = false;
678 };
679 };
680
681 // enable/disable browser forward button depending on browser history
682 if ( mSelectedPanel->mMediaSource->getHistoryForwardAvailable() )
683 {
684 if ( ! mMediaBrowserControlForwardButtonFlag )
685 {
686 mMediaBrowserControlForwardButton->enable();
687 mMediaBrowserControlForwardButtonFlag = true;
688 };
689 }
690 else
691 {
692 if ( mMediaBrowserControlForwardButtonFlag )
693 {
694 mMediaBrowserControlForwardButton->disable();
695 mMediaBrowserControlForwardButtonFlag = false;
696 };
697 };
698
699 // NOTE: This is *very* slow and not worth optimising
700 updateStatusBar();
701 };
702
703 // update all the panels
704 for( int panel_index = 0; panel_index < (int)mMediaPanels.size(); ++panel_index )
705 {
706 mediaPanel *panel = mMediaPanels[ panel_index ];
707
708 // call plugins idle function so it can potentially update itself
709 panel->mMediaSource->idle();
710
711 // update each media panel
712 updateMediaPanel( panel );
713
714 LLRect dirty_rect;
715 if ( ! panel->mMediaSource->textureValid() )
716 {
717 //std::cout << "texture invalid, skipping update..." << std::endl;
718 }
719 else
720 if ( panel &&
721 ( panel->mMediaWidth != panel->mMediaSource->getWidth() ||
722 panel->mMediaHeight != panel->mMediaSource->getHeight() ) )
723 {
724 //std::cout << "Resize in progress, skipping update..." << std::endl;
725 }
726 else
727 if ( panel->mMediaSource->getDirty( &dirty_rect ) )
728 {
729 const unsigned char* pixels = panel->mMediaSource->getBitsData();
730 if ( pixels && isTexture(panel->mMediaTextureHandle))
731 {
732 int x_offset = dirty_rect.mLeft;
733 int y_offset = dirty_rect.mBottom;
734 int width = dirty_rect.mRight - dirty_rect.mLeft;
735 int height = dirty_rect.mTop - dirty_rect.mBottom;
736
737 if((dirty_rect.mRight <= panel->mTextureWidth) && (dirty_rect.mTop <= panel->mTextureHeight))
738 {
739 // Offset the pixels pointer properly
740 pixels += ( y_offset * panel->mMediaSource->getTextureDepth() * panel->mMediaSource->getBitsWidth() );
741 pixels += ( x_offset * panel->mMediaSource->getTextureDepth() );
742
743 // set up texture
744 bindTexture( panel->mMediaTextureHandle, panel->mMediaSource->getBitsWidth() );
745 if ( mFuzzyMedia )
746 {
747 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
748 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
749 }
750 else
751 {
752 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
753 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
754 };
755
756 checkGLError("glTexParameteri");
757
758 if(panel->mMediaSource->getTextureFormatSwapBytes())
759 {
760 glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
761 checkGLError("glPixelStorei");
762 }
763
764 // draw portion that changes into texture
765 glTexSubImage2D( GL_TEXTURE_2D, 0,
766 x_offset,
767 y_offset,
768 width,
769 height,
770 panel->mMediaSource->getTextureFormatPrimary(),
771 panel->mMediaSource->getTextureFormatType(),
772 pixels );
773
774 if(checkGLError("glTexSubImage2D"))
775 {
776 std::cerr << " panel ID=" << panel->mId << std::endl;
777 std::cerr << " texture size = " << panel->mTextureWidth << " x " << panel->mTextureHeight << std::endl;
778 std::cerr << " media size = " << panel->mMediaWidth << " x " << panel->mMediaHeight << std::endl;
779 std::cerr << " dirty rect = " << dirty_rect.mLeft << ", " << dirty_rect.mBottom << ", " << dirty_rect.mRight << ", " << dirty_rect.mTop << std::endl;
780 std::cerr << " texture width = " << panel->mMediaSource->getBitsWidth() << std::endl;
781 std::cerr << " format primary = 0x" << std::hex << panel->mMediaSource->getTextureFormatPrimary() << std::dec << std::endl;
782 std::cerr << " format type = 0x" << std::hex << panel->mMediaSource->getTextureFormatType() << std::dec << std::endl;
783 std::cerr << " pixels = " << (void*)pixels << std::endl;
784 }
785
786 if(panel->mMediaSource->getTextureFormatSwapBytes())
787 {
788 glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
789 checkGLError("glPixelStorei");
790 }
791
792 panel->mMediaSource->resetDirty();
793
794 panel->mReadyToRender = true;
795 }
796 else
797 {
798 std::cerr << "dirty rect is outside current media size, skipping update" << std::endl;
799 }
800 };
801 };
802 };
803
804 // GLUI requires this
805 if ( glutGetWindow() != mAppWindow )
806 glutSetWindow( mAppWindow );
807
808 // trigger re-display
809 glutPostRedisplay();
810}
811
812////////////////////////////////////////////////////////////////////////////////
813//
814void LLMediaPluginTest::windowPosToTexturePos( int window_x, int window_y,
815 int& media_x, int& media_y,
816 int& id )
817{
818 if ( ! mSelectedPanel )
819 {
820 media_x = 0;
821 media_y = 0;
822 id = 0;
823 return;
824 };
825
826 // record cursor poisiton for a readback next frame
827 mCurMouseX = window_x;
828 // OpenGL app == coordinate system this way
829 // NOTE: unrelated to settings in plugin - this
830 // is just for this app
831 mCurMouseY = mWindowHeight - window_y;
832
833 // extract x (0..1023, y (0..1023) and id (0..15) from RGB components
834 unsigned long pixel_read_color_bits = ( mPixelReadColor[ 0 ] << 16 ) | ( mPixelReadColor[ 1 ] << 8 ) | mPixelReadColor[ 2 ];
835 int texture_x = pixel_read_color_bits & 0x3ff;
836 int texture_y = ( pixel_read_color_bits >> 10 ) & 0x3ff;
837 id = ( pixel_read_color_bits >> 20 ) & 0x0f;
838
839 // scale to size of media (1024 because we use 10 bits for X and Y from 24)
840 media_x = (int)( ( (float)mSelectedPanel->mMediaWidth * (float)texture_x ) / 1024.0f );
841 media_y = (int)( ( (float)mSelectedPanel->mMediaHeight * (float)texture_y ) / 1024.0f );
842
843 // we assume the plugin uses an inverted coordinate scheme like OpenGL
844 // if not, the plugin code inverts the Y coordinate for us - we don't need to
845 media_y = mSelectedPanel->mMediaHeight - media_y;
846
847 if ( media_x > 0 && media_y > 0 )
848 {
849 //std::cout << " mouse coords: " << mCurMouseX << " x " << mCurMouseY << " and id = " << id << std::endl;
850 //std::cout << "raw texture coords: " << texture_x << " x " << texture_y << " and id = " << id << std::endl;
851 //std::cout << " media coords: " << media_x << " x " << media_y << " and id = " << id << std::endl;
852 //std::cout << std::endl;
853 };
854}
855
856////////////////////////////////////////////////////////////////////////////////
857//
858void LLMediaPluginTest::selectPanelById( int id )
859{
860 for( int panel = 0; panel < (int)mMediaPanels.size(); ++panel )
861 {
862 if ( mMediaPanels[ panel ]->mId == id )
863 {
864 selectPanel(mMediaPanels[ panel ]);
865 return;
866 };
867 };
868}
869
870////////////////////////////////////////////////////////////////////////////////
871//
872void LLMediaPluginTest::selectPanel( mediaPanel* panel )
873{
874 if( mSelectedPanel == panel )
875 return;
876
877 // turn off volume before we delete it
878 if( mSelectedPanel && mSelectedPanel->mMediaSource )
879 {
880 mSelectedPanel->mMediaSource->setVolume( 0.0f );
881 mSelectedPanel->mMediaSource->setPriority( LLPluginClassMedia::PRIORITY_LOW );
882 };
883
884 mSelectedPanel = panel;
885
886 if( mSelectedPanel && mSelectedPanel->mMediaSource )
887 {
888 mSelectedPanel->mMediaSource->setVolume( (float)mMediaTimeControlVolume / 100.0f );
889 mSelectedPanel->mMediaSource->setPriority( LLPluginClassMedia::PRIORITY_NORMAL );
890
891 if(!mSelectedPanel->mStartUrl.empty())
892 {
893 mUrlEdit->set_text(const_cast<char*>(mSelectedPanel->mStartUrl.c_str()) );
894 }
895 };
896}
897
898////////////////////////////////////////////////////////////////////////////////
899//
900mediaPanel* LLMediaPluginTest::findMediaPanel( LLPluginClassMedia* source )
901{
902 mediaPanel *result = NULL;
903
904 for( int panel = 0; panel < (int)mMediaPanels.size(); ++panel )
905 {
906 if ( mMediaPanels[ panel ]->mMediaSource == source )
907 {
908 result = mMediaPanels[ panel ];
909 }
910 }
911
912 return result;
913}
914
915////////////////////////////////////////////////////////////////////////////////
916//
917void LLMediaPluginTest::navigateToNewURI( std::string uri )
918{
919 if ( uri.length() )
920 {
921 std::string mime_type = mimeTypeFromUrl( uri );
922
923 if ( !mSelectedPanel->mMediaSource->isPluginExited() && (mime_type == mSelectedPanel->mMimeType) )
924 {
925 std::cout << "MIME type is the same" << std::endl;
926 mSelectedPanel->mMediaSource->loadURI( uri );
927 mSelectedPanel->mMediaSource->start();
928 mBookmarkList->do_selection( 0 );
929 }
930 else
931 {
932 std::cout << "MIME type changed or plugin had exited" << std::endl;
933 replaceMediaPanel( mSelectedPanel, uri );
934 mBookmarkList->do_selection( 0 );
935 }
936 };
937}
938
939////////////////////////////////////////////////////////////////////////////////
940//
941void LLMediaPluginTest::initUrlHistory( std::string uris )
942{
943 if ( uris.length() > 0 )
944 {
945 std::cout << "init URL : " << uris << std::endl;
946 LLSD historySD;
947
948 char *cstr, *p;
949 cstr = new char[uris.size()+1];
950 strcpy(cstr, uris.c_str());
951 const char *DELIMS = " ,;";
952 p = strtok(cstr, DELIMS);
953 while (p != NULL) {
954 historySD.insert(0, p);
955 p = strtok(NULL, DELIMS);
956 }
957 mSelectedPanel->mMediaSource->initializeUrlHistory(historySD);
958 delete[] cstr;
959 }
960}
961
962////////////////////////////////////////////////////////////////////////////////
963//
964void LLMediaPluginTest::gluiCallback( int control_id )
965{
966 if ( control_id == mIdBookmarks )
967 {
968 std::string uri = mBookmarks[ mSelBookmark ].second;
969
970 navigateToNewURI( uri );
971 }
972 else
973 if ( control_id == mIdUrlEdit)
974 {
975 std::string uri = mUrlEdit->get_text();
976
977 navigateToNewURI( uri );
978 }
979 else
980 if ( control_id == mIdUrlInitHistoryEdit )
981 {
982 std::string uri = mUrlInitHistoryEdit->get_text();
983
984 initUrlHistory( uri );
985 }
986 else
987 if ( control_id == mIdControlAddPanel )
988 {
989 addMediaPanel( mBookmarks[ rand() % ( mBookmarks.size() - 1 ) + 1 ].second );
990 }
991 else
992 if ( control_id == mIdControlRemPanel )
993 {
994 remMediaPanel( mSelectedPanel );
995 }
996 else
997 if ( control_id == mIdDisableTimeout )
998 {
999 // Set the "disable timeout" flag for all active plugins.
1000 for( int i = 0; i < (int)mMediaPanels.size(); ++i )
1001 {
1002 mMediaPanels[ i ]->mMediaSource->setDisableTimeout(mDisableTimeout);
1003 }
1004 }
1005 else
1006 if ( control_id == mIdControlCrashPlugin )
1007 {
1008 // send message to plugin and ask it to crash
1009 // (switch out for ReleaseCandidate version :) )
1010 if(mSelectedPanel && mSelectedPanel->mMediaSource)
1011 {
1012 mSelectedPanel->mMediaSource->crashPlugin();
1013 }
1014 }
1015 else
1016 if ( control_id == mIdControlHangPlugin )
1017 {
1018 // send message to plugin and ask it to hang
1019 // (switch out for ReleaseCandidate version :) )
1020 if(mSelectedPanel && mSelectedPanel->mMediaSource)
1021 {
1022 mSelectedPanel->mMediaSource->hangPlugin();
1023 }
1024 }
1025 else
1026 if ( control_id == mIdControlExitApp )
1027 {
1028 // text for exiting plugin system cleanly
1029 delete this; // clean up
1030 exit( 0 );
1031 }
1032 else
1033 if ( control_id == mIdMediaTimeControlPlay )
1034 {
1035 if ( mSelectedPanel )
1036 {
1037 mSelectedPanel->mMediaSource->setLoop( false );
1038 mSelectedPanel->mMediaSource->start();
1039 };
1040 }
1041 else
1042 if ( control_id == mIdMediaTimeControlLoop )
1043 {
1044 if ( mSelectedPanel )
1045 {
1046 mSelectedPanel->mMediaSource->setLoop( true );
1047 mSelectedPanel->mMediaSource->start();
1048 };
1049 }
1050 else
1051 if ( control_id == mIdMediaTimeControlPause )
1052 {
1053 if ( mSelectedPanel )
1054 mSelectedPanel->mMediaSource->pause();
1055 }
1056 else
1057 if ( control_id == mIdMediaTimeControlStop )
1058 {
1059 if ( mSelectedPanel )
1060 {
1061 mSelectedPanel->mMediaSource->stop();
1062 };
1063 }
1064 else
1065 if ( control_id == mIdMediaTimeControlSeek )
1066 {
1067 if ( mSelectedPanel )
1068 {
1069 // get value from spinner
1070 float seconds_to_seek = mMediaTimeControlSeekSeconds;
1071 mSelectedPanel->mMediaSource->seek( seconds_to_seek );
1072 mSelectedPanel->mMediaSource->start();
1073 };
1074 }
1075 else
1076 if ( control_id == mIdMediaTimeControlRewind )
1077 {
1078 if ( mSelectedPanel )
1079 {
1080 mSelectedPanel->mMediaSource->setLoop( false );
1081 mSelectedPanel->mMediaSource->start(-2.0f);
1082 };
1083 }
1084 else
1085 if ( control_id == mIdMediaTimeControlFastForward )
1086 {
1087 if ( mSelectedPanel )
1088 {
1089 mSelectedPanel->mMediaSource->setLoop( false );
1090 mSelectedPanel->mMediaSource->start(2.0f);
1091 };
1092 }
1093 else
1094 if ( control_id == mIdMediaBrowserControlBack )
1095 {
1096 if ( mSelectedPanel )
1097 mSelectedPanel->mMediaSource->browse_back();
1098 }
1099 else
1100 if ( control_id == mIdMediaBrowserControlStop )
1101 {
1102 if ( mSelectedPanel )
1103 mSelectedPanel->mMediaSource->browse_stop();
1104 }
1105 else
1106 if ( control_id == mIdMediaBrowserControlForward )
1107 {
1108 if ( mSelectedPanel )
1109 mSelectedPanel->mMediaSource->browse_forward();
1110 }
1111 else
1112 if ( control_id == mIdMediaBrowserControlHome )
1113 {
1114 if ( mSelectedPanel )
1115 mSelectedPanel->mMediaSource->loadURI( mHomeWebUrl );
1116 }
1117 else
1118 if ( control_id == mIdMediaBrowserControlReload )
1119 {
1120 if ( mSelectedPanel )
1121 mSelectedPanel->mMediaSource->browse_reload( true );
1122 }
1123 else
1124 if ( control_id == mIdMediaBrowserControlClearCache )
1125 {
1126 if ( mSelectedPanel )
1127 mSelectedPanel->mMediaSource->clear_cache();
1128 }
1129 else
1130 if ( control_id == mIdMediaBrowserControlClearCookies )
1131 {
1132 if ( mSelectedPanel )
1133 mSelectedPanel->mMediaSource->clear_cookies();
1134 }
1135 else
1136 if ( control_id == mIdMediaBrowserControlEnableCookies )
1137 {
1138 if ( mSelectedPanel )
1139 {
1140 if ( mMediaBrowserControlEnableCookies )
1141 {
1142 mSelectedPanel->mMediaSource->enable_cookies( true );
1143 }
1144 else
1145 {
1146 mSelectedPanel->mMediaSource->enable_cookies( false );
1147 }
1148 };
1149 };
1150}
1151
1152////////////////////////////////////////////////////////////////////////////////
1153//
1154void LLMediaPluginTest::keyboard( int key )
1155{
1156 //if ( key == 'a' || key == 'A' )
1157 // addMediaPanel( mBookmarks[ rand() % ( mBookmarks.size() - 1 ) + 1 ].second );
1158 //else
1159 //if ( key == 'r' || key == 'R' )
1160 // remMediaPanel( mSelectedPanel );
1161 //else
1162 //if ( key == 'd' || key == 'D' )
1163 // dumpPanelInfo();
1164 //else
1165 if ( key == 27 )
1166 {
1167 std::cout << "Application finished - exiting..." << std::endl;
1168 delete this;
1169 exit( 0 );
1170 };
1171
1172 mSelectedPanel->mMediaSource->keyEvent( LLPluginClassMedia::KEY_EVENT_DOWN, key, 0 );
1173 mSelectedPanel->mMediaSource->keyEvent( LLPluginClassMedia::KEY_EVENT_UP, key, 0 );
1174};
1175
1176////////////////////////////////////////////////////////////////////////////////
1177//
1178void LLMediaPluginTest::mouseButton( int button, int state, int x, int y )
1179{
1180 if ( button == GLUT_LEFT_BUTTON )
1181 {
1182 if ( state == GLUT_DOWN )
1183 {
1184 int media_x, media_y, id;
1185 windowPosToTexturePos( x, y, media_x, media_y, id );
1186
1187 if ( mSelectedPanel )
1188 mSelectedPanel->mMediaSource->mouseEvent( LLPluginClassMedia::MOUSE_EVENT_DOWN, 0, media_x, media_y, 0 );
1189 }
1190 else
1191 if ( state == GLUT_UP )
1192 {
1193 int media_x, media_y, id;
1194 windowPosToTexturePos( x, y, media_x, media_y, id );
1195
1196 // only select a panel if we're on a panel
1197 // (HACK: strictly speaking this rules out clicking on
1198 // the origin of a panel but that's very unlikely)
1199 if ( media_x > 0 && media_y > 0 )
1200 {
1201 selectPanelById( id );
1202
1203 if ( mSelectedPanel )
1204 mSelectedPanel->mMediaSource->mouseEvent( LLPluginClassMedia::MOUSE_EVENT_UP, 0, media_x, media_y, 0 );
1205 };
1206 };
1207 };
1208}
1209
1210////////////////////////////////////////////////////////////////////////////////
1211//
1212void LLMediaPluginTest::mousePassive( int x, int y )
1213{
1214 int media_x, media_y, id;
1215 windowPosToTexturePos( x, y, media_x, media_y, id );
1216
1217 if ( mSelectedPanel )
1218 mSelectedPanel->mMediaSource->mouseEvent( LLPluginClassMedia::MOUSE_EVENT_MOVE, 0, media_x, media_y, 0 );
1219}
1220
1221////////////////////////////////////////////////////////////////////////////////
1222//
1223void LLMediaPluginTest::mouseMove( int x, int y )
1224{
1225 int media_x, media_y, id;
1226 windowPosToTexturePos( x, y, media_x, media_y, id );
1227
1228 if ( mSelectedPanel )
1229 mSelectedPanel->mMediaSource->mouseEvent( LLPluginClassMedia::MOUSE_EVENT_MOVE, 0, media_x, media_y, 0 );
1230}
1231
1232////////////////////////////////////////////////////////////////////////////////
1233//
1234void LLMediaPluginTest::makeChrome()
1235{
1236 // IDs used by GLUI
1237 int start_id = 0x1000;
1238
1239 // right side window - geometry manipulators
1240#if __APPLE__
1241 // the Apple GLUT implementation doesn't seem to set the graphic offset of subwindows correctly when they overlap in certain ways.
1242 // Use a separate controls window in this case.
1243 // GLUI window at right containing manipulation controls and other buttons
1244 int x = glutGet(GLUT_WINDOW_X) + glutGet(GLUT_WINDOW_WIDTH) + 4;
1245 int y = glutGet(GLUT_WINDOW_Y);
1246 GLUI* right_glui_window = GLUI_Master.create_glui( "", 0, x, y );
1247#else
1248 GLUI* right_glui_window = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_RIGHT );
1249#endif
1250 mViewRotationCtrl = right_glui_window->add_rotation( "Rotation", mViewRotation );
1251 mViewTranslationCtrl = right_glui_window->add_translation( "Translate", GLUI_TRANSLATION_XY, mViewPos );
1252 mViewTranslationCtrl->set_speed( 0.01f );
1253 mViewScaleCtrl = right_glui_window->add_translation( "Scale", GLUI_TRANSLATION_Z, &mViewPos[ 2 ] );
1254 mViewScaleCtrl->set_speed( 0.05f );
1255 right_glui_window->set_main_gfx_window( mAppWindow );
1256
1257 // right side window - app controls
1258 mIdControlAddPanel = start_id++;
1259 right_glui_window->add_statictext( "" );
1260 right_glui_window->add_separator();
1261 right_glui_window->add_statictext( "" );
1262 right_glui_window->add_button( "Add panel", mIdControlAddPanel, gluiCallbackWrapper );
1263 right_glui_window->add_statictext( "" );
1264 mIdControlRemPanel = start_id++;
1265 right_glui_window->add_button( "Rem panel", mIdControlRemPanel, gluiCallbackWrapper );
1266 right_glui_window->add_statictext( "" );
1267 right_glui_window->add_separator();
1268 right_glui_window->add_statictext( "" );
1269 mIdControlCrashPlugin = start_id++;
1270 right_glui_window->add_button( "Crash plugin", mIdControlCrashPlugin, gluiCallbackWrapper );
1271 mIdControlHangPlugin = start_id++;
1272 right_glui_window->add_button( "Hang plugin", mIdControlHangPlugin, gluiCallbackWrapper );
1273
1274 right_glui_window->add_statictext( "" );
1275 right_glui_window->add_separator();
1276 right_glui_window->add_statictext( "" );
1277 mIdControlExitApp = start_id++;
1278 right_glui_window->add_button( "Exit app", mIdControlExitApp, gluiCallbackWrapper );
1279
1280 //// top window - holds bookmark UI
1281 mIdBookmarks = start_id++;
1282 mSelBookmark = 0;
1283 GLUI* glui_window_top = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_TOP );
1284 mBookmarkList = glui_window_top->add_listbox( "", &mSelBookmark, mIdBookmarks, gluiCallbackWrapper );
1285 // only add the first 50 bookmarks - list can be very long sometimes (30,000+)
1286 // when testing list of media URLs from AGNI for example
1287 for( unsigned int each = 0; each < mBookmarks.size() && each < 50; ++each )
1288 mBookmarkList->add_item( each, const_cast< char* >( mBookmarks[ each ].first.c_str() ) );
1289 glui_window_top->set_main_gfx_window( mAppWindow );
1290
1291 glui_window_top->add_column( false );
1292 mIdUrlEdit = start_id++;
1293 mUrlEdit = glui_window_top->add_edittext( "Url:", GLUI_EDITTEXT_TEXT, 0, mIdUrlEdit, gluiCallbackWrapper );
1294 mUrlEdit->set_w( 600 );
1295 GLUI* glui_window_top2 = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_TOP );
1296 mIdUrlInitHistoryEdit = start_id++;
1297 mUrlInitHistoryEdit = glui_window_top2->add_edittext( "Init History (separate by commas or semicolons):",
1298 GLUI_EDITTEXT_TEXT, 0, mIdUrlInitHistoryEdit, gluiCallbackWrapper );
1299 mUrlInitHistoryEdit->set_w( 800 );
1300
1301 // top window - media controls for "time" media types (e.g. movies)
1302 mGluiMediaTimeControlWindow = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_TOP );
1303 mGluiMediaTimeControlWindow->set_main_gfx_window( mAppWindow );
1304 mIdMediaTimeControlPlay = start_id++;
1305 mGluiMediaTimeControlWindow->add_button( "PLAY", mIdMediaTimeControlPlay, gluiCallbackWrapper );
1306 mGluiMediaTimeControlWindow->add_column( false );
1307 mIdMediaTimeControlLoop = start_id++;
1308 mGluiMediaTimeControlWindow->add_button( "LOOP", mIdMediaTimeControlLoop, gluiCallbackWrapper );
1309 mGluiMediaTimeControlWindow->add_column( false );
1310 mIdMediaTimeControlPause = start_id++;
1311 mGluiMediaTimeControlWindow->add_button( "PAUSE", mIdMediaTimeControlPause, gluiCallbackWrapper );
1312 mGluiMediaTimeControlWindow->add_column( false );
1313
1314 GLUI_Button *button;
1315 mIdMediaTimeControlRewind = start_id++;
1316 button = mGluiMediaTimeControlWindow->add_button( "<<", mIdMediaTimeControlRewind, gluiCallbackWrapper );
1317 button->set_w(30);
1318 mGluiMediaTimeControlWindow->add_column( false );
1319 mIdMediaTimeControlFastForward = start_id++;
1320 button = mGluiMediaTimeControlWindow->add_button( ">>", mIdMediaTimeControlFastForward, gluiCallbackWrapper );
1321 button->set_w(30);
1322
1323 mGluiMediaTimeControlWindow->add_column( true );
1324
1325 mIdMediaTimeControlStop = start_id++;
1326 mGluiMediaTimeControlWindow->add_button( "STOP", mIdMediaTimeControlStop, gluiCallbackWrapper );
1327 mGluiMediaTimeControlWindow->add_column( false );
1328 mIdMediaTimeControlVolume = start_id++;
1329 GLUI_Spinner* spinner = mGluiMediaTimeControlWindow->add_spinner( "Volume", 2, &mMediaTimeControlVolume, mIdMediaTimeControlVolume, gluiCallbackWrapper);
1330 spinner->set_float_limits( 0, 100 );
1331 mGluiMediaTimeControlWindow->add_column( true );
1332 mIdMediaTimeControlSeekSeconds = start_id++;
1333 spinner = mGluiMediaTimeControlWindow->add_spinner( "", 2, &mMediaTimeControlSeekSeconds, mIdMediaTimeControlSeekSeconds, gluiCallbackWrapper);
1334 spinner->set_float_limits( 0, 200 );
1335 spinner->set_w( 32 );
1336 spinner->set_speed( 0.025f );
1337 mGluiMediaTimeControlWindow->add_column( false );
1338 mIdMediaTimeControlSeek = start_id++;
1339 mGluiMediaTimeControlWindow->add_button( "SEEK", mIdMediaTimeControlSeek, gluiCallbackWrapper );
1340 mGluiMediaTimeControlWindow->add_column( false );
1341
1342
1343 // top window - media controls for "browser" media types (e.g. web browser)
1344 mGluiMediaBrowserControlWindow = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_TOP );
1345 mGluiMediaBrowserControlWindow->set_main_gfx_window( mAppWindow );
1346 mIdMediaBrowserControlBack = start_id++;
1347 mMediaBrowserControlBackButton = mGluiMediaBrowserControlWindow->add_button( "BACK", mIdMediaBrowserControlBack, gluiCallbackWrapper );
1348 mGluiMediaBrowserControlWindow->add_column( false );
1349 mIdMediaBrowserControlStop = start_id++;
1350 mGluiMediaBrowserControlWindow->add_button( "STOP", mIdMediaBrowserControlStop, gluiCallbackWrapper );
1351 mGluiMediaBrowserControlWindow->add_column( false );
1352 mIdMediaBrowserControlForward = start_id++;
1353 mMediaBrowserControlForwardButton = mGluiMediaBrowserControlWindow->add_button( "FORWARD", mIdMediaBrowserControlForward, gluiCallbackWrapper );
1354 mGluiMediaBrowserControlWindow->add_column( false );
1355 mIdMediaBrowserControlHome = start_id++;
1356 mGluiMediaBrowserControlWindow->add_button( "HOME", mIdMediaBrowserControlHome, gluiCallbackWrapper );
1357 mGluiMediaBrowserControlWindow->add_column( false );
1358 mIdMediaBrowserControlReload = start_id++;
1359 mGluiMediaBrowserControlWindow->add_button( "RELOAD", mIdMediaBrowserControlReload, gluiCallbackWrapper );
1360 mGluiMediaBrowserControlWindow->add_column( false );
1361 mIdMediaBrowserControlClearCache = start_id++;
1362 mGluiMediaBrowserControlWindow->add_button( "CLEAR CACHE", mIdMediaBrowserControlClearCache, gluiCallbackWrapper );
1363 mGluiMediaBrowserControlWindow->add_column( false );
1364 mIdMediaBrowserControlClearCookies = start_id++;
1365 mGluiMediaBrowserControlWindow->add_button( "CLEAR COOKIES", mIdMediaBrowserControlClearCookies, gluiCallbackWrapper );
1366 mGluiMediaBrowserControlWindow->add_column( false );
1367 mIdMediaBrowserControlEnableCookies = start_id++;
1368 mMediaBrowserControlEnableCookies = 0;
1369 mGluiMediaBrowserControlWindow->add_checkbox( "Enable Cookies", &mMediaBrowserControlEnableCookies, mIdMediaBrowserControlEnableCookies, gluiCallbackWrapper );
1370
1371 // top window - misc controls
1372 GLUI* glui_window_misc_control = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_TOP );
1373 mIdRandomPanelCount = start_id++;
1374 mRandomPanelCount = 0;
1375 glui_window_misc_control->add_checkbox( "Randomize panel count", &mRandomPanelCount, mIdRandomPanelCount, gluiCallbackWrapper );
1376 glui_window_misc_control->set_main_gfx_window( mAppWindow );
1377 glui_window_misc_control->add_column( true );
1378 mIdRandomBookmarks = start_id++;
1379 mRandomBookmarks = 0;
1380 glui_window_misc_control->add_checkbox( "Randomize bookmarks", &mRandomBookmarks, mIdRandomBookmarks, gluiCallbackWrapper );
1381 glui_window_misc_control->set_main_gfx_window( mAppWindow );
1382 glui_window_misc_control->add_column( true );
1383
1384 mIdDisableTimeout = start_id++;
1385 mDisableTimeout = 0;
1386 glui_window_misc_control->add_checkbox( "Disable plugin timeout", &mDisableTimeout, mIdDisableTimeout, gluiCallbackWrapper );
1387 glui_window_misc_control->set_main_gfx_window( mAppWindow );
1388
1389 // bottom window - status
1390 mBottomGLUIWindow = GLUI_Master.create_glui_subwindow( mAppWindow, GLUI_SUBWINDOW_BOTTOM );
1391 mStatusText = mBottomGLUIWindow->add_statictext( "" );
1392 mBottomGLUIWindow->set_main_gfx_window( mAppWindow );
1393}
1394
1395////////////////////////////////////////////////////////////////////////////////
1396//
1397void LLMediaPluginTest::resetView()
1398{
1399 mViewRotationCtrl->reset();
1400
1401 mViewScaleCtrl->set_x( 0.0f );
1402 mViewScaleCtrl->set_y( 0.0f );
1403 mViewScaleCtrl->set_z( 3.0f );
1404
1405 mViewTranslationCtrl->set_x( 0.0f );
1406 mViewTranslationCtrl->set_y( 0.0f );
1407 mViewTranslationCtrl->set_z( 0.0f );
1408}
1409
1410////////////////////////////////////////////////////////////////////////////////
1411//
1412void LLMediaPluginTest::makePickTexture( int id, GLuint* texture_handle, unsigned char** texture_pixels )
1413{
1414 int pick_texture_width = 1024;
1415 int pick_texture_height = 1024;
1416 int pick_texture_depth = 3;
1417 unsigned char* ptr = new unsigned char[ pick_texture_width * pick_texture_height * pick_texture_depth ];
1418 for( int y = 0; y < pick_texture_height; ++y )
1419 {
1420 for( int x = 0; x < pick_texture_width * pick_texture_depth ; x += pick_texture_depth )
1421 {
1422 unsigned long bits = 0L;
1423 bits |= ( id << 20 ) | ( y << 10 ) | ( x / 3 );
1424 unsigned char r_component = ( bits >> 16 ) & 0xff;
1425 unsigned char g_component = ( bits >> 8 ) & 0xff;
1426 unsigned char b_component = bits & 0xff;
1427
1428 ptr[ y * pick_texture_width * pick_texture_depth + x + 0 ] = r_component;
1429 ptr[ y * pick_texture_width * pick_texture_depth + x + 1 ] = g_component;
1430 ptr[ y * pick_texture_width * pick_texture_depth + x + 2 ] = b_component;
1431 };
1432 };
1433
1434 glGenTextures( 1, texture_handle );
1435
1436 checkGLError("glGenTextures");
1437 std::cout << "glGenTextures returned " << *texture_handle << std::endl;
1438
1439 bindTexture( *texture_handle );
1440 glTexImage2D( GL_TEXTURE_2D, 0,
1441 GL_RGB,
1442 pick_texture_width, pick_texture_height,
1443 0, GL_RGB, GL_UNSIGNED_BYTE, ptr );
1444
1445 *texture_pixels = ptr;
1446}
1447
1448////////////////////////////////////////////////////////////////////////////////
1449//
1450std::string LLMediaPluginTest::mimeTypeFromUrl( std::string& url )
1451{
1452 // default to web
1453 std::string mime_type = "text/html";
1454
1455 // we may need a more advanced MIME type accessor later :-)
1456 if ( url.find( ".mov" ) != std::string::npos ) // Movies
1457 mime_type = "video/quicktime";
1458 else
1459 if ( url.find( ".txt" ) != std::string::npos ) // Apple Text descriptors
1460 mime_type = "video/quicktime";
1461 else
1462 if ( url.find( ".mp3" ) != std::string::npos ) // Apple Text descriptors
1463 mime_type = "video/quicktime";
1464 else
1465 if ( url.find( "example://" ) != std::string::npos ) // Example plugin
1466 mime_type = "example/example";
1467
1468 return mime_type;
1469}
1470
1471////////////////////////////////////////////////////////////////////////////////
1472//
1473std::string LLMediaPluginTest::pluginNameFromMimeType( std::string& mime_type )
1474{
1475#if LL_DARWIN
1476 std::string plugin_name( "media_plugin_null.dylib" );
1477 if ( mime_type == "video/quicktime" )
1478 plugin_name = "media_plugin_quicktime.dylib";
1479 else
1480 if ( mime_type == "text/html" )
1481 plugin_name = "media_plugin_webkit.dylib";
1482
1483#elif LL_WINDOWS
1484 std::string plugin_name( "media_plugin_null.dll" );
1485
1486 if ( mime_type == "video/quicktime" )
1487 plugin_name = "media_plugin_quicktime.dll";
1488 else
1489 if ( mime_type == "text/html" )
1490 plugin_name = "media_plugin_webkit.dll";
1491 else
1492 if ( mime_type == "example/example" )
1493 plugin_name = "media_plugin_example.dll";
1494
1495#elif LL_LINUX
1496 std::string plugin_name( "libmedia_plugin_null.so" );
1497
1498 if ( mime_type == "video/quicktime" )
1499 plugin_name = "libmedia_plugin_quicktime.so";
1500 else
1501 if ( mime_type == "text/html" )
1502 plugin_name = "libmedia_plugin_webkit.so";
1503#endif
1504 return plugin_name;
1505}
1506
1507////////////////////////////////////////////////////////////////////////////////
1508//
1509void LLMediaPluginTest::addMediaPanel( std::string url )
1510{
1511 // Get the plugin filename using the URL
1512 std::string mime_type = mimeTypeFromUrl( url );
1513 std::string plugin_name = pluginNameFromMimeType( mime_type );
1514
1515 // create a random size for the new media
1516 int media_width;
1517 int media_height;
1518 getRandomMediaSize( media_width, media_height, mime_type );
1519
1520 // make a new plugin
1521 LLPluginClassMedia* media_source = new LLPluginClassMedia(this);
1522
1523 // tell the plugin what size we asked for
1524 media_source->setSize( media_width, media_height );
1525
1526 // Use the launcher start and initialize the plugin
1527#if LL_DARWIN || LL_LINUX
1528 std::string launcher_name( "SLPlugin" );
1529#elif LL_WINDOWS
1530 std::string launcher_name( "SLPlugin.exe" );
1531#endif
1532 media_source->init( launcher_name, plugin_name );
1533 media_source->setDisableTimeout(mDisableTimeout);
1534
1535 // make a new panel and save parameters
1536 mediaPanel* panel = new mediaPanel;
1537 panel->mMediaSource = media_source;
1538 panel->mStartUrl = url;
1539 panel->mMimeType = mime_type;
1540 panel->mMediaWidth = media_width;
1541 panel->mMediaHeight = media_height;
1542 panel->mTextureWidth = 0;
1543 panel->mTextureHeight = 0;
1544 panel->mTextureScaleX = 0;
1545 panel->mTextureScaleY = 0;
1546 panel->mMediaTextureHandle = 0;
1547 panel->mPickTextureHandle = 0;
1548 panel->mAppTextureCoordsOpenGL = false; // really need an 'undefined' state here too
1549 panel->mReadyToRender = false;
1550
1551 // look through current media panels to find an unused index number
1552 bool id_exists = true;
1553 for( int nid = 0; nid < mMaxPanels; ++nid )
1554 {
1555 // does this id exist already?
1556 id_exists = false;
1557 for( int pid = 0; pid < (int)mMediaPanels.size(); ++pid )
1558 {
1559 if ( nid == mMediaPanels[ pid ]->mId )
1560 {
1561 id_exists = true;
1562 break;
1563 };
1564 };
1565
1566 // id wasn't found so we can use it
1567 if ( ! id_exists )
1568 {
1569 panel->mId = nid;
1570 break;
1571 };
1572 };
1573
1574 // if we get here and this flag is set, there is no room for any more panels
1575 if ( id_exists )
1576 {
1577 std::cout << "No room for any more panels" << std::endl;
1578 }
1579 else
1580 {
1581 // now we have the ID we can use it to make the
1582 // pick texture (id is baked into texture pixels)
1583 makePickTexture( panel->mId, &panel->mPickTextureHandle, &panel->mPickTexturePixels );
1584
1585 // save this in the list of panels
1586 mMediaPanels.push_back( panel );
1587
1588 // select the panel that was just created
1589 selectPanel( panel );
1590
1591 // load and start the URL
1592 panel->mMediaSource->loadURI( url );
1593 panel->mMediaSource->start();
1594
1595 std::cout << "Adding new media panel for " << url << "(" << media_width << "x" << media_height << ") with index " << panel->mId << " - total panels = " << mMediaPanels.size() << std::endl;
1596 }
1597}
1598
1599////////////////////////////////////////////////////////////////////////////////
1600//
1601void LLMediaPluginTest::updateMediaPanel( mediaPanel* panel )
1602{
1603// checkGLError("LLMediaPluginTest::updateMediaPanel");
1604
1605 if ( ! panel )
1606 return;
1607
1608 if(!panel->mMediaSource || !panel->mMediaSource->textureValid())
1609 {
1610 panel->mReadyToRender = false;
1611 return;
1612 }
1613
1614 // take a reference copy of the plugin values since they
1615 // might change during this lifetime of this function
1616 int plugin_media_width = panel->mMediaSource->getWidth();
1617 int plugin_media_height = panel->mMediaSource->getHeight();
1618 int plugin_texture_width = panel->mMediaSource->getBitsWidth();
1619 int plugin_texture_height = panel->mMediaSource->getBitsHeight();
1620
1621 // If the texture isn't created or the media or texture dimensions changed AND
1622 // the sizes are valid then we need to delete the old media texture (if necessary)
1623 // then make a new one.
1624 if ((panel->mMediaTextureHandle == 0 ||
1625 panel->mMediaWidth != plugin_media_width ||
1626 panel->mMediaHeight != plugin_media_height ||
1627 panel->mTextureWidth != plugin_texture_width ||
1628 panel->mTextureHeight != plugin_texture_height) &&
1629 ( plugin_media_width > 0 && plugin_media_height > 0 &&
1630 plugin_texture_width > 0 && plugin_texture_height > 0 ) )
1631 {
1632 std::cout << "Valid media size (" << plugin_media_width << " x " << plugin_media_height
1633 << ") and texture size (" << plugin_texture_width << " x " << plugin_texture_height
1634 << ") for panel with ID=" << panel->mId << " - making texture" << std::endl;
1635
1636 // delete old GL texture
1637 if ( isTexture( panel->mMediaTextureHandle ) )
1638 {
1639 std::cerr << "updateMediaPanel: deleting texture " << panel->mMediaTextureHandle << std::endl;
1640 glDeleteTextures( 1, &panel->mMediaTextureHandle );
1641 panel->mMediaTextureHandle = 0;
1642 }
1643
1644 std::cerr << "before: pick texture is " << panel->mPickTextureHandle << ", media texture is " << panel->mMediaTextureHandle << std::endl;
1645
1646 // make a GL texture based on the dimensions the plugin told us
1647 GLuint new_texture = 0;
1648 glGenTextures( 1, &new_texture );
1649
1650 checkGLError("glGenTextures");
1651
1652 std::cout << "glGenTextures returned " << new_texture << std::endl;
1653
1654 panel->mMediaTextureHandle = new_texture;
1655
1656 bindTexture( panel->mMediaTextureHandle );
1657
1658 std::cout << "Setting texture size to " << plugin_texture_width << " x " << plugin_texture_height << std::endl;
1659 glTexImage2D( GL_TEXTURE_2D, 0,
1660 GL_RGB,
1661 plugin_texture_width, plugin_texture_height,
1662 0, GL_RGB, GL_UNSIGNED_BYTE,
1663 0 );
1664
1665
1666 std::cerr << "after: pick texture is " << panel->mPickTextureHandle << ", media texture is " << panel->mMediaTextureHandle << std::endl;
1667 };
1668
1669 // update our record of the media and texture dimensions
1670 // NOTE: do this after we we check for sizes changes
1671 panel->mMediaWidth = plugin_media_width;
1672 panel->mMediaHeight = plugin_media_height;
1673 panel->mTextureWidth = plugin_texture_width;
1674 panel->mTextureHeight = plugin_texture_height;
1675 if ( plugin_texture_width > 0 )
1676 {
1677 panel->mTextureScaleX = (double)panel->mMediaWidth / (double)panel->mTextureWidth;
1678 };
1679 if ( plugin_texture_height > 0 )
1680 {
1681 panel->mTextureScaleY = (double)panel->mMediaHeight / (double)panel->mTextureHeight;
1682 };
1683
1684 // update the flag which tells us if the media source uses OprnGL coords or not.
1685 panel->mAppTextureCoordsOpenGL = panel->mMediaSource->getTextureCoordsOpenGL();
1686
1687 // Check to see if we have enough to render this panel.
1688 // If we do, set a flag that the display functions use so
1689 // they only render a panel with media if it's ready.
1690 if ( panel->mMediaWidth < 0 ||
1691 panel->mMediaHeight < 0 ||
1692 panel->mTextureWidth < 1 ||
1693 panel->mTextureHeight < 1 ||
1694 panel->mMediaTextureHandle == 0 )
1695 {
1696 panel->mReadyToRender = false;
1697 };
1698}
1699
1700////////////////////////////////////////////////////////////////////////////////
1701//
1702void LLMediaPluginTest::replaceMediaPanel( mediaPanel* panel, std::string url )
1703{
1704 // no media panels so we can't change anything - have to add
1705 if ( mMediaPanels.size() == 0 )
1706 return;
1707
1708 // sanity check
1709 if ( ! panel )
1710 return;
1711
1712 int index;
1713 for(index = 0; index < (int)mMediaPanels.size(); index++)
1714 {
1715 if(mMediaPanels[index] == panel)
1716 break;
1717 }
1718
1719 if(index >= (int)mMediaPanels.size())
1720 {
1721 // panel isn't in mMediaPanels
1722 return;
1723 }
1724
1725 std::cout << "Replacing media panel with index " << panel->mId << std::endl;
1726
1727 int panel_id = panel->mId;
1728
1729 if(mSelectedPanel == panel)
1730 mSelectedPanel = NULL;
1731
1732 delete panel;
1733
1734 // Get the plugin filename using the URL
1735 std::string mime_type = mimeTypeFromUrl( url );
1736 std::string plugin_name = pluginNameFromMimeType( mime_type );
1737
1738 // create a random size for the new media
1739 int media_width;
1740 int media_height;
1741 getRandomMediaSize( media_width, media_height, mime_type );
1742
1743 // make a new plugin
1744 LLPluginClassMedia* media_source = new LLPluginClassMedia(this);
1745
1746 // tell the plugin what size we asked for
1747 media_source->setSize( media_width, media_height );
1748
1749 // Use the launcher start and initialize the plugin
1750#if LL_DARWIN || LL_LINUX
1751 std::string launcher_name( "SLPlugin" );
1752#elif LL_WINDOWS
1753 std::string launcher_name( "SLPlugin.exe" );
1754#endif
1755 media_source->init( launcher_name, plugin_name );
1756 media_source->setDisableTimeout(mDisableTimeout);
1757
1758 // make a new panel and save parameters
1759 panel = new mediaPanel;
1760 panel->mMediaSource = media_source;
1761 panel->mStartUrl = url;
1762 panel->mMimeType = mime_type;
1763 panel->mMediaWidth = media_width;
1764 panel->mMediaHeight = media_height;
1765 panel->mTextureWidth = 0;
1766 panel->mTextureHeight = 0;
1767 panel->mTextureScaleX = 0;
1768 panel->mTextureScaleY = 0;
1769 panel->mMediaTextureHandle = 0;
1770 panel->mPickTextureHandle = 0;
1771 panel->mAppTextureCoordsOpenGL = false; // really need an 'undefined' state here too
1772 panel->mReadyToRender = false;
1773
1774 panel->mId = panel_id;
1775
1776 // Replace the entry in the panels array
1777 mMediaPanels[index] = panel;
1778
1779 // now we have the ID we can use it to make the
1780 // pick texture (id is baked into texture pixels)
1781 makePickTexture( panel->mId, &panel->mPickTextureHandle, &panel->mPickTexturePixels );
1782
1783 // select the panel that was just created
1784 selectPanel( panel );
1785
1786 // load and start the URL
1787 panel->mMediaSource->loadURI( url );
1788 panel->mMediaSource->start();
1789}
1790
1791////////////////////////////////////////////////////////////////////////////////
1792//
1793void LLMediaPluginTest::getRandomMediaSize( int& width, int& height, std::string mime_type )
1794{
1795 // Make a new media source with a random size which we'll either
1796 // directly or the media plugin will tell us what it wants later.
1797 // Use a random size so we can test support for weird media sizes.
1798 // (Almost everything else will get filled in later once the
1799 // plugin responds)
1800 // NB. Do we need to enforce that width is on 4 pixel boundary?
1801 width = ( ( rand() % 170 ) + 30 ) * 4;
1802 height = ( ( rand() % 170 ) + 30 ) * 4;
1803
1804 // adjust this random size if it's a browser so we get
1805 // a more useful size for testing..
1806 if ( mime_type == "text/html" || mime_type == "example/example" )
1807 {
1808 width = ( ( rand() % 100 ) + 100 ) * 4;
1809 height = ( width * ( ( rand() % 400 ) + 1000 ) ) / 1000;
1810 };
1811}
1812
1813////////////////////////////////////////////////////////////////////////////////
1814//
1815void LLMediaPluginTest::remMediaPanel( mediaPanel* panel )
1816{
1817 // always leave one panel
1818 if ( mMediaPanels.size() == 1 )
1819 return;
1820
1821 // sanity check - don't think this can happen but see above for a case where it might...
1822 if ( ! panel )
1823 return;
1824
1825 std::cout << "Removing media panel with index " << panel->mId << " - total panels = " << mMediaPanels.size() - 1 << std::endl;
1826
1827 if(mSelectedPanel == panel)
1828 mSelectedPanel = NULL;
1829
1830 delete panel;
1831
1832 // remove from storage list
1833 for( int i = 0; i < (int)mMediaPanels.size(); ++i )
1834 {
1835 if ( mMediaPanels[ i ] == panel )
1836 {
1837 mMediaPanels.erase( mMediaPanels.begin() + i );
1838 break;
1839 };
1840 };
1841
1842 // select the first panel
1843 selectPanel( mMediaPanels[ 0 ] );
1844}
1845
1846////////////////////////////////////////////////////////////////////////////////
1847//
1848void LLMediaPluginTest::updateStatusBar()
1849{
1850 if ( ! mSelectedPanel )
1851 return;
1852
1853 // cache results - this is a very slow function
1854 static int cached_id = -1;
1855 static int cached_media_width = -1;
1856 static int cached_media_height = -1;
1857 static int cached_texture_width = -1;
1858 static int cached_texture_height = -1;
1859 static bool cached_supports_browser_media = true;
1860 static bool cached_supports_time_media = false;
1861 static int cached_movie_time = -1;
1862
1863 static std::string cached_plugin_version = "";
1864 if (
1865 cached_id == mSelectedPanel->mId &&
1866 cached_media_width == mSelectedPanel->mMediaWidth &&
1867 cached_media_height == mSelectedPanel->mMediaHeight &&
1868 cached_texture_width == mSelectedPanel->mTextureWidth &&
1869 cached_texture_height == mSelectedPanel->mTextureHeight &&
1870 cached_supports_browser_media == mSelectedPanel->mMediaSource->pluginSupportsMediaBrowser() &&
1871 cached_supports_time_media == mSelectedPanel->mMediaSource->pluginSupportsMediaTime() &&
1872 cached_plugin_version == mSelectedPanel->mMediaSource->getPluginVersion() &&
1873 cached_movie_time == (int)mSelectedPanel->mMediaSource->getCurrentTime()
1874 )
1875 {
1876 // nothing changed so don't spend time in this shitty function
1877 return;
1878 };
1879
1880 std::ostringstream stream( "" );
1881
1882 stream.str( "" );
1883 stream.clear();
1884
1885 stream << "Id: ";
1886 stream << std::setw( 2 ) << std::setfill( '0' );
1887 stream << mSelectedPanel->mId;
1888 stream << " | ";
1889 stream << "Media: ";
1890 stream << std::setw( 3 ) << std::setfill( '0' );
1891 stream << mSelectedPanel->mMediaWidth;
1892 stream << " x ";
1893 stream << std::setw( 3 ) << std::setfill( '0' );
1894 stream << mSelectedPanel->mMediaHeight;
1895 stream << " | ";
1896 stream << "Texture: ";
1897 stream << std::setw( 4 ) << std::setfill( '0' );
1898 stream << mSelectedPanel->mTextureWidth;
1899 stream << " x ";
1900 stream << std::setw( 4 ) << std::setfill( '0' );
1901 stream << mSelectedPanel->mTextureHeight;
1902 stream << " | ";
1903 if ( mSelectedPanel->mMediaSource->pluginSupportsMediaBrowser() )
1904 stream << "BROWSER";
1905 else
1906 if ( mSelectedPanel->mMediaSource->pluginSupportsMediaTime() )
1907 stream << "TIME ";
1908 stream << " | ";
1909 stream << mSelectedPanel->mMediaSource->getPluginVersion();
1910 stream << " | ";
1911 if ( mSelectedPanel->mMediaSource->pluginSupportsMediaTime() )
1912 {
1913 stream << std::setw( 3 ) << std::setfill( '0' );
1914 stream << (int)mSelectedPanel->mMediaSource->getCurrentTime();
1915 stream << " / ";
1916 stream << std::setw( 3 ) << std::setfill( '0' );
1917 stream << (int)mSelectedPanel->mMediaSource->getDuration();
1918 stream << " @ ";
1919 stream << (int)mSelectedPanel->mMediaSource->getCurrentPlayRate();
1920 stream << " | ";
1921 };
1922
1923 glutSetWindow( mBottomGLUIWindow->get_glut_window_id() );
1924 mStatusText->set_text( const_cast< char*>( stream.str().c_str() ) );
1925 glutSetWindow( mAppWindow );
1926
1927 // caching
1928 cached_id = mSelectedPanel->mId;
1929 cached_media_width = mSelectedPanel->mMediaWidth;
1930 cached_media_height = mSelectedPanel->mMediaHeight;
1931 cached_texture_width = mSelectedPanel->mTextureWidth;
1932 cached_texture_height = mSelectedPanel->mTextureHeight;
1933 cached_supports_browser_media = mSelectedPanel->mMediaSource->pluginSupportsMediaBrowser();
1934 cached_supports_time_media = mSelectedPanel->mMediaSource->pluginSupportsMediaTime();
1935 cached_plugin_version = mSelectedPanel->mMediaSource->getPluginVersion();
1936 cached_movie_time = (int)mSelectedPanel->mMediaSource->getCurrentTime();
1937}
1938
1939////////////////////////////////////////////////////////////////////////////////
1940//
1941void LLMediaPluginTest::dumpPanelInfo()
1942{
1943 std::cout << std::endl << "===== Media Panels =====" << std::endl;
1944 for( int i = 0; i < (int)mMediaPanels.size(); ++i )
1945 {
1946 std::cout << std::setw( 2 ) << std::setfill( '0' );
1947 std::cout << i + 1 << "> ";
1948 std::cout << "Id: ";
1949 std::cout << std::setw( 2 ) << std::setfill( '0' );
1950 std::cout << mMediaPanels[ i ]->mId;
1951 std::cout << " | ";
1952 std::cout << "Media: ";
1953 std::cout << std::setw( 3 ) << std::setfill( '0' );
1954 std::cout << mMediaPanels[ i ]->mMediaWidth;
1955 std::cout << " x ";
1956 std::cout << std::setw( 3 ) << std::setfill( '0' );
1957 std::cout << mMediaPanels[ i ]->mMediaHeight;
1958 std::cout << " | ";
1959 std::cout << "Texture: ";
1960 std::cout << std::setw( 4 ) << std::setfill( '0' );
1961 std::cout << mMediaPanels[ i ]->mTextureWidth;
1962 std::cout << " x ";
1963 std::cout << std::setw( 4 ) << std::setfill( '0' );
1964 std::cout << mMediaPanels[ i ]->mTextureHeight;
1965 std::cout << " | ";
1966 if ( mMediaPanels[ i ] == mSelectedPanel )
1967 std::cout << "(selected)";
1968
1969 std::cout << std::endl;
1970 };
1971 std::cout << "========================" << std::endl;
1972}
1973
1974////////////////////////////////////////////////////////////////////////////////
1975//
1976void LLMediaPluginTest::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
1977{
1978 // Uncomment this to make things much, much quieter.
1979// return;
1980
1981 switch(event)
1982 {
1983 case MEDIA_EVENT_CONTENT_UPDATED:
1984 // too spammy -- don't log these
1985// std::cerr << "Media event: MEDIA_EVENT_CONTENT_UPDATED " << std::endl;
1986 break;
1987
1988 case MEDIA_EVENT_TIME_DURATION_UPDATED:
1989 // too spammy -- don't log these
1990// std::cerr << "Media event: MEDIA_EVENT_TIME_DURATION_UPDATED, time is " << self->getCurrentTime() << " of " << self->getDuration() << std::endl;
1991 break;
1992
1993 case MEDIA_EVENT_SIZE_CHANGED:
1994 std::cerr << "Media event: MEDIA_EVENT_SIZE_CHANGED " << std::endl;
1995 break;
1996
1997 case MEDIA_EVENT_CURSOR_CHANGED:
1998 std::cerr << "Media event: MEDIA_EVENT_CURSOR_CHANGED, new cursor is " << self->getCursorName() << std::endl;
1999 break;
2000
2001 case MEDIA_EVENT_NAVIGATE_BEGIN:
2002 std::cerr << "Media event: MEDIA_EVENT_NAVIGATE_BEGIN " << std::endl;
2003 break;
2004
2005 case MEDIA_EVENT_NAVIGATE_COMPLETE:
2006 std::cerr << "Media event: MEDIA_EVENT_NAVIGATE_COMPLETE, result string is: " << self->getNavigateResultString() << std::endl;
2007 break;
2008
2009 case MEDIA_EVENT_PROGRESS_UPDATED:
2010 std::cerr << "Media event: MEDIA_EVENT_PROGRESS_UPDATED, loading at " << self->getProgressPercent() << "%" << std::endl;
2011 break;
2012
2013 case MEDIA_EVENT_STATUS_TEXT_CHANGED:
2014 std::cerr << "Media event: MEDIA_EVENT_STATUS_TEXT_CHANGED, new status text is: " << self->getStatusText() << std::endl;
2015 break;
2016
2017 case MEDIA_EVENT_NAME_CHANGED:
2018 std::cerr << "Media event: MEDIA_EVENT_NAME_CHANGED, new name is: " << self->getMediaName() << std::endl;
2019 glutSetWindowTitle( self->getMediaName().c_str() );
2020 break;
2021
2022 case MEDIA_EVENT_LOCATION_CHANGED:
2023 {
2024 std::cerr << "Media event: MEDIA_EVENT_LOCATION_CHANGED, new uri is: " << self->getLocation() << std::endl;
2025 mediaPanel* panel = findMediaPanel(self);
2026 if(panel != NULL)
2027 {
2028 panel->mStartUrl = self->getLocation();
2029 if(panel == mSelectedPanel)
2030 {
2031 mUrlEdit->set_text(const_cast<char*>(panel->mStartUrl.c_str()) );
2032 }
2033 }
2034 }
2035 break;
2036
2037 case MEDIA_EVENT_CLICK_LINK_HREF:
2038 std::cerr << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, uri is " << self->getClickURL() << std::endl;
2039 break;
2040
2041 case MEDIA_EVENT_CLICK_LINK_NOFOLLOW:
2042 std::cerr << "Media event: MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is " << self->getClickURL() << std::endl;
2043 break;
2044
2045 case MEDIA_EVENT_PLUGIN_FAILED:
2046 std::cerr << "Media event: MEDIA_EVENT_PLUGIN_FAILED" << std::endl;
2047 break;
2048
2049 case MEDIA_EVENT_PLUGIN_FAILED_LAUNCH:
2050 std::cerr << "Media event: MEDIA_EVENT_PLUGIN_FAILED_LAUNCH" << std::endl;
2051 break;
2052 }
2053}
2054
2055////////////////////////////////////////////////////////////////////////////////
2056//
2057static void gluiCallbackWrapper( int control_id )
2058{
2059 if ( gApplication )
2060 gApplication->gluiCallback( control_id );
2061}
2062
2063////////////////////////////////////////////////////////////////////////////////
2064//
2065void glutReshape( int width, int height )
2066{
2067 if ( gApplication )
2068 gApplication->reshape( width, height );
2069};
2070
2071////////////////////////////////////////////////////////////////////////////////
2072//
2073void glutDisplay()
2074{
2075 if ( gApplication )
2076 gApplication->display();
2077};
2078
2079////////////////////////////////////////////////////////////////////////////////
2080//
2081void glutIdle(int update_ms)
2082{
2083 GLUI_Master.set_glutTimerFunc( update_ms, glutIdle, update_ms);
2084
2085 if ( gApplication )
2086 gApplication->idle();
2087
2088};
2089
2090////////////////////////////////////////////////////////////////////////////////
2091//
2092void glutKeyboard( unsigned char key, int x, int y )
2093{
2094 if ( gApplication )
2095 gApplication->keyboard( key );
2096};
2097
2098////////////////////////////////////////////////////////////////////////////////
2099//
2100void glutMousePassive( int x, int y )
2101{
2102 if ( gApplication )
2103 gApplication->mousePassive( x, y );
2104}
2105
2106////////////////////////////////////////////////////////////////////////////////
2107//
2108void glutMouseMove( int x , int y )
2109{
2110 if ( gApplication )
2111 gApplication->mouseMove( x, y );
2112}
2113
2114////////////////////////////////////////////////////////////////////////////////
2115//
2116void glutMouseButton( int button, int state, int x, int y )
2117{
2118 if ( gApplication )
2119 gApplication->mouseButton( button, state, x, y );
2120}
2121
2122////////////////////////////////////////////////////////////////////////////////
2123//
2124int main( int argc, char* argv[] )
2125{
2126#if LL_DARWIN
2127 // Set the current working directory to <application bundle>/Contents/Resources/
2128 CFURLRef resources_url = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle());
2129 if(resources_url != NULL)
2130 {
2131 CFStringRef resources_string = CFURLCopyFileSystemPath(resources_url, kCFURLPOSIXPathStyle);
2132 CFRelease(resources_url);
2133 if(resources_string != NULL)
2134 {
2135 char buffer[PATH_MAX] = "";
2136 if(CFStringGetCString(resources_string, buffer, sizeof(buffer), kCFStringEncodingUTF8))
2137 {
2138 chdir(buffer);
2139 }
2140 CFRelease(resources_string);
2141 }
2142 }
2143#endif
2144
2145 glutInit( &argc, argv );
2146 glutInitDisplayMode( GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB );
2147
2148 const int app_window_x = 80;
2149 const int app_window_y = 0;
2150 const int app_window_width = 960;
2151 const int app_window_height = 960;
2152
2153 glutInitWindowPosition( app_window_x, app_window_y );
2154 glutInitWindowSize( app_window_width, app_window_height );
2155
2156 int app_window_handle = glutCreateWindow( "LLMediaPluginTest" );
2157
2158 glutDisplayFunc( glutDisplay );
2159
2160 GLUI_Master.set_glutReshapeFunc( glutReshape );
2161 GLUI_Master.set_glutKeyboardFunc( glutKeyboard );
2162 GLUI_Master.set_glutMouseFunc( glutMouseButton );
2163
2164 glutPassiveMotionFunc( glutMousePassive );
2165 glutMotionFunc( glutMouseMove );
2166
2167 glutSetWindow( app_window_handle );
2168
2169 gApplication = new LLMediaPluginTest( app_window_handle, app_window_width, app_window_height );
2170
2171 // update at approximately 60hz
2172 int update_ms = 1000 / 60;
2173
2174 GLUI_Master.set_glutTimerFunc( update_ms, glutIdle, update_ms);
2175
2176 glutMainLoop();
2177
2178 delete gApplication;
2179}