void LLViewerMediaImpl::update()
{
	LLPluginClassMedia* plugin = getMediaPlugin();
	if (!plugin)
	{
		return;
	}
	
	plugin->idle();
	
	if (plugin->isPluginExited())
	{
		destroyMediaSource();
		return;
	}

	if (!plugin->textureValid())
	{
		return;
	}
	
	if(mSuspendUpdates || !mVisible)
	{
		return;
	}
	
	LLViewerTexture* placeholder_image = updatePlaceholderImage();
		
	if(placeholder_image)
	{
		LLRect dirty_rect;
		if (plugin->getDirty(&dirty_rect))
		{
			// Constrain the dirty rect to be inside the texture
			S32 x_pos = llmax(dirty_rect.mLeft, 0);
			S32 y_pos = llmax(dirty_rect.mBottom, 0);
			S32 width = llmin(dirty_rect.mRight, placeholder_image->getWidth()) - x_pos;
			S32 height = llmin(dirty_rect.mTop, placeholder_image->getHeight()) - y_pos;
			
			if(width > 0 && height > 0)
			{

				U8* data = plugin->getBitsData();

				// Offset the pixels pointer to match x_pos and y_pos
				data += ( x_pos * plugin->getTextureDepth() * plugin->getBitsWidth() );
				data += ( y_pos * plugin->getTextureDepth() );
				
				placeholder_image->setSubImage(
						data, 
						plugin->getBitsWidth(), 
						plugin->getBitsHeight(),
						x_pos, 
						y_pos, 
						width, 
						height,
						TRUE);		// force a fast update (i.e. don't call analyzeAlpha, etc.)

			}
			
			plugin->resetDirty();
		}
	}
}
		void display()
		{
			mMediaSource->idle();

			// Check whether the texture needs to be recreated.
			if(mMediaSource->textureValid())
			{
				if(
					(mAppTextureWidth != mMediaSource->getTextureWidth() ||	mAppTextureHeight != mMediaSource->getTextureHeight()) &&
					(mAppWindowWidth == mMediaSource->getWidth() && mAppWindowHeight == mMediaSource->getHeight())
				)
				{
					// Attempt to (re)create the texture
					createTexture();
				}
			}
						
			// clear screen
			glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

			glLoadIdentity();
			
			if(mAppTexture != 0)
			{
				// use the browser texture
				glBindTexture( GL_TEXTURE_2D, mAppTexture );

				// If dirty, update the texture.
				LLRect dirtyRect;
				if(!mMediaSource->textureValid())
				{
//					LL_DEBUGS("media_plugin_test") << "Resize in progress, skipping update..." << LL_ENDL;
				}
				else if(mAppWindowWidth != mMediaSource->getWidth() || mAppWindowHeight != mMediaSource->getHeight())
				{
					// A resize is in progress.  Just wait for it...
				}
				else if(mMediaSource->getDirty(&dirtyRect))
				{
					// grab the page
					const unsigned char* pixels = mMediaSource->getBitsData();
					if ( pixels )
					{
						// write them into the texture
						
						// Paranoia: intersect dirtyRect with (0, 0, mAppTextureWidth, mAppTextureHeight)?

						int x_offset = dirtyRect.mLeft;
						int y_offset = dirtyRect.mBottom;
						int width = dirtyRect.mRight - dirtyRect.mLeft;
						int height = dirtyRect.mTop - dirtyRect.mBottom;

						LL_DEBUGS("media_plugin_test") << "Updating, dirty rect is (" 
							<< dirtyRect.mLeft << ", " 
							<< dirtyRect.mTop << ", " 
							<< dirtyRect.mRight << ", " 
							<< dirtyRect.mBottom << "), update params are: (" 
							<< x_offset << ", " 
							<< y_offset << ", " 
							<< width << ", " 
							<< height << ")" 
							<< LL_ENDL; 
						
						// Offset the pixels pointer properly
						pixels += (y_offset * mMediaSource->getTextureDepth() * mMediaSource->getTextureWidth());
						pixels += (x_offset * mMediaSource->getTextureDepth());
						
						glPixelStorei(GL_UNPACK_ROW_LENGTH, mMediaSource->getTextureWidth());
						
						glTexSubImage2D( GL_TEXTURE_2D, 0, 
							x_offset, 
							y_offset,
							width, 
							height,
							mMediaSource->getTextureFormatPrimary(), 
							mMediaSource->getTextureFormatType(), 
							pixels );
						
						mMediaSource->resetDirty();
					}
				}
				
				// scale the texture so that it fits the screen
				GLdouble media_texture_x = mAppWindowWidth / (double)mAppTextureWidth;
				GLdouble media_texture_y = mAppWindowHeight / (double)mAppTextureHeight;

				// draw the single quad full screen (orthographic)

				glEnable( GL_TEXTURE_2D );
				glColor3f( 1.0f, 1.0f, 1.0f );
				glBegin( GL_QUADS );
				if(mAppTextureCoordsOpenGL)
				{
					// Render the texture as per opengl coords (where 0,0 is at the lower left)
					glTexCoord2d( 0, 0 );
					glVertex2d( 0, 0 );

					glTexCoord2d( 0 , media_texture_y );
					glVertex2d( 0, mAppWindowHeight);

					glTexCoord2d( media_texture_x, media_texture_y );
					glVertex2d( mAppWindowWidth , mAppWindowHeight);

					glTexCoord2d( media_texture_x, 0 );
					glVertex2d( mAppWindowWidth, 0 );
				}
				else
				{
					// Render the texture the "other way round" (where 0,0 is at the upper left)
					glTexCoord2d( 0, media_texture_y );
					glVertex2d( 0, 0 );

					glTexCoord2d( 0 , 0 );
					glVertex2d( 0, mAppWindowHeight);

					glTexCoord2d( media_texture_x, 0 );
					glVertex2d( mAppWindowWidth , mAppWindowHeight);

					glTexCoord2d( media_texture_x, media_texture_y );
					glVertex2d( mAppWindowWidth, 0 );
				}
				glEnd();

			}
			
			glutSwapBuffers();
		};