aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/test_apps/llplugintest
diff options
context:
space:
mode:
authorArmin Weatherwax2010-06-14 12:04:49 +0200
committerArmin Weatherwax2010-09-23 15:38:25 +0200
commit35df5441d3e2789663532c948731aff3a1e04728 (patch)
treeac7674289784a5f96106ea507637055a8dada78a /linden/indra/test_apps/llplugintest
parentChanged version to Experimental 2010.09.18 (diff)
downloadmeta-impy-35df5441d3e2789663532c948731aff3a1e04728.zip
meta-impy-35df5441d3e2789663532c948731aff3a1e04728.tar.gz
meta-impy-35df5441d3e2789663532c948731aff3a1e04728.tar.bz2
meta-impy-35df5441d3e2789663532c948731aff3a1e04728.tar.xz
llmediaplugins first step
Diffstat (limited to '')
-rw-r--r--linden/indra/test_apps/llplugintest/CMakeLists.txt378
-rw-r--r--linden/indra/test_apps/llplugintest/bookmarks.txt28
-rw-r--r--linden/indra/test_apps/llplugintest/demo_media_plugin.cpp472
-rw-r--r--linden/indra/test_apps/llplugintest/demo_media_plugin_2.cpp578
-rw-r--r--linden/indra/test_apps/llplugintest/demo_plugin.cpp220
-rw-r--r--linden/indra/test_apps/llplugintest/llmediaplugintest.cpp2179
-rw-r--r--linden/indra/test_apps/llplugintest/llmediaplugintest.h201
-rw-r--r--linden/indra/test_apps/llplugintest/media_mappings.txt3
-rw-r--r--linden/indra/test_apps/llplugintest/media_plugin_test.cpp511
-rw-r--r--linden/indra/test_apps/llplugintest/media_simple_test.cpp460
-rw-r--r--linden/indra/test_apps/llplugintest/plugin_host.cpp92
-rw-r--r--linden/indra/test_apps/llplugintest/plugin_process_launcher.cpp197
12 files changed, 5319 insertions, 0 deletions
diff --git a/linden/indra/test_apps/llplugintest/CMakeLists.txt b/linden/indra/test_apps/llplugintest/CMakeLists.txt
new file mode 100644
index 0000000..a6cb740
--- /dev/null
+++ b/linden/indra/test_apps/llplugintest/CMakeLists.txt
@@ -0,0 +1,378 @@
1# -*- cmake -*-
2
3project(llplugintest)
4
5include(00-Common)
6include(FindOpenGL)
7include(LLCommon)
8include(LLPlugin)
9include(Linking)
10include(PluginAPI)
11include(LLImage)
12include(LLMath)
13include(LLMessage)
14include(LLRender)
15include(LLWindow)
16include(Glut)
17include(Glui)
18
19include_directories(
20 ${LLPLUGIN_INCLUDE_DIRS}
21 ${LLCOMMON_INCLUDE_DIRS}
22 ${LLIMAGE_INCLUDE_DIRS}
23 ${LLMATH_INCLUDE_DIRS}
24 ${LLMESSAGE_INCLUDE_DIRS}
25 ${LLRENDER_INCLUDE_DIRS}
26 ${LLWINDOW_INCLUDE_DIRS}
27)
28
29if (DARWIN)
30 include(CMakeFindFrameworks)
31 find_library(COREFOUNDATION_LIBRARY CoreFoundation)
32endif (DARWIN)
33
34### demo_plugin
35
36#set(demo_plugin_SOURCE_FILES
37# demo_plugin.cpp
38# )
39#
40#add_library(demo_plugin
41# SHARED
42# ${demo_plugin_SOURCE_FILES}
43#)
44#
45#target_link_libraries(demo_plugin
46# ${LLPLUGIN_LIBRARIES}
47# ${LLCOMMON_LIBRARIES}
48# ${PLUGIN_API_WINDOWS_LIBRARIES}
49#)
50#
51#add_dependencies(demo_plugin
52# ${LLPLUGIN_LIBRARIES}
53# ${LLCOMMON_LIBRARIES}
54#)
55#
56#if (DARWIN)
57# # Don't prepend 'lib' to the executable name, and don't embed a full path in the library's install name
58# set_target_properties(
59# demo_plugin
60# PROPERTIES
61# PREFIX ""
62# BUILD_WITH_INSTALL_RPATH 1
63# INSTALL_NAME_DIR "@executable_path"
64# )
65#endif (DARWIN)
66
67### plugin_host
68
69#set(plugin_host_SOURCE_FILES
70# plugin_host.cpp
71# )
72#
73#add_executable(plugin_host
74# WIN32
75# ${plugin_host_SOURCE_FILES}
76#)
77#
78#set_target_properties(plugin_host
79# PROPERTIES
80# WIN32_EXECUTABLE
81# FALSE
82#)
83#
84#target_link_libraries(plugin_host
85# ${LLPLUGIN_LIBRARIES}
86# ${LLCOMMON_LIBRARIES}
87# ${PLUGIN_API_WINDOWS_LIBRARIES}
88#)
89#
90#add_dependencies(plugin_host
91# demo_plugin
92# ${LLPLUGIN_LIBRARIES}
93# ${LLCOMMON_LIBRARIES}
94#)
95
96### plugin_process_launcher
97
98#set(plugin_process_launcher_SOURCE_FILES
99# plugin_process_launcher.cpp
100# )
101#
102#add_executable(plugin_process_launcher
103# WIN32
104# ${plugin_process_launcher_SOURCE_FILES}
105#)
106#
107#set_target_properties(plugin_process_launcher
108# PROPERTIES
109# WIN32_EXECUTABLE
110# FALSE
111#)
112#
113#target_link_libraries(plugin_process_launcher
114# ${LLPLUGIN_LIBRARIES}
115# ${LLMESSAGE_LIBRARIES}
116# ${LLCOMMON_LIBRARIES}
117# ${PLUGIN_API_WINDOWS_LIBRARIES}
118#)
119#
120#add_dependencies(plugin_process_launcher
121# SLPlugin
122# demo_plugin
123# ${LLPLUGIN_LIBRARIES}
124# ${LLMESSAGE_LIBRARIES}
125# ${LLCOMMON_LIBRARIES}
126#)
127
128### media_simple_test
129
130#set(media_simple_test_SOURCE_FILES
131# media_simple_test.cpp
132# )
133#
134#add_executable(media_simple_test
135# WIN32
136# ${media_simple_test_SOURCE_FILES}
137#)
138#
139#add_dependencies(media_simple_test copy_win_libs)
140#
141#set_target_properties(media_simple_test
142# PROPERTIES
143# WIN32_EXECUTABLE
144# FALSE
145#)
146#
147#target_link_libraries(media_simple_test
148# ${GLUT_LIBRARY}
149# ${OPENGL_LIBRARIES}
150# ${LLCOMMON_LIBRARIES}
151#)
152
153### media_plugin_test
154
155#set(media_plugin_test_SOURCE_FILES
156# media_plugin_test.cpp
157# )
158#
159#add_executable(media_plugin_test
160# WIN32
161# ${media_plugin_test_SOURCE_FILES}
162#)
163#
164#set_target_properties(media_plugin_test
165# PROPERTIES
166# WIN32_EXECUTABLE
167# FALSE
168#)
169#
170#target_link_libraries(media_plugin_test
171# ${GLUT_LIBRARY}
172# ${OPENGL_LIBRARIES}
173# ${LLPLUGIN_LIBRARIES}
174# ${LLMESSAGE_LIBRARIES}
175# ${LLCOMMON_LIBRARIES}
176# ${PLUGIN_API_WINDOWS_LIBRARIES}
177#)
178#
179#add_dependencies(media_plugin_test
180# copy_win_libs
181# SLPlugin
182# demo_media_plugin
183# ${LLPLUGIN_LIBRARIES}
184# ${LLMESSAGE_LIBRARIES}
185# ${LLCOMMON_LIBRARIES}
186#)
187
188### demo_media_plugin
189
190#set(demo_media_plugin_SOURCE_FILES
191# demo_media_plugin.cpp
192# )
193#
194#add_library(demo_media_plugin
195# SHARED
196# ${demo_media_plugin_SOURCE_FILES}
197#)
198#
199#target_link_libraries(demo_media_plugin
200# ${LLPLUGIN_LIBRARIES}
201# ${LLCOMMON_LIBRARIES}
202# ${PLUGIN_API_WINDOWS_LIBRARIES}
203#)
204#
205#add_dependencies(demo_media_plugin
206# ${LLPLUGIN_LIBRARIES}
207# ${LLCOMMON_LIBRARIES}
208#)
209#
210#if (DARWIN)
211# # Don't prepend 'lib' to the executable name, and don't embed a full path in the library's install name
212# set_target_properties(
213# demo_media_plugin
214# PROPERTIES
215# PREFIX ""
216# BUILD_WITH_INSTALL_RPATH 1
217# INSTALL_NAME_DIR "@executable_path"
218# )
219#endif (DARWIN)
220
221### demo_media_plugin_2
222
223#set(demo_media_plugin_2_SOURCE_FILES
224# demo_media_plugin_2.cpp
225# )
226#
227#add_library(demo_media_plugin_2
228# SHARED
229# ${demo_media_plugin_2_SOURCE_FILES}
230#)
231#
232#target_link_libraries(demo_media_plugin_2
233# ${LLPLUGIN_LIBRARIES}
234# ${LLCOMMON_LIBRARIES}
235# ${PLUGIN_API_WINDOWS_LIBRARIES}
236#)
237#
238#add_dependencies(demo_media_plugin_2
239# ${LLPLUGIN_LIBRARIES}
240# ${LLCOMMON_LIBRARIES}
241#)
242#
243#if (DARWIN)
244# # Don't prepend 'lib' to the executable name, and don't embed a full path in the library's install name
245# set_target_properties(
246# demo_media_plugin_2
247# PROPERTIES
248# PREFIX ""
249# BUILD_WITH_INSTALL_RPATH 1
250# INSTALL_NAME_DIR "@executable_path"
251# )
252#endif (DARWIN)
253
254### llmediaplugintest
255
256set(llmediaplugintest_SOURCE_FILES
257 llmediaplugintest.cpp
258 llmediaplugintest.h
259 bookmarks.txt
260 )
261
262add_executable(llmediaplugintest
263 WIN32
264 ${llmediaplugintest_SOURCE_FILES}
265)
266
267set_target_properties(llmediaplugintest
268 PROPERTIES
269 WIN32_EXECUTABLE
270 FALSE
271)
272
273target_link_libraries(llmediaplugintest
274 ${GLUT_LIBRARY}
275 ${GLUI_LIBRARY}
276 ${OPENGL_LIBRARIES}
277 ${LLPLUGIN_LIBRARIES}
278 ${LLMESSAGE_LIBRARIES}
279 ${LLCOMMON_LIBRARIES}
280 ${PLUGIN_API_WINDOWS_LIBRARIES}
281)
282
283if (DARWIN)
284 # The testbed needs to use a couple of CoreFoundation calls now, to deal with being a bundled app.
285 target_link_libraries(llmediaplugintest
286 ${COREFOUNDATION_LIBRARY}
287 )
288endif (DARWIN)
289
290add_dependencies(llmediaplugintest
291 copy_win_libs
292 SLPlugin
293 media_plugin_quicktime
294 media_plugin_webkit
295 media_plugin_example
296 ${LLPLUGIN_LIBRARIES}
297 ${LLMESSAGE_LIBRARIES}
298 ${LLCOMMON_LIBRARIES}
299)
300
301# turn off weird GLUI pragma
302add_definitions(-DGLUI_NO_LIB_PRAGMA)
303
304if (DARWIN OR LINUX)
305 # glui.h contains code that triggers the "overloaded-virtual" warning in gcc.
306 set_source_files_properties(llmediaplugintest.cpp PROPERTIES COMPILE_FLAGS "-Wno-overloaded-virtual")
307endif (DARWIN OR LINUX)
308
309# Gather build products of the various dependencies into the build directory for the testbed.
310
311if (DARWIN)
312 # path inside the app bundle where we'll need to copy plugins and other related files
313 set(PLUGINS_DESTINATION_DIR
314 ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/llmediaplugintest.app/Contents/Resources
315 )
316
317 # create the Contents/Resources directory
318 add_custom_command(
319 TARGET llmediaplugintest POST_BUILD
320 COMMAND ${CMAKE_COMMAND}
321 ARGS
322 -E
323 make_directory
324 ${PLUGINS_DESTINATION_DIR}
325 COMMENT "Creating Resources directory in app bundle."
326 )
327else (DARWIN)
328 set(PLUGINS_DESTINATION_DIR
329 ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/
330 )
331endif (DARWIN)
332
333get_target_property(BUILT_SLPLUGIN SLPlugin LOCATION)
334add_custom_command(TARGET llmediaplugintest POST_BUILD
335 COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_SLPLUGIN} ${PLUGINS_DESTINATION_DIR}
336 DEPENDS ${BUILT_SLPLUGIN}
337)
338
339if (DARWIN OR WINDOWS)
340 get_target_property(BUILT_WEBKIT_PLUGIN media_plugin_webkit LOCATION)
341 add_custom_command(TARGET llmediaplugintest POST_BUILD
342 COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_WEBKIT_PLUGIN} ${PLUGINS_DESTINATION_DIR}
343 DEPENDS ${BUILT_WEBKIT_PLUGIN}
344 )
345
346 get_target_property(BUILT_QUICKTIME_PLUGIN media_plugin_quicktime LOCATION)
347 add_custom_command(TARGET llmediaplugintest POST_BUILD
348 COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_QUICKTIME_PLUGIN} ${PLUGINS_DESTINATION_DIR}
349 DEPENDS ${BUILT_QUICKTIME_PLUGIN}
350 )
351
352 get_target_property(BUILT_EXAMPLE_PLUGIN media_plugin_example LOCATION)
353 add_custom_command(TARGET llmediaplugintest POST_BUILD
354 COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_EXAMPLE_PLUGIN} ${PLUGINS_DESTINATION_DIR}
355 DEPENDS ${BUILT_EXAMPLE_PLUGIN}
356 )
357
358 # copy over bookmarks file if llmediaplugintest gets built
359 get_target_property(BUILT_LLMEDIAPLUGINTEST llmediaplugintest LOCATION)
360 add_custom_command(TARGET llmediaplugintest POST_BUILD
361 COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/bookmarks.txt ${CMAKE_CURRENT_BINARY_DIR}/
362 DEPENDS ${BUILT_LLMEDIAPLUGINTEST}
363 )
364 # also copy it to the same place as SLPlugin, which is what the mac wants...
365 add_custom_command(TARGET llmediaplugintest POST_BUILD
366 COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/bookmarks.txt ${PLUGINS_DESTINATION_DIR}
367 DEPENDS ${BUILT_LLMEDIAPLUGINTEST}
368 )
369endif (DARWIN OR WINDOWS)
370
371if (DARWIN)
372 add_custom_command(TARGET llmediaplugintest POST_BUILD
373 COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libllqtwebkit.dylib ${PLUGINS_DESTINATION_DIR}
374 DEPENDS ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libllqtwebkit.dylib
375 )
376endif (DARWIN)
377
378
diff --git a/linden/indra/test_apps/llplugintest/bookmarks.txt b/linden/indra/test_apps/llplugintest/bookmarks.txt
new file mode 100644
index 0000000..796cc5d
--- /dev/null
+++ b/linden/indra/test_apps/llplugintest/bookmarks.txt
@@ -0,0 +1,28 @@
1# format is description, url (don't put ',' chars in description :)
2# if no ',' found, whole line is used for both description and url
3(WK) Google Home Page,http://www.google.com
4(WK) BBC News Home Page,http://news.bbc.co.uk
5(WK) Second Life,http://secondlife.com
6(WK) WebKit Home ,http://www.webkit.org
7(WK) Yahoo News,http://news.yahoo.com
8(WK) Canvas Paint (DHTML version of MS Paint),http://www.canvaspaint.org
9(WK) DHTML Lemmings!,http://www.elizium.nu/scripts/lemmings/
10(WK) DHTML graphics demos,http://www.dhteumeuleu.com/
11(WK) Neat Javascript 3D,http://gyu.que.jp/jscloth/
12(QT) Local sample,file:///C|/Program Files/QuickTime/Sample.mov
13(QT) Movie - Watchmen Trailer,http://movies.apple.com/movies/wb/watchmen/watchmen-tlr2_480p.mov
14(QT) Movie - Transformers - Revenge of the Fallen,http://movies.apple.com/movies/paramount/transformers2/transformersrevengeofthefallen-tlr1_h.320.mov
15(QT) Movie - Terminator Salvation,http://movies.apple.com/movies/wb/terminatorsalvation/terminatorsalvation-tlr3_h.320.mov
16(QT) Movie - Angels and Demons,http://movies.apple.com/movies/sony_pictures/angelsanddemons/angelsanddemons-video_h.320.mov
17(QT) Movie - Sin City Trailer,http://movies.apple.com/movies/miramax/sin_city/sin_city_480.mov
18(QT) Movie - The Incredibles Trailer,http://movies.apple.com/movies/disney/the_incredibles/the_incredibles-tlr_a480.mov
19(QT) Movie - Streaming Apple Event,http://stream.qtv.apple.com/events/mar/0903lajkszg/m_090374535329zdwg_650_ref.mov
20(QT) Movie - MPEG-4 from Amazon S3,http://s3.amazonaws.com/callum-linden/flashdemo/interactive_flash_demo.mp4
21(QT) Movie - Star Trek,http://movies.apple.com/movies/paramount/star_trek/startrek-tlr3_h.320.mov
22(QT) Movie - Ice Age 3,http://movies.apple.com/movies/fox/ice_age_iii/iceage3-tlrd_h.320.mov
23(QT) Movie - AstroBoy,http://movies.apple.com/movies/summit/astroboy/astroboy-tsr_h.320.mov
24(QT) Movie - Ante Up,http://movies.apple.com/movies/independent/anteup/anteup_h.320.mov
25(QT) Movie - Every Little Step,http://movies.apple.com/movies/sony/everylittlestep/everylittlestep-clip_h.320.mov
26(QT) Movie - The Informers,http://movies.apple.com/movies/independent/theinformers/theinformers_h.320.mov
27(QT) Animated GIF,http://upload.wikimedia.org/wikipedia/commons/4/44/Optical.greysquares.arp-animated.gif
28(QT) Apple Text Descriptors,http://ubrowser.com/tmp/apple_text.txt
diff --git a/linden/indra/test_apps/llplugintest/demo_media_plugin.cpp b/linden/indra/test_apps/llplugintest/demo_media_plugin.cpp
new file mode 100644
index 0000000..89e15fd
--- /dev/null
+++ b/linden/indra/test_apps/llplugintest/demo_media_plugin.cpp
@@ -0,0 +1,472 @@
1/**
2 * @file demo_plugin.cpp
3 * @brief Test plugin to be loaded by the llplugin testbed.
4 *
5 * $LicenseInfo:firstyear=2008&license=viewergpl$
6 *
7 * Copyright (c) 2008-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://secondlifegrid.net/programs/open_source/licensing/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
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32
33#include "linden_common.h"
34
35#include "llgl.h"
36
37#include "llplugininstance.h"
38#include "llpluginmessage.h"
39#include "llpluginmessageclasses.h"
40
41// TODO: Make sure that the only symbol exported from this library is LLPluginInitEntryPoint
42
43class DemoMediaPlugin
44{
45public:
46
47 static int init(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data);
48
49private:
50 DemoMediaPlugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
51 ~DemoMediaPlugin();
52
53 static void staticReceiveMessage(const char *message_string, void **user_data);
54 void receiveMessage(const char *message_string);
55 void sendMessage(const LLPluginMessage &message);
56 void setDirty(int left, int top, int right, int bottom);
57
58 LLPluginInstance::sendMessageFunction mHostSendFunction;
59 void *mHostUserData;
60 bool mDeleteMe;
61
62 class SharedSegmentInfo
63 {
64 public:
65 void *mAddress;
66 size_t mSize;
67 };
68
69 typedef std::map<std::string, SharedSegmentInfo> SharedSegmentMap;
70
71 SharedSegmentMap mSharedSegments;
72
73public:
74
75 void clear(void)
76 {
77// return;
78
79 if(mPixels != NULL)
80 {
81 for( int y = 0; y < mHeight; ++y )
82 {
83 unsigned char *row = mPixels + ( y * mTextureWidth * mDepth);
84 for(int x = 0; x < mWidth; ++x)
85 {
86 unsigned char *pixel = row + (x * mDepth);
87 if(0)
88 {
89 pixel[0] = 0x20;
90 pixel[1] = 0x20;
91 pixel[2] = 0x20;
92 }
93 else
94 {
95 pixel[0] = rand() % 0x40;
96 pixel[1] = rand() % 0x40;
97 pixel[2] = rand() % 0x40;
98 }
99 }
100 }
101
102 setDirty(0, 0, mWidth, mHeight);
103 }
104 };
105
106 ////////////////////////////////////////////////////////////////////////////////
107 //
108 void update()
109 {
110 const time_t interval = 5;
111 static time_t last_time = time( NULL );
112 time_t cur_time = time( NULL );
113
114 if ( cur_time - last_time > interval )
115 {
116 clear();
117
118 last_time = cur_time;
119 };
120 };
121
122 ////////////////////////////////////////////////////////////////////////////////
123 //
124 void write_pixel( int x, int y, unsigned char r, unsigned char g, unsigned char b )
125 {
126 // make sure we don't write outside the buffer
127 if((x < 0) || (x >= mWidth) || (y < 0) || (y >= mHeight))
128 return;
129
130 if(mPixels != NULL)
131 {
132 unsigned char *pixel = mPixels;
133 pixel += y * mTextureWidth * mDepth; // row offset
134 pixel += (x * mDepth); // columm offset
135 pixel[0] = b;
136 pixel[1] = g;
137 pixel[2] = r;
138
139 setDirty(x, y, x+1, y+1);
140 }
141 }
142
143 ////////////////////////////////////////////////////////////////////////////////
144 //
145 void mouseDown( int x, int y )
146 {
147 write_pixel( x, y, 0xff, 0x00, 0x00 );
148 };
149
150 ////////////////////////////////////////////////////////////////////////////////
151 //
152 void mouseUp( int x, int y )
153 {
154 write_pixel( x, y, 0xff, 0xff, 0x00 );
155 };
156
157 ////////////////////////////////////////////////////////////////////////////////
158 //
159 void mouseMove( int x, int y )
160 {
161 write_pixel( x , y , 0xff, 0x00, 0xff );
162 };
163
164 ////////////////////////////////////////////////////////////////////////////////
165 //
166 void keyPress( unsigned char key )
167 {
168 };
169
170private:
171 unsigned char* mPixels;
172 int mWidth;
173 int mHeight;
174 int mTextureWidth;
175 int mTextureHeight;
176 int mDepth;
177};
178
179int DemoMediaPlugin::init(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data)
180{
181 DemoMediaPlugin *self = new DemoMediaPlugin(host_send_func, host_user_data);
182 *plugin_send_func = staticReceiveMessage;
183 *plugin_user_data = (void*)self;
184
185 return 0;
186}
187
188
189DemoMediaPlugin::DemoMediaPlugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data)
190{
191 std::cerr << "DemoMediaPlugin constructor" << std::endl;
192
193 mHostSendFunction = host_send_func;
194 mHostUserData = host_user_data;
195 mDeleteMe = false;
196}
197
198DemoMediaPlugin::~DemoMediaPlugin()
199{
200 std::cerr << "DemoMediaPlugin destructor" << std::endl;
201}
202
203void DemoMediaPlugin::staticReceiveMessage(const char *message_string, void **user_data)
204{
205 DemoMediaPlugin *self = (DemoMediaPlugin*)*user_data;
206
207 if(self != NULL)
208 {
209 self->receiveMessage(message_string);
210
211 // If the plugin has processed the delete message, delete it.
212 if(self->mDeleteMe)
213 {
214 delete self;
215 *user_data = NULL;
216 }
217 }
218}
219
220void DemoMediaPlugin::receiveMessage(const char *message_string)
221{
222// std::cerr << "DemoMediaPlugin::receiveMessage: received message: \"" << message_string << "\"" << std::endl;
223 LLPluginMessage message_in;
224
225 if(message_in.parse(message_string) >= 0)
226 {
227 std::string message_class = message_in.getClass();
228 std::string message_name = message_in.getName();
229 if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE)
230 {
231 if(message_name == "init")
232 {
233 LLPluginMessage message("base", "init_response");
234 LLSD versions = LLSD::emptyMap();
235 versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION;
236 versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION;
237 // Normally a plugin would only specify one of these two subclasses, but this is a demo...
238 versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION;
239 versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME] = LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION;
240 message.setValueLLSD("versions", versions);
241 sendMessage(message);
242
243 // Plugin gets to decide the texture parameters to use.
244 mDepth = 3;
245
246 message.setMessage(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params");
247 message.setValueS32("depth", mDepth);
248 message.setValueU32("internalformat", GL_RGB);
249 message.setValueU32("format", GL_RGB);
250 message.setValueU32("type", GL_UNSIGNED_BYTE);
251 message.setValueBoolean("coords_opengl", false); // true == use OpenGL-style coordinates, false == (0,0) is upper left.
252 sendMessage(message);
253 }
254 else if(message_name == "idle")
255 {
256 // no response is necessary here.
257 update();
258 }
259 else if(message_name == "shutdown")
260 {
261 sendMessage(LLPluginMessage("base", "shutdown_response"));
262
263 mDeleteMe = true;
264 }
265 else if(message_name == "shm_added")
266 {
267 SharedSegmentInfo info;
268 info.mAddress = (void*)message_in.getValueU32("address");
269 info.mSize = (size_t)message_in.getValueS32("size");
270 std::string name = message_in.getValue("name");
271
272
273 std::cerr << "DemoMediaPlugin::receiveMessage: shared memory added, name: " << name
274 << ", size: " << info.mSize
275 << ", address: " << info.mAddress
276 << std::endl;
277
278 mSharedSegments.insert(SharedSegmentMap::value_type(name, info));
279
280 }
281 else if(message_name == "shm_remove")
282 {
283 std::string name = message_in.getValue("name");
284
285 std::cerr << "DemoMediaPlugin::receiveMessage: shared memory remove, name = " << name << std::endl;
286
287 SharedSegmentMap::iterator iter = mSharedSegments.find(name);
288 if(iter != mSharedSegments.end())
289 {
290 if(mPixels == iter->second.mAddress)
291 {
292 // This is the currently active pixel buffer. Make sure we stop drawing to it.
293 mPixels = NULL;
294 }
295 mSharedSegments.erase(iter);
296 }
297 else
298 {
299 std::cerr << "DemoMediaPlugin::receiveMessage: unknown shared memory region!" << std::endl;
300 }
301
302 // Send the response so it can be cleaned up.
303 LLPluginMessage message("base", "shm_remove_response");
304 message.setValue("name", name);
305 sendMessage(message);
306 }
307 else
308 {
309 std::cerr << "DemoMediaPlugin::receiveMessage: unknown base message: " << message_name << std::endl;
310 }
311 }
312 else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
313 {
314 if(message_name == "size_change")
315 {
316 std::string name = message_in.getValue("name");
317 S32 width = message_in.getValueS32("width");
318 S32 height = message_in.getValueS32("height");
319 S32 texture_width = message_in.getValueS32("texture_width");
320 S32 texture_height = message_in.getValueS32("texture_height");
321
322 LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response");
323 message.setValue("name", name);
324 message.setValueS32("width", width);
325 message.setValueS32("height", height);
326 message.setValueS32("texture_width", texture_width);
327 message.setValueS32("texture_height", texture_height);
328 sendMessage(message);
329
330 if(!name.empty())
331 {
332 // Find the shared memory region with this name
333 SharedSegmentMap::iterator iter = mSharedSegments.find(name);
334 if(iter != mSharedSegments.end())
335 {
336 std::cerr << "Got size change, new size is " << width << " by " << height << std::endl;
337 std::cerr << " texture size is " << texture_width << " by " << texture_height << std::endl;
338
339 mPixels = (unsigned char*)iter->second.mAddress;
340 mWidth = width;
341 mHeight = height;
342 mTextureWidth = texture_width;
343 mTextureHeight = texture_height;
344
345 clear();
346 }
347 }
348 }
349 else if(message_name == "mouse_event")
350 {
351 std::string event = message_in.getValue("event");
352 S32 x = message_in.getValueS32("x");
353 S32 y = message_in.getValueS32("y");
354// std::string modifiers = message.getValue("modifiers");
355
356// std::cerr << "DemoMediaPlugin::receiveMessage: mouse event \"" << event
357// << "\", coords " << x << ", " << y
358// << std::endl;
359
360 if(event == "down")
361 {
362 mouseDown(x, y);
363 }
364 else if(event == "up")
365 {
366 mouseUp(x, y);
367 }
368 else if(event == "move")
369 {
370 mouseMove(x, y);
371 }
372 }
373 else
374 {
375 std::cerr << "DemoMediaPlugin::receiveMessage: unknown media message: " << message_string << std::endl;
376 }
377 }
378 else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER)
379 {
380 if(message_name == "focus")
381 {
382 // foo = message_in.getValueBoolean("focused");
383 }
384 else if(message_name == "clear_cache")
385 {
386 }
387 else if(message_name == "clear_cookies")
388 {
389 }
390 else if(message_name == "enable_cookies")
391 {
392 // foo = message_in.getValueBoolean("enable");
393 }
394 else if(message_name == "proxy_setup")
395 {
396 // foo = message_in.getValueBoolean("enable");
397 // bar = message_in.getValue("host");
398 // baz = message_in.getValueS32("port");
399 }
400 else if(message_name == "browse_stop")
401 {
402 }
403 else if(message_name == "browse_reload")
404 {
405 // foo = message_in.getValueBoolean("ignore_cache");
406 }
407 else if(message_name == "browse_forward")
408 {
409 }
410 else if(message_name == "browse_back")
411 {
412 }
413 else if(message_name == "set_status_redirect")
414 {
415 // foo = message_in.getValueS32("code");
416 // bar = message_in.getValue("url");
417 }
418 else
419 {
420 std::cerr << "DemoMediaPlugin::receiveMessage: unknown media_browser message: " << message_string << std::endl;
421 }
422 }
423 else
424 {
425 std::cerr << "DemoMediaPlugin::receiveMessage: unknown message class: " << message_class << std::endl;
426 }
427
428 }
429}
430
431void DemoMediaPlugin::sendMessage(const LLPluginMessage &message)
432{
433 std::string output = message.generate();
434 mHostSendFunction(output.c_str(), &mHostUserData);
435}
436
437void DemoMediaPlugin::setDirty(int left, int top, int right, int bottom)
438{
439 LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "updated");
440
441 message.setValueS32("left", left);
442 message.setValueS32("top", top);
443 message.setValueS32("right", right);
444 message.setValueS32("bottom", bottom);
445
446 sendMessage(message);
447}
448
449
450extern "C"
451{
452#ifdef WIN32
453 __declspec(dllexport)
454#endif
455 int LLPluginInitEntryPoint(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data);
456}
457
458int
459#ifdef WIN32
460 __declspec(dllexport)
461#endif
462 LLPluginInitEntryPoint(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data)
463{
464 return DemoMediaPlugin::init(host_send_func, host_user_data, plugin_send_func, plugin_user_data);
465}
466
467#ifdef WIN32
468int WINAPI DllEntryPoint( HINSTANCE hInstance, unsigned long reason, void* params )
469{
470 return 1;
471}
472#endif
diff --git a/linden/indra/test_apps/llplugintest/demo_media_plugin_2.cpp b/linden/indra/test_apps/llplugintest/demo_media_plugin_2.cpp
new file mode 100644
index 0000000..7a76f74
--- /dev/null
+++ b/linden/indra/test_apps/llplugintest/demo_media_plugin_2.cpp
@@ -0,0 +1,578 @@
1/**
2 * @file demo_plugin.cpp
3 * @brief Test plugin to be loaded by the llplugin testbed.
4 *
5 * $LicenseInfo:firstyear=2008&license=viewergpl$
6 *
7 * Copyright (c) 2008-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://secondlifegrid.net/programs/open_source/licensing/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
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32
33#include "linden_common.h"
34
35#include "llgl.h"
36
37#include "llplugininstance.h"
38#include "llpluginmessage.h"
39#include "llpluginmessageclasses.h"
40
41// TODO: Make sure that the only symbol exported from this library is LLPluginInitEntryPoint
42
43class DemoMediaPlugin2
44{
45public:
46
47 static int init(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data);
48
49private:
50 DemoMediaPlugin2(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
51 ~DemoMediaPlugin2();
52
53 static void staticReceiveMessage(const char *message_string, void **user_data);
54 void receiveMessage(const char *message_string);
55 void sendMessage(const LLPluginMessage &message);
56 void setDirty(int left, int top, int right, int bottom);
57
58 LLPluginInstance::sendMessageFunction mHostSendFunction;
59 void *mHostUserData;
60 bool mDeleteMe;
61
62 class SharedSegmentInfo
63 {
64 public:
65 void *mAddress;
66 size_t mSize;
67 };
68
69 typedef std::map<std::string, SharedSegmentInfo> SharedSegmentMap;
70
71 SharedSegmentMap mSharedSegments;
72
73public:
74 void updatePixels(void)
75 {
76 if ( mWidth < 1 || mWidth > 2048 || mHeight < 1 || mHeight > 2048 )
77 return;
78
79 if ( mPixels == 0 )
80 return;
81
82 if ( mFirstTime )
83 {
84 // now we have a valid width/height - we can initialize positions
85 for( int n = 0; n < NumObjects; ++n )
86 {
87 mXpos[ n ] = ( mWidth / 2 ) + rand() % ( mWidth / 16 ) - ( mWidth / 32 );
88 mYpos[ n ] = ( mHeight / 2 ) + rand() % ( mHeight / 16 ) - ( mHeight / 32 );
89
90 mColorR[ n ] = rand() % 0xa0 + 0x60;
91 mColorG[ n ] = rand() % 0xa0 + 0x60;
92 mColorB[ n ] = rand() % 0xa0 + 0x60;
93
94 mXInc[ n ] = 0;
95 while ( mXInc[ n ] == 0 )
96 mXInc[ n ] = rand() % 7 - 3;
97
98 mYInc[ n ] = 0;
99 while ( mYInc[ n ] == 0 )
100 mYInc[ n ] = rand() % 9 - 4;
101
102 mBlockSize[ n ] = rand() % 0x16 + 0x04;
103 };
104
105 delete [] mBackgroundPixels;
106
107 mBackgroundPixels = new unsigned char[ mWidth * mHeight * mDepth ];
108
109 mFirstTime = false;
110 };
111
112 if ( time( NULL ) > mLastUpdateTime + 3 )
113 {
114 const int num_squares = rand() % 20 + 4;
115 int sqr1_r = rand() % 0x80 + 0x20;
116 int sqr1_g = rand() % 0x80 + 0x20;
117 int sqr1_b = rand() % 0x80 + 0x20;
118 int sqr2_r = rand() % 0x80 + 0x20;
119 int sqr2_g = rand() % 0x80 + 0x20;
120 int sqr2_b = rand() % 0x80 + 0x20;
121
122 for ( int y1 = 0; y1 < num_squares; ++y1 )
123 {
124 for ( int x1 = 0; x1 < num_squares; ++x1 )
125 {
126 int px_start = mWidth * x1 / num_squares;
127 int px_end = ( mWidth * ( x1 + 1 ) ) / num_squares;
128 int py_start = mHeight * y1 / num_squares;
129 int py_end = ( mHeight * ( y1 + 1 ) ) / num_squares;
130
131 for( int y2 = py_start; y2 < py_end; ++y2 )
132 {
133 for( int x2 = px_start; x2 < px_end; ++x2 )
134 {
135 int rowspan = mWidth * mDepth;
136
137 if ( ( y1 % 2 ) ^ ( x1 % 2 ) )
138 {
139 mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 0 ] = sqr1_r;
140 mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 1 ] = sqr1_g;
141 mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 2 ] = sqr1_b;
142 }
143 else
144 {
145 mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 0 ] = sqr2_r;
146 mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 1 ] = sqr2_g;
147 mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 2 ] = sqr2_b;
148 };
149 };
150 };
151 };
152 };
153
154 time( &mLastUpdateTime );
155 };
156
157 memcpy( mPixels, mBackgroundPixels, mWidth * mHeight * mDepth );
158
159 for( int n = 0; n < NumObjects; ++n )
160 {
161 if ( rand() % 50 == 0 )
162 {
163 mXInc[ n ] = 0;
164 while ( mXInc[ n ] == 0 )
165 mXInc[ n ] = rand() % 7 - 3;
166
167 mYInc[ n ] = 0;
168 while ( mYInc[ n ] == 0 )
169 mYInc[ n ] = rand() % 9 - 4;
170 };
171
172 if ( mXpos[ n ] + mXInc[ n ] < 0 || mXpos[ n ] + mXInc[ n ] >= mWidth - mBlockSize[ n ] )
173 mXInc[ n ] =- mXInc[ n ];
174
175 if ( mYpos[ n ] + mYInc[ n ] < 0 || mYpos[ n ] + mYInc[ n ] >= mHeight - mBlockSize[ n ] )
176 mYInc[ n ] =- mYInc[ n ];
177
178 mXpos[ n ] += mXInc[ n ];
179 mYpos[ n ] += mYInc[ n ];
180
181 for( int y = 0; y < mBlockSize[ n ]; ++y )
182 {
183 for( int x = 0; x < mBlockSize[ n ]; ++x )
184 {
185 mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 0 ] = mColorR[ n ];
186 mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 1 ] = mColorG[ n ];
187 mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 2 ] = mColorB[ n ];
188 };
189 };
190 };
191
192 // TODO: experiment with setDirty to just follow block position
193 setDirty( 0, 0, mWidth, mHeight );
194 };
195
196 ////////////////////////////////////////////////////////////////////////////////
197 //
198 void update()
199 {
200 updatePixels();
201 };
202
203 ////////////////////////////////////////////////////////////////////////////////
204 //
205 void write_pixel( int x, int y, unsigned char r, unsigned char g, unsigned char b )
206 {
207 // make sure we don't write outside the buffer
208 if((x < 0) || (x >= mWidth) || (y < 0) || (y >= mHeight))
209 return;
210
211 if( mBackgroundPixels != NULL)
212 {
213 unsigned char *pixel = mBackgroundPixels;
214 pixel += y * mWidth * mDepth; // row offset
215 pixel += (x * mDepth); // columm offset
216 pixel[0] = b;
217 pixel[1] = g;
218 pixel[2] = r;
219
220 setDirty(x, y, x+1, y+1);
221 }
222 }
223
224 ////////////////////////////////////////////////////////////////////////////////
225 //
226 void mouseDown( int x, int y )
227 {
228 write_pixel( x, y, 0xff, 0x00, 0x00 );
229 };
230
231 ////////////////////////////////////////////////////////////////////////////////
232 //
233 void mouseUp( int x, int y )
234 {
235 write_pixel( x, y, 0xff, 0xff, 0x00 );
236 };
237
238 ////////////////////////////////////////////////////////////////////////////////
239 //
240 void mouseMove( int x, int y )
241 {
242 write_pixel( x , y , 0xff, 0x00, 0xff );
243 };
244
245 ////////////////////////////////////////////////////////////////////////////////
246 //
247 void keyPress( unsigned char key )
248 {
249 };
250
251private:
252 unsigned char* mPixels;
253 int mWidth;
254 int mHeight;
255 int mTextureWidth;
256 int mTextureHeight;
257 int mDepth;
258 time_t mLastUpdateTime;
259 bool mFirstTime;
260 unsigned char* mBackgroundPixels;
261 enum Constants2 { NumObjects = 20 };
262 int mColorR[ NumObjects ];
263 int mColorG[ NumObjects ];
264 int mColorB[ NumObjects ];
265 int mXpos[ NumObjects ];
266 int mYpos[ NumObjects ];
267 int mXInc[ NumObjects ];
268 int mYInc[ NumObjects ];
269 int mBlockSize[ NumObjects ];
270};
271
272int DemoMediaPlugin2::init(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data)
273{
274 DemoMediaPlugin2 *self = new DemoMediaPlugin2(host_send_func, host_user_data);
275 *plugin_send_func = staticReceiveMessage;
276 *plugin_user_data = (void*)self;
277
278 return 0;
279}
280
281
282DemoMediaPlugin2::DemoMediaPlugin2(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data)
283{
284 std::cerr << "DemoMediaPlugin2 constructor" << std::endl;
285
286 mHostSendFunction = host_send_func;
287 mHostUserData = host_user_data;
288 mDeleteMe = false;
289
290 mLastUpdateTime = 0;
291 mFirstTime = true;
292 mLastUpdateTime = 0;
293 mWidth = 0;
294 mHeight = 0;
295 mDepth = 0;
296 mPixels = 0;
297 mBackgroundPixels = 0;
298
299 srand( get_clock_count() ) ;
300}
301
302DemoMediaPlugin2::~DemoMediaPlugin2()
303{
304 std::cerr << "DemoMediaPlugin2 destructor" << std::endl;
305}
306
307void DemoMediaPlugin2::staticReceiveMessage(const char *message_string, void **user_data)
308{
309 DemoMediaPlugin2 *self = (DemoMediaPlugin2*)*user_data;
310
311 if(self != NULL)
312 {
313 self->receiveMessage(message_string);
314
315 // If the plugin has processed the delete message, delete it.
316 if(self->mDeleteMe)
317 {
318 delete self;
319 *user_data = NULL;
320 }
321 }
322}
323
324void DemoMediaPlugin2::receiveMessage(const char *message_string)
325{
326// std::cerr << "DemoMediaPlugin2::receiveMessage: received message: \"" << message_string << "\"" << std::endl;
327 LLPluginMessage message_in;
328
329 if(message_in.parse(message_string) >= 0)
330 {
331 std::string message_class = message_in.getClass();
332 std::string message_name = message_in.getName();
333 if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE)
334 {
335 if(message_name == "init")
336 {
337 LLPluginMessage message("base", "init_response");
338 LLSD versions = LLSD::emptyMap();
339 versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION;
340 versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION;
341 // Normally a plugin would only specify one of these two subclasses, but this is a demo...
342 versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION;
343 versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME] = LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION;
344 message.setValueLLSD("versions", versions);
345 sendMessage(message);
346
347 // Plugin gets to decide the texture parameters to use.
348 mDepth = 3;
349
350 message.setMessage(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params");
351 message.setValueS32("depth", mDepth);
352 message.setValueU32("internalformat", GL_RGB);
353 message.setValueU32("format", GL_RGB);
354 message.setValueU32("type", GL_UNSIGNED_BYTE);
355 message.setValueBoolean("coords_opengl", false); // true == use OpenGL-style coordinates, false == (0,0) is upper left.
356 sendMessage(message);
357 }
358 else if(message_name == "idle")
359 {
360 // no response is necessary here.
361 update();
362 }
363 else if(message_name == "shutdown")
364 {
365 sendMessage(LLPluginMessage("base", "shutdown_response"));
366
367 mDeleteMe = true;
368 }
369 else if(message_name == "shm_added")
370 {
371 SharedSegmentInfo info;
372 info.mAddress = (void*)message_in.getValueU32("address");
373 info.mSize = (size_t)message_in.getValueS32("size");
374 std::string name = message_in.getValue("name");
375
376
377 std::cerr << "DemoMediaPlugin2::receiveMessage: shared memory added, name: " << name
378 << ", size: " << info.mSize
379 << ", address: " << info.mAddress
380 << std::endl;
381
382 mSharedSegments.insert(SharedSegmentMap::value_type(name, info));
383
384 }
385 else if(message_name == "shm_remove")
386 {
387 std::string name = message_in.getValue("name");
388
389 std::cerr << "DemoMediaPlugin2::receiveMessage: shared memory remove, name = " << name << std::endl;
390
391 SharedSegmentMap::iterator iter = mSharedSegments.find(name);
392 if(iter != mSharedSegments.end())
393 {
394 if(mPixels == iter->second.mAddress)
395 {
396 // This is the currently active pixel buffer. Make sure we stop drawing to it.
397 mPixels = NULL;
398 }
399 mSharedSegments.erase(iter);
400 }
401 else
402 {
403 std::cerr << "DemoMediaPlugin2::receiveMessage: unknown shared memory region!" << std::endl;
404 }
405
406 // Send the response so it can be cleaned up.
407 LLPluginMessage message("base", "shm_remove_response");
408 message.setValue("name", name);
409 sendMessage(message);
410 }
411 else
412 {
413 std::cerr << "DemoMediaPlugin2::receiveMessage: unknown base message: " << message_name << std::endl;
414 }
415 }
416 else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
417 {
418 if(message_name == "size_change")
419 {
420 std::string name = message_in.getValue("name");
421 S32 width = message_in.getValueS32("width");
422 S32 height = message_in.getValueS32("height");
423 S32 texture_width = message_in.getValueS32("texture_width");
424 S32 texture_height = message_in.getValueS32("texture_height");
425
426 LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response");
427 message.setValue("name", name);
428 message.setValueS32("width", width);
429 message.setValueS32("height", height);
430 message.setValueS32("texture_width", texture_width);
431 message.setValueS32("texture_height", texture_height);
432 sendMessage(message);
433
434 if(!name.empty())
435 {
436 // Find the shared memory region with this name
437 SharedSegmentMap::iterator iter = mSharedSegments.find(name);
438 if(iter != mSharedSegments.end())
439 {
440 std::cerr << "Got size change, new size is " << width << " by " << height << std::endl;
441 std::cerr << " texture size is " << texture_width << " by " << texture_height << std::endl;
442
443 mPixels = (unsigned char*)iter->second.mAddress;
444 mWidth = width;
445 mHeight = height;
446
447 mTextureWidth = texture_width;
448 mTextureHeight = texture_height;
449
450 mFirstTime = true;
451 updatePixels();
452 }
453 }
454 }
455 else if(message_name == "mouse_event")
456 {
457 std::string event = message_in.getValue("event");
458 S32 x = message_in.getValueS32("x");
459 S32 y = message_in.getValueS32("y");
460// std::string modifiers = message.getValue("modifiers");
461
462// std::cerr << "DemoMediaPlugin2::receiveMessage: mouse event \"" << event
463// << "\", coords " << x << ", " << y
464// << std::endl;
465
466 if(event == "down")
467 {
468 mouseDown(x, y);
469 }
470 else if(event == "up")
471 {
472 mouseUp(x, y);
473 }
474 else if(event == "move")
475 {
476 mouseMove(x, y);
477 }
478 }
479 else
480 {
481 std::cerr << "DemoMediaPlugin2::receiveMessage: unknown media message: " << message_string << std::endl;
482 }
483 }
484 else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER)
485 {
486 if(message_name == "focus")
487 {
488 // foo = message_in.getValueBoolean("focused");
489 }
490 else if(message_name == "clear_cache")
491 {
492 }
493 else if(message_name == "clear_cookies")
494 {
495 }
496 else if(message_name == "enable_cookies")
497 {
498 // foo = message_in.getValueBoolean("enable");
499 }
500 else if(message_name == "proxy_setup")
501 {
502 // foo = message_in.getValueBoolean("enable");
503 // bar = message_in.getValue("host");
504 // baz = message_in.getValueS32("port");
505 }
506 else if(message_name == "browse_stop")
507 {
508 }
509 else if(message_name == "browse_reload")
510 {
511 // foo = message_in.getValueBoolean("ignore_cache");
512 }
513 else if(message_name == "browse_forward")
514 {
515 }
516 else if(message_name == "browse_back")
517 {
518 }
519 else if(message_name == "set_status_redirect")
520 {
521 // foo = message_in.getValueS32("code");
522 // bar = message_in.getValue("url");
523 }
524 else
525 {
526 std::cerr << "DemoMediaPlugin2::receiveMessage: unknown media_browser message: " << message_string << std::endl;
527 }
528 }
529 else
530 {
531 std::cerr << "DemoMediaPlugin2::receiveMessage: unknown message class: " << message_class << std::endl;
532 }
533
534 }
535}
536
537void DemoMediaPlugin2::sendMessage(const LLPluginMessage &message)
538{
539 std::string output = message.generate();
540 mHostSendFunction(output.c_str(), &mHostUserData);
541}
542
543void DemoMediaPlugin2::setDirty(int left, int top, int right, int bottom)
544{
545 LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "updated");
546
547 message.setValueS32("left", left);
548 message.setValueS32("top", top);
549 message.setValueS32("right", right);
550 message.setValueS32("bottom", bottom);
551
552 sendMessage(message);
553}
554
555
556extern "C"
557{
558#ifdef WIN32
559 __declspec(dllexport)
560#endif
561 int LLPluginInitEntryPoint(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data);
562}
563
564int
565#ifdef WIN32
566 __declspec(dllexport)
567#endif
568 LLPluginInitEntryPoint(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data)
569{
570 return DemoMediaPlugin2::init(host_send_func, host_user_data, plugin_send_func, plugin_user_data);
571}
572
573#ifdef WIN32
574int WINAPI DllEntryPoint( HINSTANCE hInstance, unsigned long reason, void* params )
575{
576 return 1;
577}
578#endif
diff --git a/linden/indra/test_apps/llplugintest/demo_plugin.cpp b/linden/indra/test_apps/llplugintest/demo_plugin.cpp
new file mode 100644
index 0000000..772fa16
--- /dev/null
+++ b/linden/indra/test_apps/llplugintest/demo_plugin.cpp
@@ -0,0 +1,220 @@
1/**
2 * @file demo_plugin.cpp
3 * @brief Test plugin to be loaded by the llplugin testbed.
4 *
5 * $LicenseInfo:firstyear=2008&license=viewergpl$
6 *
7 * Copyright (c) 2008-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://secondlifegrid.net/programs/open_source/licensing/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
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32
33#include "linden_common.h"
34
35#ifdef WIN32
36#include <windows.h>
37#endif
38
39#include "llplugininstance.h"
40#include "llpluginmessage.h"
41#include "llpluginmessageclasses.h"
42
43// TODO: Make sure that the only symbol exported from this library is LLPluginInitEntryPoint
44
45class DemoPlugin
46{
47public:
48
49 static int init(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data);
50
51private:
52 DemoPlugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
53 ~DemoPlugin();
54
55 static void staticReceiveMessage(const char *message_string, void **user_data);
56 void receiveMessage(const char *message_string);
57 void sendMessage(const LLPluginMessage &message);
58
59 LLPluginInstance::sendMessageFunction mHostSendFunction;
60 void *mHostUserData;
61 bool mDeleteMe;
62
63 int mSharedSegmentFillValue;
64 void *mSharedSegmentBase;
65 size_t mSharedSegmentSize;
66};
67
68int DemoPlugin::init(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data)
69{
70 DemoPlugin *self = new DemoPlugin(host_send_func, host_user_data);
71 *plugin_send_func = staticReceiveMessage;
72 *plugin_user_data = (void*)self;
73
74 return 0;
75}
76
77DemoPlugin::DemoPlugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data)
78{
79 std::cerr << "DemoPlugin constructor" << std::endl;
80
81 mHostSendFunction = host_send_func;
82 mHostUserData = host_user_data;
83 mDeleteMe = false;
84 mSharedSegmentBase = NULL;
85 mSharedSegmentSize = 0;
86 mSharedSegmentFillValue = 0;
87}
88
89DemoPlugin::~DemoPlugin()
90{
91 std::cerr << "DemoPlugin destructor" << std::endl;
92}
93
94void DemoPlugin::staticReceiveMessage(const char *message_string, void **user_data)
95{
96 DemoPlugin *self = (DemoPlugin*)*user_data;
97
98 if(self != NULL)
99 {
100 self->receiveMessage(message_string);
101
102 // If the plugin has processed the delete message, delete it.
103 if(self->mDeleteMe)
104 {
105 delete self;
106 *user_data = NULL;
107 }
108 }
109}
110
111void DemoPlugin::receiveMessage(const char *message_string)
112{
113// std::cerr << "DemoPlugin::receiveMessage: received message: \"" << message_string << "\"" << std::endl;
114 LLPluginMessage message_in;
115
116 if(message_in.parse(message_string) >= 0)
117 {
118 std::string message_class = message_in.getClass();
119 std::string message_name = message_in.getName();
120 if(message_class == "base")
121 {
122 if(message_name == "init")
123 {
124 LLPluginMessage message("base", "init_response");
125 LLSD versions = LLSD::emptyMap();
126 versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION;
127 versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION;
128 message.setValueLLSD("versions", versions);
129 sendMessage(message);
130 }
131 else if(message_name == "idle")
132 {
133 // no response is necessary here.
134// std::cerr << "DemoPlugin::receiveMessage: idle processing" << std::endl;
135 if(mSharedSegmentBase != NULL)
136 {
137 // Fill the shared memory segment
138 memset(mSharedSegmentBase, mSharedSegmentFillValue, mSharedSegmentSize);
139 // and increment the fill value
140 mSharedSegmentFillValue++;
141 }
142 }
143 else if(message_name == "shutdown")
144 {
145 sendMessage(LLPluginMessage("base", "shutdown_response"));
146
147 mDeleteMe = true;
148 }
149 else if(message_name == "shm_added")
150 {
151 // Normally, we would check the name and match it up with something from another message.
152 // For this test, just fill any segment that comes in.
153 mSharedSegmentSize = (size_t)message_in.getValueS32("size");
154 mSharedSegmentBase = (void*)message_in.getValueU32("address");
155
156 std::cerr << "DemoPlugin::receiveMessage: shared memory added, name: " << message_in.getValue("name")
157 << ", size: " << mSharedSegmentSize
158 << ", address: " << mSharedSegmentBase
159 << std::endl;
160
161 memset(mSharedSegmentBase, mSharedSegmentFillValue, mSharedSegmentSize);
162
163 }
164 else if(message_name == "shm_remove")
165 {
166 std::cerr << "DemoPlugin::receiveMessage: shared memory remove" << std::endl;
167
168 // Normally, we would check the name and match it up with something from another message.
169 // For this test, just stop filling the only segment we track.
170
171 mSharedSegmentBase = NULL;
172
173 // Send the response so it can be cleaned up.
174 LLPluginMessage message("base", "shm_remove_response");
175 message.setValue("name", message_in.getValue("name"));
176 sendMessage(message);
177 }
178 else
179 {
180 std::cerr << "DemoPlugin::receiveMessage: unknown base message: " << message_name << std::endl;
181 }
182 }
183 else
184 {
185 std::cerr << "DemoPlugin::receiveMessage: unknown message class: " << message_class << std::endl;
186 }
187
188 }
189}
190
191void DemoPlugin::sendMessage(const LLPluginMessage &message)
192{
193 std::string output = message.generate();
194 mHostSendFunction(output.c_str(), &mHostUserData);
195}
196
197
198extern "C"
199{
200#ifdef WIN32
201 __declspec(dllexport)
202#endif
203 int LLPluginInitEntryPoint(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data);
204}
205
206int
207#ifdef WIN32
208 __declspec(dllexport)
209#endif
210 LLPluginInitEntryPoint(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data)
211{
212 return DemoPlugin::init(host_send_func, host_user_data, plugin_send_func, plugin_user_data);
213}
214
215#ifdef WIN32
216int WINAPI DllEntryPoint( HINSTANCE hInstance, unsigned long reason, void* params )
217{
218 return 1;
219}
220#endif
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}
diff --git a/linden/indra/test_apps/llplugintest/llmediaplugintest.h b/linden/indra/test_apps/llplugintest/llmediaplugintest.h
new file mode 100644
index 0000000..c2b2bab
--- /dev/null
+++ b/linden/indra/test_apps/llplugintest/llmediaplugintest.h
@@ -0,0 +1,201 @@
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#ifndef LL_MEDIA_PLUGIN_TEST_H
33#define LL_MEDIA_PLUGIN_TEST_H
34
35#include <vector>
36#include <string>
37#include "llpluginclassmedia.h"
38#include "llgl.h"
39
40// Forward declarations
41class GLUI_Rotation;
42class GLUI_Translation;
43class GLUI_Listbox;
44class GLUI_EditText;
45class GLUI_StaticText;
46class GLUI;
47class GLUI_Button;
48
49////////////////////////////////////////////////////////////////////////////////
50//
51struct mediaPanel
52{
53 public:
54 mediaPanel();
55 ~mediaPanel();
56 int mId;
57 std::string mStartUrl;
58 std::string mMimeType;
59 LLPluginClassMedia *mMediaSource;
60 int mMediaWidth;
61 int mMediaHeight;
62 int mTextureWidth;
63 int mTextureHeight;
64 double mTextureScaleX;
65 double mTextureScaleY;
66 GLuint mMediaTextureHandle;
67 GLuint mPickTextureHandle;
68 unsigned char* mPickTexturePixels;
69 bool mAppTextureCoordsOpenGL;
70 bool mReadyToRender;
71};
72
73////////////////////////////////////////////////////////////////////////////////
74//
75class LLMediaPluginTest : public LLPluginClassMediaOwner
76{
77 public:
78 LLMediaPluginTest( int app_window, int window_width, int window_height );
79 ~LLMediaPluginTest();
80
81 void reshape( int width, int height );
82 void display();
83 void idle();
84 void gluiCallback( int control_id );
85 void keyboard( int key );
86 void mousePassive( int x, int y );
87 void mouseButton( int button, int state, int x, int y );
88 void mouseMove( int x, int y );
89
90 void bindTexture(GLuint texture, GLint row_length = 0, GLint alignment = 1);
91 bool checkGLError(const char *name = "OpenGL");
92 void drawGeometry( int panel );
93 void startPanelHighlight( float red, float green, float blue, float line_width );
94 void endPanelHighlight();
95 enum { DrawTypePickTexture, DrawTypeMediaTexture };
96 void draw( int draw_type );
97 void windowPosToTexturePos( int window_x, int window_y, int& media_x, int& media_y, int& id );
98
99 void addMediaPanel( std::string url );
100 void updateMediaPanel( mediaPanel* panel );
101 void remMediaPanel( mediaPanel* panel );
102 void replaceMediaPanel( mediaPanel* panel, std::string url );
103 void getRandomMediaSize( int& width, int& height, std::string mime_type );
104 void navigateToNewURI( std::string uri );
105 void initUrlHistory( std::string uri );
106 void selectPanelById( int id );
107 void selectPanel( mediaPanel* panel );
108 mediaPanel* findMediaPanel( LLPluginClassMedia* panel );
109 void makePickTexture( int id, GLuint* texture_handle, unsigned char** texture_pixels );
110 void makeChrome();
111 void resetView();
112
113 void dumpPanelInfo();
114 void updateStatusBar();
115
116 // Inherited from LLPluginClassMediaOwner
117 /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, LLPluginClassMediaOwner::EMediaEvent);
118
119 private:
120 const int mVersionMajor;
121 const int mVersionMinor;
122 const int mVersionPatch;
123 const int mMaxPanels;
124 int mAppWindow;
125 int mWindowWidth;
126 int mWindowHeight;
127 int mCurMouseX;
128 int mCurMouseY;
129 unsigned char mPixelReadColor[ 3 ];
130 bool mFuzzyMedia;
131 const std::string mHomeWebUrl;
132
133 std::vector< mediaPanel* > mMediaPanels;
134 mediaPanel* mSelectedPanel;
135 std::string mimeTypeFromUrl( std::string& url );
136 std::string pluginNameFromMimeType( std::string& mime_type );
137
138 GLUI_Rotation* mViewRotationCtrl;
139 GLUI_Translation* mViewScaleCtrl;
140 GLUI_Translation* mViewTranslationCtrl;
141 float mViewportAspect;
142 float mViewPos[ 3 ];
143 float mViewRotation[ 16 ];
144
145 int mIdControlAddPanel;
146 int mIdControlRemPanel;
147
148 std::vector< std::pair< std::string, std::string > > mBookmarks;
149 GLUI_Listbox* mBookmarkList;
150 int mIdBookmarks;
151 int mIdUrlEdit;
152 GLUI_EditText* mUrlEdit;
153 int mIdUrlInitHistoryEdit;
154 GLUI_EditText* mUrlInitHistoryEdit;
155 int mSelBookmark;
156 int mIdRandomPanelCount;
157 int mRandomPanelCount;
158 int mIdRandomBookmarks;
159 int mRandomBookmarks;
160 int mIdDisableTimeout;
161 int mDisableTimeout;
162 int mIdControlCrashPlugin;
163 int mIdControlHangPlugin;
164 int mIdControlExitApp;
165
166 GLUI* mGluiMediaTimeControlWindow;
167 int mIdMediaTimeControlPlay;
168 int mIdMediaTimeControlLoop;
169 int mIdMediaTimeControlPause;
170 int mIdMediaTimeControlStop;
171 int mIdMediaTimeControlSeek;
172 int mIdMediaTimeControlVolume;
173 int mMediaTimeControlVolume;
174 int mIdMediaTimeControlSeekSeconds;
175 int mMediaTimeControlSeekSeconds;
176 int mIdMediaTimeControlRewind;
177 int mIdMediaTimeControlFastForward;
178
179 GLUI* mGluiMediaBrowserControlWindow;
180 int mIdMediaBrowserControlBack;
181 GLUI_Button* mMediaBrowserControlBackButton;
182 int mIdMediaBrowserControlStop;
183 int mIdMediaBrowserControlForward;
184 GLUI_Button* mMediaBrowserControlForwardButton;
185 bool mGluiMediaTimeControlWindowFlag;
186 bool mGluiMediaBrowserControlWindowFlag;
187 bool mMediaBrowserControlBackButtonFlag;
188 bool mMediaBrowserControlForwardButtonFlag;
189 int mIdMediaBrowserControlHome;
190 int mIdMediaBrowserControlReload;
191 int mIdMediaBrowserControlClearCache;
192 int mIdMediaBrowserControlClearCookies;
193 int mIdMediaBrowserControlEnableCookies;
194 int mMediaBrowserControlEnableCookies;
195
196 GLUI* mBottomGLUIWindow;
197 GLUI_StaticText* mStatusText;
198};
199
200#endif // LL_MEDIA_PLUGIN_TEST_H
201
diff --git a/linden/indra/test_apps/llplugintest/media_mappings.txt b/linden/indra/test_apps/llplugintest/media_mappings.txt
new file mode 100644
index 0000000..74188bc
--- /dev/null
+++ b/linden/indra/test_apps/llplugintest/media_mappings.txt
@@ -0,0 +1,3 @@
1Flash demo_media_plugin_flash.dll
2ColNoise demo_media_plugin.dll
3CheckBounce demo_media_plugin_2.dll
diff --git a/linden/indra/test_apps/llplugintest/media_plugin_test.cpp b/linden/indra/test_apps/llplugintest/media_plugin_test.cpp
new file mode 100644
index 0000000..8e42fa7
--- /dev/null
+++ b/linden/indra/test_apps/llplugintest/media_plugin_test.cpp
@@ -0,0 +1,511 @@
1/**
2 * @file demo_plugin.cpp
3 * @brief Test plugin to be loaded by the llplugin testbed.
4 *
5 * $LicenseInfo:firstyear=2008&license=viewergpl$
6 *
7 * Copyright (c) 2008-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://secondlifegrid.net/programs/open_source/licensing/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
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32
33#include "linden_common.h"
34#include "indra_constants.h"
35
36#include "lltimer.h" // for ms_sleep()
37#include "llpumpio.h"
38#include "llapr.h"
39#include "llerrorcontrol.h"
40#include "llpluginclassmedia.h"
41
42#include <string>
43#include <iostream>
44#include <stdlib.h>
45#include <time.h>
46
47#include "llmediaplugintest.h" // for GLUT headers
48
49
50////////////////////////////////////////////////////////////////////////////////
51//
52class mediaPluginTest : public LLPluginClassMediaOwner
53{
54 private:
55 int mAppWindowWidth;
56 int mAppWindowHeight;
57 LLPluginClassMedia* mMediaSource;
58 int mAppTextureWidth;
59 int mAppTextureHeight;
60 bool mAppTextureCoordsOpenGL;
61 GLuint mAppTexture;
62 std::string mAppWindowName;
63 std::string mHomeUrl;
64 std::string mLauncherFilename;
65 std::string mPluginFilename;
66
67 LLPluginClassMedia *mPlugin;
68
69 public:
70 mediaPluginTest(const std::string &launcher_filename, const std::string &plugin_filename) :
71 mAppWindowWidth( 800 ),
72 mAppWindowHeight( 600 ),
73 mAppTextureWidth( 0 ),
74 mAppTextureHeight( 0 ),
75 mAppTextureCoordsOpenGL(false),
76 mAppTexture( 0 ),
77 mAppWindowName( "Media Simple Test" ),
78 mHomeUrl( "" )
79 {
80 mLauncherFilename = launcher_filename;
81 mMediaSource = new LLPluginClassMedia(this);
82 mMediaSource->init(launcher_filename, plugin_filename);
83 };
84
85 ////////////////////////////////////////////////////////////////////////////////
86 //
87 virtual ~mediaPluginTest()
88 {
89 delete mMediaSource;
90 };
91
92 ////////////////////////////////////////////////////////////////////////////////
93 //
94 void createTexture()
95 {
96 // create the texture used to display the browser data
97 if(mMediaSource->textureValid())
98 {
99 mAppTextureWidth = mMediaSource->getTextureWidth();
100 mAppTextureHeight = mMediaSource->getTextureHeight();
101 mAppTextureCoordsOpenGL = mMediaSource->getTextureCoordsOpenGL();
102
103 if(mAppTexture != 0)
104 {
105 glDeleteTextures( 1, &mAppTexture );
106 mAppTexture = 0;
107 }
108
109 glGenTextures( 1, &mAppTexture );
110 glBindTexture( GL_TEXTURE_2D, mAppTexture );
111 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
112 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
113 glTexImage2D( GL_TEXTURE_2D, 0,
114 mMediaSource->getTextureFormatInternal(),
115 mAppTextureWidth,
116 mAppTextureHeight,
117 0,
118 mMediaSource->getTextureFormatPrimary(),
119 mMediaSource->getTextureFormatType(),
120 NULL );
121 }
122 }
123
124 ////////////////////////////////////////////////////////////////////////////////
125 //
126 void initGL()
127 {
128 // OpenGL initialization
129 glClearColor( 0.0f, 0.0f, 0.0f, 0.5f);
130 glEnable( GL_COLOR_MATERIAL );
131 glColorMaterial( GL_FRONT, GL_AMBIENT_AND_DIFFUSE );
132 glEnable( GL_TEXTURE_2D );
133 glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
134 glEnable( GL_CULL_FACE );
135 }
136
137 ////////////////////////////////////////////////////////////////////////////////
138 //
139 void reshape( int width, int height )
140 {
141 if ( height == 0 )
142 height = 1;
143
144 glMatrixMode( GL_PROJECTION );
145 glLoadIdentity();
146
147 glViewport( 0, 0, width, height );
148 glOrtho( 0.0f, width, height, 0.0f, -1.0f, 1.0f );
149
150 // we use these values elsewhere so save
151 mAppWindowWidth = width;
152 mAppWindowHeight = height;
153
154 // Request a media size change
155 mMediaSource->setSize(width, height);
156
157 glMatrixMode( GL_MODELVIEW );
158 glLoadIdentity();
159
160 glutPostRedisplay();
161 };
162
163 ////////////////////////////////////////////////////////////////////////////////
164 //
165 void idle()
166 {
167 // lots of updates for smooth motion
168 glutPostRedisplay();
169 };
170
171 ////////////////////////////////////////////////////////////////////////////////
172 //
173 void display()
174 {
175 mMediaSource->idle();
176
177 // Check whether the texture needs to be recreated.
178 if(mMediaSource->textureValid())
179 {
180 if(
181 (mAppTextureWidth != mMediaSource->getTextureWidth() || mAppTextureHeight != mMediaSource->getTextureHeight()) &&
182 (mAppWindowWidth == mMediaSource->getWidth() && mAppWindowHeight == mMediaSource->getHeight())
183 )
184 {
185 // Attempt to (re)create the texture
186 createTexture();
187 }
188 }
189
190 // clear screen
191 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
192
193 glLoadIdentity();
194
195 if(mAppTexture != 0)
196 {
197 // use the browser texture
198 glBindTexture( GL_TEXTURE_2D, mAppTexture );
199
200 // If dirty, update the texture.
201 LLRect dirtyRect;
202 if(!mMediaSource->textureValid())
203 {
204// LL_DEBUGS("media_plugin_test") << "Resize in progress, skipping update..." << LL_ENDL;
205 }
206 else if(mAppWindowWidth != mMediaSource->getWidth() || mAppWindowHeight != mMediaSource->getHeight())
207 {
208 // A resize is in progress. Just wait for it...
209 }
210 else if(mMediaSource->getDirty(&dirtyRect))
211 {
212 // grab the page
213 const unsigned char* pixels = mMediaSource->getBitsData();
214 if ( pixels )
215 {
216 // write them into the texture
217
218 // Paranoia: intersect dirtyRect with (0, 0, mAppTextureWidth, mAppTextureHeight)?
219
220 int x_offset = dirtyRect.mLeft;
221 int y_offset = dirtyRect.mBottom;
222 int width = dirtyRect.mRight - dirtyRect.mLeft;
223 int height = dirtyRect.mTop - dirtyRect.mBottom;
224
225 LL_DEBUGS("media_plugin_test") << "Updating, dirty rect is ("
226 << dirtyRect.mLeft << ", "
227 << dirtyRect.mTop << ", "
228 << dirtyRect.mRight << ", "
229 << dirtyRect.mBottom << "), update params are: ("
230 << x_offset << ", "
231 << y_offset << ", "
232 << width << ", "
233 << height << ")"
234 << LL_ENDL;
235
236 // Offset the pixels pointer properly
237 pixels += (y_offset * mMediaSource->getTextureDepth() * mMediaSource->getTextureWidth());
238 pixels += (x_offset * mMediaSource->getTextureDepth());
239
240 glPixelStorei(GL_UNPACK_ROW_LENGTH, mMediaSource->getTextureWidth());
241
242 glTexSubImage2D( GL_TEXTURE_2D, 0,
243 x_offset,
244 y_offset,
245 width,
246 height,
247 mMediaSource->getTextureFormatPrimary(),
248 mMediaSource->getTextureFormatType(),
249 pixels );
250
251 mMediaSource->resetDirty();
252 }
253 }
254
255 // scale the texture so that it fits the screen
256 GLdouble media_texture_x = mAppWindowWidth / (double)mAppTextureWidth;
257 GLdouble media_texture_y = mAppWindowHeight / (double)mAppTextureHeight;
258
259 // draw the single quad full screen (orthographic)
260
261 glEnable( GL_TEXTURE_2D );
262 glColor3f( 1.0f, 1.0f, 1.0f );
263 glBegin( GL_QUADS );
264 if(mAppTextureCoordsOpenGL)
265 {
266 // Render the texture as per opengl coords (where 0,0 is at the lower left)
267 glTexCoord2d( 0, 0 );
268 glVertex2d( 0, 0 );
269
270 glTexCoord2d( 0 , media_texture_y );
271 glVertex2d( 0, mAppWindowHeight);
272
273 glTexCoord2d( media_texture_x, media_texture_y );
274 glVertex2d( mAppWindowWidth , mAppWindowHeight);
275
276 glTexCoord2d( media_texture_x, 0 );
277 glVertex2d( mAppWindowWidth, 0 );
278 }
279 else
280 {
281 // Render the texture the "other way round" (where 0,0 is at the upper left)
282 glTexCoord2d( 0, media_texture_y );
283 glVertex2d( 0, 0 );
284
285 glTexCoord2d( 0 , 0 );
286 glVertex2d( 0, mAppWindowHeight);
287
288 glTexCoord2d( media_texture_x, 0 );
289 glVertex2d( mAppWindowWidth , mAppWindowHeight);
290
291 glTexCoord2d( media_texture_x, media_texture_y );
292 glVertex2d( mAppWindowWidth, 0 );
293 }
294 glEnd();
295
296 }
297
298 glutSwapBuffers();
299 };
300
301
302 ////////////////////////////////////////////////////////////////////////////////
303 //
304 MASK getModifiers(void)
305 {
306 MASK result = 0;
307
308 int modifiers = glutGetModifiers();
309
310 if(modifiers & GLUT_ACTIVE_SHIFT)
311 result |= MASK_SHIFT;
312 if(modifiers & GLUT_ACTIVE_CTRL)
313 result |= MASK_CONTROL;
314 if(modifiers & GLUT_ACTIVE_ALT)
315 result |= MASK_ALT;
316
317 return result;
318 }
319
320 ////////////////////////////////////////////////////////////////////////////////
321 //
322 void mouseButton( int button, int state, int x, int y )
323 {
324 // Texture has been scaled so it's 1:1 with screen pixels, so no need to scale mouse coords here.
325// x = ( x * mAppTextureWidth ) / mAppWindowWidth;
326// y = ( y * mAppTextureHeight ) / mAppWindowHeight;
327
328 if ( button == GLUT_LEFT_BUTTON )
329 {
330 if ( state == GLUT_DOWN )
331 mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, x, y, getModifiers());
332 else if ( state == GLUT_UP )
333 mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, x, y, getModifiers());
334 }
335
336 // force a GLUT update
337 glutPostRedisplay();
338 };
339
340 ////////////////////////////////////////////////////////////////////////////////
341 //
342 void mouseMove( int x , int y )
343 {
344 // Texture has been scaled so it's 1:1 with screen pixels, so no need to scale mouse coords here.
345// x = ( x * mAppTextureWidth ) / mAppWindowWidth;
346// y = ( y * mAppTextureHeight ) / mAppWindowHeight;
347
348 // GLUT complains if I get the keyboard modifiers here, so just pretend there aren't any.
349 mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_MOVE, x, y, 0);
350
351 // force a GLUT update
352 glutPostRedisplay();
353 };
354
355 ////////////////////////////////////////////////////////////////////////////////
356 //
357 void keyboard( unsigned char key )
358 {
359 mMediaSource->keyEvent( LLPluginClassMedia::KEY_EVENT_DOWN, key, getModifiers());
360 };
361
362 ////////////////////////////////////////////////////////////////////////////////
363 //
364 int getAppWindowWidth()
365 {
366 return mAppWindowWidth;
367 };
368
369 ////////////////////////////////////////////////////////////////////////////////
370 //
371 int getAppWindowHeight()
372 {
373 return mAppWindowHeight;
374 };
375
376 ////////////////////////////////////////////////////////////////////////////////
377 //
378 std::string getAppWindowName()
379 {
380 return mAppWindowName;
381 };
382
383};
384
385mediaPluginTest* gApplication;
386
387////////////////////////////////////////////////////////////////////////////////
388//
389void glutReshape( int width, int height )
390{
391 if ( gApplication )
392 gApplication->reshape( width, height );
393};
394
395////////////////////////////////////////////////////////////////////////////////
396//
397void glutDisplay()
398{
399 if ( gApplication )
400 gApplication->display();
401};
402
403////////////////////////////////////////////////////////////////////////////////
404//
405void glutIdle()
406{
407 if ( gApplication )
408 gApplication->idle();
409};
410
411////////////////////////////////////////////////////////////////////////////////
412//
413void glutKeyboard( unsigned char key, int x, int y )
414{
415 if ( key == 27 )
416 {
417 delete gApplication;
418 exit( 0 );
419 };
420
421 if ( gApplication )
422 gApplication->keyboard( key );
423};
424
425////////////////////////////////////////////////////////////////////////////////
426//
427void glutMouseMove( int x, int y )
428{
429 if ( gApplication )
430 gApplication->mouseMove( x, y );
431}
432
433////////////////////////////////////////////////////////////////////////////////
434//
435void glutMouseButton( int button, int state, int x, int y )
436{
437 if ( gApplication )
438 gApplication->mouseButton( button, state, x, y );
439}
440
441////////////////////////////////////////////////////////////////////////////////
442//
443int main( int argc, char* argv[] )
444{
445
446 ll_init_apr();
447
448 // Set up llerror logging
449 {
450 LLError::initForApplication(".");
451 LLError::setDefaultLevel(LLError::LEVEL_INFO);
452 }
453
454 std::string launcher_name;
455 std::string plugin_name;
456
457 if(argc >= 3)
458 {
459 launcher_name = argv[1];
460 plugin_name = argv[2];
461 }
462 else
463 {
464#if LL_DARWIN
465 // hardcoding the testbed arguments by default
466 launcher_name = "plugin_process_host";
467 plugin_name = "libdemo_media_plugin_quicktime.dylib";
468#elif LL_WINDOWS
469 // hardcoding the testbed arguments by default
470 launcher_name = "plugin_process_host.exe";
471 plugin_name = "demo_media_plugin_quicktime.dll";
472#else
473 LL_ERRS("plugin_process_launcher") << "usage: " << argv[0] << " launcher_filename plugin_filename" << LL_ENDL;
474#endif
475 }
476
477 gApplication = new mediaPluginTest(launcher_name, plugin_name);
478
479 if ( gApplication )
480 {
481 glutInit( &argc, argv );
482 glutInitDisplayMode( GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB );
483
484 glutInitWindowPosition( 80, 0 );
485 glutInitWindowSize( gApplication->getAppWindowWidth(), gApplication->getAppWindowHeight() );
486
487 glutCreateWindow( gApplication->getAppWindowName().c_str() );
488
489 glutKeyboardFunc( glutKeyboard );
490
491 glutMouseFunc( glutMouseButton );
492 glutPassiveMotionFunc( glutMouseMove );
493 glutMotionFunc( glutMouseMove );
494
495 glutDisplayFunc( glutDisplay );
496 glutReshapeFunc( glutReshape );
497
498 glutIdleFunc( glutIdle );
499
500 gApplication->initGL();
501
502 glutMainLoop();
503
504 delete gApplication;
505 };
506
507 ll_cleanup_apr();
508
509 return 0;
510}
511
diff --git a/linden/indra/test_apps/llplugintest/media_simple_test.cpp b/linden/indra/test_apps/llplugintest/media_simple_test.cpp
new file mode 100644
index 0000000..9a60e8e
--- /dev/null
+++ b/linden/indra/test_apps/llplugintest/media_simple_test.cpp
@@ -0,0 +1,460 @@
1/**
2 * @file demo_plugin.cpp
3 * @brief Test plugin to be loaded by the llplugin testbed.
4 *
5 * $LicenseInfo:firstyear=2008&license=viewergpl$
6 *
7 * Copyright (c) 2008-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://secondlifegrid.net/programs/open_source/licensing/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
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32
33#include <string>
34#include <iostream>
35#include <stdlib.h>
36#include <time.h>
37
38#if LL_DARWIN
39 #include <GLUT/glut.h>
40#elif LL_LINUX
41 #include <GL/glut.h>
42#else
43 #include "glut.h"
44#endif
45
46////////////////////////////////////////////////////////////////////////////////
47//
48class mediaSource
49{
50 public:
51 ////////////////////////////////////////////////////////////////////////////////
52 //
53 mediaSource() :
54 mPixels( 0 ),
55 mIsDirty( false ),
56 mWidth( 200 ),
57 mHeight( 100 ),
58 mDepth( 3 ),
59 mPixelFormat( GL_BGR_EXT )
60 {
61 mPixels = new unsigned char [ mWidth * mHeight * mDepth ];
62
63 for( int i = 0; i < mWidth * mHeight * mDepth; ++i )
64 *( mPixels + i ) = rand() % 0x40;
65 };
66
67 ////////////////////////////////////////////////////////////////////////////////
68 //
69 void update()
70 {
71 const time_t interval = 1;
72 static time_t last_time = time( NULL );
73 time_t cur_time = time( NULL );
74
75 if ( cur_time - last_time > interval )
76 {
77 for( int i = 0; i < mWidth * mHeight * mDepth; ++i )
78 *( mPixels + i ) = rand() % 0x40;
79
80 mIsDirty = true;
81
82 last_time = cur_time;
83 };
84 };
85
86 ////////////////////////////////////////////////////////////////////////////////
87 //
88 void write_pixel( int x, int y, unsigned char r, unsigned char g, unsigned char b )
89 {
90 // make sure we don't write outside the buffer
91 if((x < 0) || (x >= mWidth) || (y < 0) || (y >= mHeight))
92 return;
93
94 *( mPixels + ( mHeight - y ) * mWidth * mDepth + x * mDepth + 0 ) = b;
95 *( mPixels + ( mHeight - y ) * mWidth * mDepth + x * mDepth + 1 ) = g;
96 *( mPixels + ( mHeight - y ) * mWidth * mDepth + x * mDepth + 2 ) = r;
97
98 mIsDirty = true;
99 }
100
101 ////////////////////////////////////////////////////////////////////////////////
102 //
103 void mouseDown( int x, int y )
104 {
105 write_pixel( x, y, 0xff, 0x00, 0x00 );
106 };
107
108 ////////////////////////////////////////////////////////////////////////////////
109 //
110 void mouseUp( int x, int y )
111 {
112 write_pixel( x, y, 0xff, 0xff, 0x00 );
113 };
114
115 ////////////////////////////////////////////////////////////////////////////////
116 //
117 void mouseMove( int x, int y )
118 {
119 write_pixel( x, y, 0xff, 0x00, 0xff );
120 };
121
122 ////////////////////////////////////////////////////////////////////////////////
123 //
124 void keyPress( unsigned char key )
125 {
126 };
127
128 ////////////////////////////////////////////////////////////////////////////////
129 //
130 int getWidth() { return mWidth; };
131 int getHeight() { return mHeight; };
132 int getDepth() { return mDepth; };
133 int getPixelFormat() { return mPixelFormat; };
134 bool isDirty() { return mIsDirty; };
135 void ackDirty() { mIsDirty = false; };
136 unsigned char* getPixels() { return mPixels; };
137
138 private:
139 unsigned char* mPixels;
140 bool mIsDirty;
141 int mWidth;
142 int mHeight;
143 int mDepth;
144 int mPixelFormat;
145};
146
147////////////////////////////////////////////////////////////////////////////////
148//
149class mediaSimpleTest
150{
151 public:
152 mediaSimpleTest() :
153 mAppWindowWidth( 800 ),
154 mAppWindowHeight( 600 ),
155 mAppTextureWidth( 0 ),
156 mAppTextureHeight( 0 ),
157 mAppTexture( 0 ),
158 mAppWindowName( "Media Simple Test" ),
159 mHomeUrl( "" )
160 {
161 mMediaSource = new mediaSource;
162
163 // calculate texture size required (next power of two above browser window size
164 for ( mAppTextureWidth = 1; mAppTextureWidth < mMediaSource->getWidth(); mAppTextureWidth <<= 1 ) {};
165 for ( mAppTextureHeight = 1; mAppTextureHeight < mMediaSource->getHeight(); mAppTextureHeight <<= 1 ) {};
166 };
167
168 ////////////////////////////////////////////////////////////////////////////////
169 //
170 ~mediaSimpleTest()
171 {
172 delete mMediaSource;
173 };
174
175 ////////////////////////////////////////////////////////////////////////////////
176 //
177 void initGL()
178 {
179 // OpenGL initialization
180 glClearColor( 0.0f, 0.0f, 0.0f, 0.5f);
181 glEnable( GL_COLOR_MATERIAL );
182 glColorMaterial( GL_FRONT, GL_AMBIENT_AND_DIFFUSE );
183 glEnable( GL_TEXTURE_2D );
184 glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
185 glEnable( GL_CULL_FACE );
186
187 // create the texture used to display the browser data
188 glGenTextures( 1, &mAppTexture );
189 glBindTexture( GL_TEXTURE_2D, mAppTexture );
190 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
191 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
192 glTexImage2D( GL_TEXTURE_2D, 0,
193 GL_RGB,
194 mAppTextureWidth, mAppTextureHeight,
195 0, GL_RGB, GL_UNSIGNED_BYTE, 0 );
196 }
197
198 ////////////////////////////////////////////////////////////////////////////////
199 //
200 void reshape( int width, int height )
201 {
202 if ( height == 0 )
203 height = 1;
204
205 glMatrixMode( GL_PROJECTION );
206 glLoadIdentity();
207
208 glViewport( 0, 0, width, height );
209 glOrtho( 0.0f, width, height, 0.0f, -1.0f, 1.0f );
210
211 // we use these values elsewhere so save
212 mAppWindowWidth = width;
213 mAppWindowHeight = height;
214
215 glMatrixMode( GL_MODELVIEW );
216 glLoadIdentity();
217
218 glutPostRedisplay();
219 };
220
221 ////////////////////////////////////////////////////////////////////////////////
222 //
223 void idle()
224 {
225 // lots of updates for smooth motion
226 glutPostRedisplay();
227 };
228
229 ////////////////////////////////////////////////////////////////////////////////
230 //
231 void display()
232 {
233 // clear screen
234 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
235
236 glLoadIdentity();
237
238 // use the browser texture
239 glBindTexture( GL_TEXTURE_2D, mAppTexture );
240
241 // needs to be updated?
242 mMediaSource->update();
243 if ( mMediaSource->isDirty() )
244 {
245 // grab the page
246 const unsigned char* pixels = mMediaSource->getPixels();
247 if ( pixels )
248 {
249 // write them into the texture
250 glTexSubImage2D( GL_TEXTURE_2D, 0,
251 0, 0,
252 mMediaSource->getWidth(),
253 mMediaSource->getHeight(),
254 mMediaSource->getPixelFormat(),
255 GL_UNSIGNED_BYTE,
256 pixels );
257
258 // acknowledge we saw media was dirty and updated
259 mMediaSource->ackDirty();
260 };
261 };
262
263 // scale the texture so that it fits the screen
264 GLfloat texture_scale_x = ( GLfloat )mMediaSource->getWidth() / ( GLfloat )mAppTextureWidth;
265 GLfloat texture_scale_y = ( GLfloat )mMediaSource->getHeight() / ( GLfloat )mAppTextureHeight;
266
267 // draw the single quad full screen (orthographic)
268 glMatrixMode( GL_TEXTURE );
269 glPushMatrix();
270 glScalef( texture_scale_x, texture_scale_y, 1.0f );
271
272 glEnable( GL_TEXTURE_2D );
273 glColor3f( 1.0f, 1.0f, 1.0f );
274 glBegin( GL_QUADS );
275 glTexCoord2f( 1.0f, 1.0f );
276 glVertex2d( mAppWindowWidth, 0 );
277
278 glTexCoord2f( 0.0f, 1.0f );
279 glVertex2d( 0, 0 );
280
281 glTexCoord2f( 0.0f, 0.0f );
282 glVertex2d( 0, mAppWindowHeight );
283
284 glTexCoord2f( 1.0f, .0f );
285 glVertex2d( mAppWindowWidth, mAppWindowHeight );
286 glEnd();
287
288 glMatrixMode( GL_TEXTURE );
289 glPopMatrix();
290
291 glutSwapBuffers();
292 };
293
294 ////////////////////////////////////////////////////////////////////////////////
295 //
296 void mouseButton( int button, int state, int x, int y )
297 {
298 // texture is scaled to fit the screen so we scale mouse coords in the same way
299 x = ( x * mMediaSource->getWidth() ) / mAppWindowWidth;
300 y = ( y * mMediaSource->getHeight() ) / mAppWindowHeight;
301
302 if ( button == GLUT_LEFT_BUTTON )
303 {
304 if ( state == GLUT_DOWN )
305 mMediaSource->mouseDown( x, y );
306 else
307 if ( state == GLUT_UP )
308 mMediaSource->mouseUp( x, y );
309 };
310
311 // force a GLUT update
312 glutPostRedisplay();
313 };
314
315 ////////////////////////////////////////////////////////////////////////////////
316 //
317 void mouseMove( int x , int y )
318 {
319 // texture is scaled to fit the screen so we scale mouse coords in the same way
320 x = ( x * mMediaSource->getWidth() ) / mAppWindowWidth;
321 y = ( y * mMediaSource->getHeight() ) / mAppWindowHeight;
322
323 mMediaSource->mouseMove( x, y );
324
325 // force a GLUT update
326 glutPostRedisplay();
327 };
328
329 ////////////////////////////////////////////////////////////////////////////////
330 //
331 void keyboard( unsigned char key )
332 {
333 mMediaSource->keyPress( key );
334 };
335
336 ////////////////////////////////////////////////////////////////////////////////
337 //
338 int getAppWindowWidth()
339 {
340 return mAppWindowWidth;
341 };
342
343 ////////////////////////////////////////////////////////////////////////////////
344 //
345 int getAppWindowHeight()
346 {
347 return mAppWindowHeight;
348 };
349
350 ////////////////////////////////////////////////////////////////////////////////
351 //
352 std::string getAppWindowName()
353 {
354 return mAppWindowName;
355 };
356
357 private:
358 int mAppWindowWidth;
359 int mAppWindowHeight;
360 mediaSource* mMediaSource;
361 int mAppTextureWidth;
362 int mAppTextureHeight;
363 GLuint mAppTexture;
364 std::string mAppWindowName;
365 std::string mHomeUrl;
366};
367
368mediaSimpleTest* gApplication;
369
370////////////////////////////////////////////////////////////////////////////////
371//
372void glutReshape( int width, int height )
373{
374 if ( gApplication )
375 gApplication->reshape( width, height );
376};
377
378////////////////////////////////////////////////////////////////////////////////
379//
380void glutDisplay()
381{
382 if ( gApplication )
383 gApplication->display();
384};
385
386////////////////////////////////////////////////////////////////////////////////
387//
388void glutIdle()
389{
390 if ( gApplication )
391 gApplication->idle();
392};
393
394////////////////////////////////////////////////////////////////////////////////
395//
396void glutKeyboard( unsigned char key, int x, int y )
397{
398 if ( key == 27 )
399 {
400 delete gApplication;
401 exit( 0 );
402 };
403
404 if ( gApplication )
405 gApplication->keyboard( key );
406};
407
408////////////////////////////////////////////////////////////////////////////////
409//
410void glutMouseMove( int x, int y )
411{
412 if ( gApplication )
413 gApplication->mouseMove( x, y );
414}
415
416////////////////////////////////////////////////////////////////////////////////
417//
418void glutMouseButton( int button, int state, int x, int y )
419{
420 if ( gApplication )
421 gApplication->mouseButton( button, state, x, y );
422}
423
424////////////////////////////////////////////////////////////////////////////////
425//
426int main( int argc, char* argv[] )
427{
428 gApplication = new mediaSimpleTest;
429
430 if ( gApplication )
431 {
432 glutInit( &argc, argv );
433 glutInitDisplayMode( GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB );
434
435 glutInitWindowPosition( 80, 0 );
436 glutInitWindowSize( gApplication->getAppWindowWidth(), gApplication->getAppWindowHeight() );
437
438 glutCreateWindow( gApplication->getAppWindowName().c_str() );
439
440 glutKeyboardFunc( glutKeyboard );
441
442 glutMouseFunc( glutMouseButton );
443 glutPassiveMotionFunc( glutMouseMove );
444 glutMotionFunc( glutMouseMove );
445
446 glutDisplayFunc( glutDisplay );
447 glutReshapeFunc( glutReshape );
448
449 glutIdleFunc( glutIdle );
450
451 gApplication->initGL();
452
453 glutMainLoop();
454
455 delete gApplication;
456 };
457
458 return 0;
459}
460
diff --git a/linden/indra/test_apps/llplugintest/plugin_host.cpp b/linden/indra/test_apps/llplugintest/plugin_host.cpp
new file mode 100644
index 0000000..5ba5d8b
--- /dev/null
+++ b/linden/indra/test_apps/llplugintest/plugin_host.cpp
@@ -0,0 +1,92 @@
1/**
2 * @file plugin_host.cpp
3 * @brief Testbed for llplugin which directly loads a plugin dynamic library.
4 *
5 * $LicenseInfo:firstyear=2008&license=viewergpl$
6 *
7 * Copyright (c) 2008-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://secondlifegrid.net/programs/open_source/licensing/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
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32
33
34#include "linden_common.h"
35
36#include "llplugininstance.h"
37#include "llpluginmessage.h"
38#include "llerrorcontrol.h"
39
40class MessageReceiver: public LLPluginInstanceMessageListener
41{
42 // Inherited from LLPluginInstanceMessageListener
43 /* virtual */ void receivePluginMessage(const std::string &message)
44 {
45 LL_INFOS("plugin_host") << "message received from plugin: " << message << LL_ENDL;
46 }
47
48};
49
50int main(int argc, char **argv)
51{
52 ll_init_apr();
53
54 // Set up llerror logging
55 {
56 LLError::initForApplication(".");
57 LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
58 }
59
60 if(argc < 2)
61 {
62 LL_ERRS("plugin_host") << "usage: " << argv[0] << " plugin_filename" << LL_ENDL;
63 exit(1);
64 }
65
66 std::string name = argv[1];
67
68 MessageReceiver receiver;
69 LLPluginInstance *plugin = new LLPluginInstance(&receiver);
70 if(plugin->load(name) == 0)
71 {
72 LLPluginMessage message;
73 message.setMessage("base", "init");
74 message.setValue("foo", "1");
75 message.setValue("bar", "2");
76 plugin->sendMessage(message.generate());
77
78 message.setMessage("base", "idle");
79 message.setValue("baz", "3");
80 plugin->sendMessage(message.generate());
81
82 message.setMessage("base", "shutdown");
83 plugin->sendMessage(message.generate());
84
85 plugin->idle();
86 }
87
88 delete plugin;
89
90 ll_cleanup_apr();
91}
92
diff --git a/linden/indra/test_apps/llplugintest/plugin_process_launcher.cpp b/linden/indra/test_apps/llplugintest/plugin_process_launcher.cpp
new file mode 100644
index 0000000..82b11e3
--- /dev/null
+++ b/linden/indra/test_apps/llplugintest/plugin_process_launcher.cpp
@@ -0,0 +1,197 @@
1/**
2 * @file plugin_process_launcher.cpp
3 * @brief Testbed for llplugin which launches the plugin loader shell.
4 *
5 * $LicenseInfo:firstyear=2008&license=viewergpl$
6 *
7 * Copyright (c) 2008-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://secondlifegrid.net/programs/open_source/licensing/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
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32
33#include "linden_common.h"
34
35#include "llprocesslauncher.h"
36#include "lltimer.h" // for ms_sleep()
37#include "llpumpio.h"
38#include "llapr.h"
39#include "llerrorcontrol.h"
40#include "llpluginprocessparent.h"
41
42class PluginProcessLauncherMessageReceiver : public LLPluginProcessParentOwner
43{
44LOG_CLASS(PluginProcessLauncherMessageReceiver);
45
46public:
47 virtual ~PluginProcessLauncherMessageReceiver()
48 {
49 }
50
51 /* virtual */ void receivePluginMessage(const LLPluginMessage &message)
52 {
53 LL_INFOS("plugin_process_launcher") << "received message: \n" << message.generate() << LL_ENDL;
54 }
55};
56
57LLPumpIO* gServicePump;
58LLPluginProcessParent *gPlugin;
59
60
61#define SHARED_MEMORY_SIZE 0x10000
62#define SHARED_MEMORY_NAME "testsegment"
63enum State
64{
65 STATE_STARTUP,
66 STATE_ADD_MEMORY,
67 STATE_RUNNING,
68 STATE_REMOVE_MEMORY,
69 STATE_SHUTDOWN,
70 STATE_CLEANUP,
71 STATE_DONE
72};
73
74int main(int argc, char **argv)
75{
76 ll_init_apr();
77
78 // Set up llerror logging
79 {
80 LLError::initForApplication(".");
81 LLError::setDefaultLevel(LLError::LEVEL_INFO);
82 }
83
84 std::string launcher_name;
85 std::string plugin_name;
86
87 if(argc >= 3)
88 {
89 launcher_name = argv[1];
90 plugin_name = argv[2];
91 }
92 else
93 {
94#if LL_DARWIN
95 // hardcoding the testbed arguments by default
96 launcher_name = "plugin_process_host";
97 plugin_name = "libdemo_plugin.dylib";
98#elif LL_WINDOWS
99 // hardcoding the testbed arguments by default
100 launcher_name = "plugin_process_host.exe";
101 plugin_name = "demo_plugin.dll";
102#else
103 LL_ERRS("plugin_process_launcher") << "usage: " << argv[0] << " launcher_filename plugin_filename" << LL_ENDL;
104#endif
105 }
106
107 PluginProcessLauncherMessageReceiver receiver;
108
109 gServicePump = new LLPumpIO(gAPRPoolp);
110 gServicePump->prime(gAPRPoolp);
111
112 gPlugin = new LLPluginProcessParent(gServicePump, &receiver);
113
114 State state = STATE_STARTUP;
115 while(state != STATE_DONE)
116 {
117 switch(state)
118 {
119 case STATE_STARTUP:
120 LL_INFOS("plugin_process_launcher") << "startup" << LL_ENDL;
121 gPlugin->init(launcher_name, plugin_name);
122 state = STATE_ADD_MEMORY;
123 break;
124
125 case STATE_ADD_MEMORY:
126 if(gPlugin->isRunning())
127 {
128 LL_INFOS("plugin_process_launcher") << "adding shared memory" << LL_ENDL;
129 gPlugin->addSharedMemory(SHARED_MEMORY_SIZE);
130 state = STATE_RUNNING;
131 }
132 break;
133
134 case STATE_RUNNING:
135 {
136 volatile unsigned char *addr = (unsigned char*)gPlugin->getSharedMemoryAddress(SHARED_MEMORY_NAME);
137 if(addr != NULL)
138 {
139 int val = (int)(addr[0]);
140 if(val >= 16)
141 {
142 state = STATE_REMOVE_MEMORY;
143 }
144 else
145 {
146 LL_INFOS("plugin_process_launcher") << "running, value from shared memory is " << val << LL_ENDL;
147 }
148 }
149 }
150 break;
151
152 case STATE_REMOVE_MEMORY:
153 LL_INFOS("plugin_process_launcher") << "removing shared memory" << LL_ENDL;
154 gPlugin->removeSharedMemory(SHARED_MEMORY_NAME);
155 state = STATE_SHUTDOWN;
156 break;
157
158 case STATE_SHUTDOWN:
159 {
160 volatile unsigned char *addr = (unsigned char*)gPlugin->getSharedMemoryAddress(SHARED_MEMORY_NAME);
161 if(addr == NULL)
162 {
163 LL_INFOS("plugin_process_launcher") << "sending shutdown request" << LL_ENDL;
164 gPlugin->shutdownRequest();
165 state = STATE_CLEANUP;
166 }
167 }
168 break;
169
170 case STATE_CLEANUP:
171 if(gPlugin->isDone())
172 {
173 LL_INFOS("plugin_process_launcher") << "plugin is done" << LL_ENDL;
174 state = STATE_DONE;
175 }
176 break;
177
178 case STATE_DONE:
179 // should never reach here -- the while() should exit first.
180 break;
181 }
182
183 // Do this every time through the loop
184 if(state != STATE_DONE)
185 {
186 gServicePump->pump();
187 gServicePump->callback();
188 gPlugin->idle();
189 ms_sleep(100);
190 }
191 }
192
193 delete gPlugin;
194
195 ll_cleanup_apr();
196
197}