/** * @file media_plugin_example.cpp * @brief Example plugin for LLMedia API plugin system * * @cond * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ * @endcond */ #include "linden_common.h" #include "llgl.h" #include "llplugininstance.h" #include "llpluginmessage.h" #include "llpluginmessageclasses.h" #include "media_plugin_base.h" #include //////////////////////////////////////////////////////////////////////////////// // class mediaPluginExample : public MediaPluginBase { public: mediaPluginExample(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); ~mediaPluginExample(); /*virtual*/ void receiveMessage(const char* message_string); private: bool init(); void update(F64 milliseconds); bool mFirstTime; time_t mLastUpdateTime; enum Constants { ENumObjects = 64 }; unsigned char* mBackgroundPixels; int mColorR[ENumObjects]; int mColorG[ENumObjects]; int mColorB[ENumObjects]; int mXpos[ENumObjects]; int mYpos[ENumObjects]; int mXInc[ENumObjects]; int mYInc[ENumObjects]; int mBlockSize[ENumObjects]; }; //////////////////////////////////////////////////////////////////////////////// // mediaPluginExample::mediaPluginExample(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) : MediaPluginBase(host_send_func, host_user_data) { mFirstTime = true; mTextureWidth = 0; mTextureHeight = 0; mWidth = 0; mHeight = 0; mDepth = 4; mPixels = 0; mLastUpdateTime = 0; mBackgroundPixels = 0; } //////////////////////////////////////////////////////////////////////////////// // mediaPluginExample::~mediaPluginExample() { } //////////////////////////////////////////////////////////////////////////////// // void mediaPluginExample::receiveMessage(const char* message_string) { // std::cerr << "MediaPluginWebKit::receiveMessage: received message: \"" << message_string << "\"" << std::endl; LLPluginMessage message_in; if (message_in.parse(message_string) >= 0) { std::string message_class = message_in.getClass(); std::string message_name = message_in.getName(); if (message_class == LLPLUGIN_MESSAGE_CLASS_BASE) { if (message_name == "init") { LLPluginMessage message("base", "init_response"); LLSD versions = LLSD::emptyMap(); versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION; message.setValueLLSD("versions", versions); std::string plugin_version = "Example plugin 0.0.0"; message.setValue("plugin_version", plugin_version); sendMessage(message); } else if (message_name == "idle") { // no response is necessary here. F64 time = message_in.getValueReal("time"); // Convert time to milliseconds for update() update((int)(time * 1000.0f)); } else if (message_name == "cleanup") { LLPluginMessage message("base", "goodbye"); sendMessage(message); mDeleteMe = true; } else if (message_name == "shm_added") { SharedSegmentInfo info; info.mAddress = message_in.getValuePointer("address"); info.mSize = (size_t)message_in.getValueS32("size"); std::string name = message_in.getValue("name"); mSharedSegments.insert(SharedSegmentMap::value_type(name, info)); } else if (message_name == "shm_remove") { std::string name = message_in.getValue("name"); SharedSegmentMap::iterator iter = mSharedSegments.find(name); if (iter != mSharedSegments.end()) { if (mPixels == iter->second.mAddress) { // This is the currently active pixel buffer. Make sure we stop drawing to it. mPixels = NULL; mTextureSegmentName.clear(); } mSharedSegments.erase(iter); } else { // std::cerr << "MediaPluginWebKit::receiveMessage: unknown shared memory region!" << std::endl; } // Send the response so it can be cleaned up. LLPluginMessage message("base", "shm_remove_response"); message.setValue("name", name); sendMessage(message); } else { // std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl; } } else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) { if (message_name == "init") { // Plugin gets to decide the texture parameters to use. mDepth = 4; LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params"); message.setValueS32("default_width", 1024); message.setValueS32("default_height", 1024); message.setValueS32("depth", mDepth); message.setValueU32("internalformat", GL_RGB); message.setValueU32("format", GL_RGBA); message.setValueU32("type", GL_UNSIGNED_BYTE); message.setValueBoolean("coords_opengl", true); sendMessage(message); } else if (message_name == "size_change") { std::string name = message_in.getValue("name"); S32 width = message_in.getValueS32("width"); S32 height = message_in.getValueS32("height"); S32 texture_width = message_in.getValueS32("texture_width"); S32 texture_height = message_in.getValueS32("texture_height"); if (!name.empty()) { // Find the shared memory region with this name SharedSegmentMap::iterator iter = mSharedSegments.find(name); if (iter != mSharedSegments.end()) { mPixels = (unsigned char*)iter->second.mAddress; mWidth = width; mHeight = height; mTextureWidth = texture_width; mTextureHeight = texture_height; }; }; LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response"); message.setValue("name", name); message.setValueS32("width", width); message.setValueS32("height", height); message.setValueS32("texture_width", texture_width); message.setValueS32("texture_height", texture_height); sendMessage(message); mFirstTime = true; mLastUpdateTime = 0; } else if (message_name == "load_uri") { } else if (message_name == "mouse_event") { std::string event = message_in.getValue("event"); if (event == "down") { } else if (event == "up") { } else if (event == "double_click") { } } } else { }; } } //////////////////////////////////////////////////////////////////////////////// // void mediaPluginExample::update(F64 milliseconds) { if (mWidth < 1 || mWidth > 2048 || mHeight < 1 || mHeight > 2048) return; if (mPixels == 0) return; if (mFirstTime) { for (int n = 0; n < ENumObjects; ++n) { mXpos[n] = (mWidth / 2) + rand() % (mWidth / 16) - (mWidth / 32); mYpos[n] = (mHeight / 2) + rand() % (mHeight / 16) - (mHeight / 32); mColorR[n] = rand() % 0x60 + 0x60; mColorG[n] = rand() % 0x60 + 0x60; mColorB[n] = rand() % 0x60 + 0x60; mXInc[n] = 0; while (mXInc[n] == 0) mXInc[n] = rand() % 7 - 3; mYInc[n] = 0; while (mYInc[n] == 0) mYInc[n] = rand() % 9 - 4; mBlockSize[n] = rand() % 0x30 + 0x10; }; delete[] mBackgroundPixels; mBackgroundPixels = new unsigned char[mWidth * mHeight * mDepth]; mFirstTime = false; }; if (time(NULL) > mLastUpdateTime + 3) { const int num_squares = rand() % 20 + 4; int sqr1_r = rand() % 0x80 + 0x20; int sqr1_g = rand() % 0x80 + 0x20; int sqr1_b = rand() % 0x80 + 0x20; int sqr2_r = rand() % 0x80 + 0x20; int sqr2_g = rand() % 0x80 + 0x20; int sqr2_b = rand() % 0x80 + 0x20; for (int y1 = 0; y1 < num_squares; ++y1) { for (int x1 = 0; x1 < num_squares; ++x1) { int px_start = mWidth * x1 / num_squares; int px_end = (mWidth * (x1 + 1)) / num_squares; int py_start = mHeight * y1 / num_squares; int py_end = (mHeight * (y1 + 1)) / num_squares; for (int y2 = py_start; y2 < py_end; ++y2) { for (int x2 = px_start; x2 < px_end; ++x2) { int rowspan = mWidth * mDepth; if ((y1 % 2) ^ (x1 % 2)) { mBackgroundPixels[y2 * rowspan + x2 * mDepth + 0] = sqr1_r; mBackgroundPixels[y2 * rowspan + x2 * mDepth + 1] = sqr1_g; mBackgroundPixels[y2 * rowspan + x2 * mDepth + 2] = sqr1_b; } else { mBackgroundPixels[y2 * rowspan + x2 * mDepth + 0] = sqr2_r; mBackgroundPixels[y2 * rowspan + x2 * mDepth + 1] = sqr2_g; mBackgroundPixels[y2 * rowspan + x2 * mDepth + 2] = sqr2_b; }; }; }; }; }; time(&mLastUpdateTime); }; memcpy(mPixels, mBackgroundPixels, mWidth * mHeight * mDepth); for (int n = 0; n < ENumObjects; ++n) { if (rand() % 50 == 0) { mXInc[n] = 0; while (mXInc[n] == 0) mXInc[n] = rand() % 7 - 3; mYInc[n] = 0; while (mYInc[n] == 0) mYInc[n] = rand() % 9 - 4; }; if (mXpos[n] + mXInc[n] < 0 || mXpos[n] + mXInc[n] >= mWidth - mBlockSize[n]) mXInc[n] = -mXInc[n]; if (mYpos[n] + mYInc[n] < 0 || mYpos[n] + mYInc[n] >= mHeight - mBlockSize[n]) mYInc[n] = -mYInc[n]; mXpos[n] += mXInc[n]; mYpos[n] += mYInc[n]; for (int y = 0; y < mBlockSize[n]; ++y) { for (int x = 0; x < mBlockSize[n]; ++x) { mPixels[(mXpos[n] + x) * mDepth + (mYpos[n] + y) * mDepth * mWidth + 0] = mColorR[n]; mPixels[(mXpos[n] + x) * mDepth + (mYpos[n] + y) * mDepth * mWidth + 1] = mColorG[n]; mPixels[(mXpos[n] + x) * mDepth + (mYpos[n] + y) * mDepth * mWidth + 2] = mColorB[n]; }; }; }; setDirty(0, 0, mWidth, mHeight); }; //////////////////////////////////////////////////////////////////////////////// // bool mediaPluginExample::init() { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text"); message.setValue("name", "Example Plugin"); sendMessage(message); return true; }; //////////////////////////////////////////////////////////////////////////////// // int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void* host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) { mediaPluginExample* self = new mediaPluginExample(host_send_func, host_user_data); *plugin_send_func = mediaPluginExample::staticReceiveMessage; *plugin_user_data = (void*)self; return 0; }