Example #1
0
void HTML::PaintScrollImage(Ogre::HardwarePixelBufferSharedPtr pixelBuffer, const Berkelium::Rect& scrollOrigRect, int scroll_dx, int scroll_dy)
{

  Berkelium::Rect scrolledRect = scrollOrigRect.translate(scroll_dx, scroll_dy);

  Berkelium::Rect scrolled_shared_rect = scrollOrigRect.intersect(scrolledRect);
  // Only do scrolling if they have non-zero intersection
  if(scrolled_shared_rect.width() == 0 || scrolled_shared_rect.height() == 0)
    return;
  Berkelium::Rect shared_rect = scrolled_shared_rect.translate(-scroll_dx, -scroll_dy);

  size_t width = shared_rect.width();
  size_t height = shared_rect.height();

  Ogre::TexturePtr shadow = Ogre::TextureManager::getSingleton().createManual("scrollbuf", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, Ogre::Bitwise::firstPO2From(width), Ogre::Bitwise::firstPO2From(height), 1, 1, Ogre::PF_BYTE_BGRA);
  {
    Ogre::HardwarePixelBufferSharedPtr shadowBuffer = shadow->getBuffer();

    Berkelium::Rect borderedScrollRect = GetBorderedRect(shared_rect);
    Berkelium::Rect borderedScrolledRect = GetBorderedRect(scrolled_shared_rect);

    shadowBuffer->blit(pixelBuffer, Ogre::Box(borderedScrollRect.left(), borderedScrollRect.top(), borderedScrollRect.right(), borderedScrollRect.bottom()), Ogre::Box(0, 0, width, height));

    pixelBuffer->blit(shadowBuffer, Ogre::Box(0, 0, width, height), Ogre::Box(borderedScrolledRect.left(), borderedScrolledRect.top(), borderedScrolledRect.right(), borderedScrolledRect.bottom()));
  }

  Ogre::ResourcePtr shadowResource(shadow);
  Ogre::TextureManager::getSingleton().remove(shadowResource);

}
void UnityBerkeliumWindow::convertColors(const Berkelium::Rect &rect, const unsigned char *sourceBuffer)
{
	// Note: we convert from BGRA bytes to RGBA floats. RGB24 textures in Unity are still 32bit in memory.
	for(int x = rect.left(); x < rect.right(); ++x)
	{
		for(int y = rect.top(); y < rect.bottom(); ++y)
		{
			// We copy to the beginning of the buffer
			// (because we can't change the start address of the buffer we provide the Unity .SetPixels function
			int idx = (y - rect.top()) * rect.width() + (x - rect.left());
			//int idx = y * rect.width() + x;

			m_buffer[idx * 4 + 0] = sourceBuffer[idx * 4 + 2] / 255.0f; // R
			m_buffer[idx * 4 + 1] = sourceBuffer[idx * 4 + 1] / 255.0f; // G
			m_buffer[idx * 4 + 2] = sourceBuffer[idx * 4 + 0] / 255.0f; // B
			
			if(m_transparency)
				m_buffer[idx * 4 + 3] = sourceBuffer[idx * 4 + 3] / 255.0f; // A
		}
	}
}
void UnityBerkeliumWindow::convertColors(const Berkelium::Rect &rect, const unsigned char *sourceBuffer, const Berkelium::Rect &srcRect)
{
    int top = rect.top() - srcRect.top();
    int left = rect.left() - srcRect.left();
	
    // Note: we convert from BGRA bytes to RGBA floats. RGB24 textures in Unity are still 32bit in memory.
	for(int x = 0; x < rect.width(); ++x)
	{
		for(int y = 0; y < rect.height(); ++y)
		{
			int idx = (rect.height() - (y + 1)) * rect.width() + x;
			int sourceIdx = left + (y + top) * srcRect.width() + x;

			m_buffer[idx * 4 + 0] = sourceBuffer[sourceIdx * 4 + 2] / 255.0f; // R
			m_buffer[idx * 4 + 1] = sourceBuffer[sourceIdx * 4 + 1] / 255.0f; // G
			m_buffer[idx * 4 + 2] = sourceBuffer[sourceIdx * 4 + 0] / 255.0f; // B
			
			if(m_transparency)
				m_buffer[idx * 4 + 3] = sourceBuffer[sourceIdx * 4 + 3] / 255.0f; // A
		}
	}
}
void BrowserWindowImpl::onPaint(
	Berkelium::Window *win,
	const unsigned char *sourceBuffer,
	const Berkelium::Rect &sourceBufferRect,
	size_t numCopyRects,
	const Berkelium::Rect *copyRects,
	int dx, int dy,
	const Berkelium::Rect &scrollRect)
{
//	std::cout<<"Paint:"<<std::endl;
	video::IHardwarePixelBuffer* surface= m_texture->getSurface(0);


	video::ColorConverter::convert32BitTo32Bit(sourceBuffer,m_flipped,math::vector2d(sourceBufferRect.width(),sourceBufferRect.height()),0,1,1);

	video::LockedPixelBox lockedBox(
		math::box3d(sourceBufferRect.left(),sourceBufferRect.top(),0,
		sourceBufferRect.right(),sourceBufferRect.bottom(),1),video::EPixel_X8R8G8B8,(void*)m_flipped);

	lockedBox.box.MinP.y=m_size.y-lockedBox.box.MinP.y;
	lockedBox.box.MaxP.y=m_size.y-lockedBox.box.MaxP.y;

	math::Swap(lockedBox.box.MinP.y,lockedBox.box.MaxP.y);

	if(m_refresh)
	{
		surface->blitFromMemory(lockedBox);
		m_refresh=false;
		return;
	}

	for(int i=0;i<numCopyRects;++i)
	{
	//	std::cout << "\tRect: " << copyRects[i].width()<<" "<<copyRects[i].height()<< std::endl;

		math::box3d lockBox(copyRects[i].left(),copyRects[i].top(),0,
			copyRects[i].right(),copyRects[i].bottom(),1);
		lockBox.MinP.y=m_size.y-lockBox.MinP.y;
		lockBox.MaxP.y=m_size.y-lockBox.MaxP.y;
		math::Swap(lockBox.MinP.y,lockBox.MaxP.y);

		video::LockedPixelBox lb=lockedBox.getSubBox(lockBox);
		surface->blitFromMemory(lb);
		// 			const video::LockedPixelBox& lb= surface->lock(lockBox,video::IHardwareBuffer::ELO_Discard);
		// 			memcpy(lb.data,sourceBuffer,sourceBufferRect.width()*sourceBufferRect.height()*4
	}


}
Example #5
0
	virtual void onPaint
	(
		Berkelium::Window* wini,
		const unsigned char *bitmap_in,
		const Berkelium::Rect &bitmap_rect,
		size_t num_copy_rects,
		const Berkelium::Rect* copy_rects,
		int dx,
		int dy,
		const Berkelium::Rect& scroll_rect
	)
	{
		if (!tex || (tex->GetFlags() & r3dTexture::fCreated) == 0 || !d_show_browser->GetBool()) return;

		void * dstBuf = tex->Lock(true);

		if (dstBuf)
		{
			ScrollSubrect(dstBuf, scroll_rect, dx, dy);

			for (size_t i = 0; i < num_copy_rects; ++i)
			{
				//	Calc bitmap_rect relative coordinates
				int height = copy_rects[i].height();
				int width = copy_rects[i].width();
				int left = copy_rects[i].left();
				int top = copy_rects[i].top();

				r3d_assert(bitmap_rect.left() <= left);
				r3d_assert(bitmap_rect.top() <= top);
				r3d_assert(bitmap_rect.width() >= width);
				r3d_assert(bitmap_rect.height() >= height);

				unsigned char *dstPtr = reinterpret_cast<byte*>(dstBuf) + left * pixelSize + top * tex->GetLockPitch();
				const unsigned char *srcPtr = bitmap_in + (left - bitmap_rect.left()) * pixelSize + (top - bitmap_rect.top()) * bitmap_rect.width() * pixelSize;
				
				for (int j = 0; j < height; ++j)
				{
					memcpy(dstPtr, srcPtr, width * pixelSize);
					dstPtr += tex->GetLockPitch();
					srcPtr += bitmap_rect.width() * pixelSize;
				}
			}
		}

		tex->Unlock();
	}
void UnityBerkeliumWindow::onPaint(Berkelium::Window *pWindow, const unsigned char *sourceBuffer, const Berkelium::Rect &rect, int dx, int dy, const Berkelium::Rect &scrollRect)
{
#ifdef DEBUG
	cerr << "[UnityBerkeliumWindow] onPaint called (window: " << pWindow << ")" << endl;
	cerr << "  rect: (left=" << rect.left() << ", width=" << rect.width() << ", top=" << rect.top() << ", height=" << rect.height() << ")" << endl;
	cerr << "  sourceBuffer: " << (void *) sourceBuffer << endl;
#endif

	// Scrolling
	if(dx != 0 || dy != 0)
	{
#if 0
		// scroll_rect contains the Rect we need to move
		// First we figure out where the the data is moved to by translating it
		//Berkelium::Rect scrolled_rect = scrollRect.translate(-dx, -dy);
		Berkelium::Rect scrolled_rect = scrollRect;
		scrolled_rect.mLeft -= dx;
		scrolled_rect.mTop -= dy;

		// Next we figure out where they intersect, giving the scrolled
		// region
		Berkelium::Rect scrolled_shared_rect = scrollRect.intersect(scrolled_rect);

		// Only do scrolling if they have non-zero intersection
		if(scrolled_shared_rect.width() > 0 && scrolled_shared_rect.height() > 0)
		{
			// And the scroll is performed by moving shared_rect by (dx,dy)
			//Berkelium::Rect shared_rect = scrolled_shared_rect.translate(dx, dy);
			Berkelium::Rect shared_rect = scrolled_shared_rect;
			shared_rect.mLeft += dx;
			shared_rect.mTop += dy;

			for(int y = scrolled_shared_rect.top(); y < shared_rect.bottom(); ++y)
			{
				::memcpy(
					m_buffer + y * m_width * 4 /*+ scrolled_shared_rect.left() * 4*/,
					m_buffer + ((scrolled_shared_rect.top() + y) * m_width /*+ scrolled_shared_rect.left()*/) * 4,
					scrolled_shared_rect.width() * 4
				);
			}

			// Copy the data out of the texture
			/*size_t scrollBuffSize = scrolled_shared_rect.width() * scrolled_shared_rect.height() * 4;
			unsigned char *scrollBuffer = new unsigned char[scrollBuffSize];
			
			for(int line = 0; line < scrolled_shared_rect.height(); ++line)
			{
				::memcpy(
					scrollBuffer + line * scrolled_shared_rect.width() * 4,

			}*/
#if 0
			glGetTexImage(
				GL_TEXTURE_2D, 0,
				GL_BGRA, GL_UNSIGNED_BYTE,
				scroll_buffer
				);

			// Annoyingly, OpenGL doesn't provide convenient primitives, so
			// we manually copy out the region to the beginning of the
			// buffer
			int wid = scrolled_shared_rect.width();
			int hig = scrolled_shared_rect.height();
			for(int jj = 0; jj < hig; jj++) {
				memcpy(
					scroll_buffer + (jj*wid * 4),
					scroll_buffer + ((scrolled_shared_rect.top()+jj)*dest_texture_width + scrolled_shared_rect.left()) * 4,
					wid*4
					);
			}

			// And finally, we push it back into the texture in the right
			// location
			glTexSubImage2D(GL_TEXTURE_2D, 0,
				shared_rect.left(), shared_rect.top(),
				shared_rect.width(), shared_rect.height(),
				GL_BGRA, GL_UNSIGNED_BYTE, scroll_buffer
				);
#endif
		}
#endif
	}

	// Apply the dirty rectangle
	convertColors(rect, sourceBuffer);

	// Call the paint callback
	m_lastDirtyRect = rect;
	m_paintFunc(/*rect.left(), rect.top(), rect.width(), rect.height()*/);
}
void UnityBerkeliumWindow::onPaint(Berkelium::Window *win, const unsigned char *sourceBuffer, const Berkelium::Rect &sourceBufferRect, size_t numCopyRects, const Berkelium::Rect *copyRects, int dx, int dy, const Berkelium::Rect &scrollRect)
{
#ifdef DEBUG
	cerr << "[UnityBerkeliumWindow] onPaint called (window: " << win << ")" << endl;
	cerr << "  sourceBuffer: " << (void *) sourceBuffer << endl;
	cerr << "  sourceBufferRect: (left=" << sourceBufferRect.left() << ", width=" << sourceBufferRect.width() << ", top=" << sourceBufferRect.top() << ", height=" << sourceBufferRect.height() << ")" << endl;
	cerr << "  num dirty rects: " << numCopyRects << endl;
	for(size_t i = 0; i < numCopyRects; ++i)
		cerr << "  rect " << i << ": (left=" << copyRects[i].left() << ", width=" << copyRects[i].width() << ", top=" << copyRects[i].top() << ", height=" << copyRects[i].height() << ")" << endl;
#endif

	// Handle Scrolling
	if(dx != 0 || dy != 0)
	{
        // scroll_rect contains the Rect we need to move
        // First we figure out where the the data is moved to by translating it
        Berkelium::Rect scrolled_rect = scrollRect.translate(-dx, -dy);
        // Next we figure out where they intersect, giving the scrolled
        // region
        Berkelium::Rect scrolled_shared_rect = scrollRect.intersect(scrolled_rect);
        // Only do scrolling if they have non-zero intersection
        if (scrolled_shared_rect.width() > 0 && scrolled_shared_rect.height() > 0) {
            // And the scroll is performed by moving shared_rect by (dx,dy)
            scrolled_shared_rect.mTop = m_height - scrolled_shared_rect.bottom();
            dy = -dy;
            if(m_scrollRectFunc)
                m_scrollRectFunc(scrolled_shared_rect.left(), scrolled_shared_rect.top(), scrolled_shared_rect.width(), scrolled_shared_rect.height(), dx, dy);
      }
	}

	// Apply the dirty rectangles
	for(size_t i = 0; i < numCopyRects; ++i)
	{
		convertColors(copyRects[i], sourceBuffer, sourceBufferRect);
		m_lastDirtyRect = copyRects[i];
        m_lastDirtyRect.mTop = m_height - m_lastDirtyRect.bottom();
        
		if(m_setPixelsFunc)
			m_setPixelsFunc(/*rect.left(), rect.top(), rect.width(), rect.height()*/);
	}

	// Call the paint callback
	if(m_applyTextureFunc)
		m_applyTextureFunc();
}
/**
 * @inheritDoc.
 */
inline Ogre::Box BrowserWindow::rectToBox(Berkelium::Rect rect) {
    return Ogre::Box(rect.left(), rect.top(), 0, rect.right(), rect.bottom(), 1);
}
Example #9
0
	void ScrollSubrect(void *data, const Berkelium::Rect& scroll_rect, int dx, int dy)
	{
		if (!data || !tex)
			return;

		byte *byteData = reinterpret_cast<byte*>(data);

		Berkelium::Rect dstRect = scroll_rect.translate(dx, dy);
		
		//	Y scroll
		if (dy != 0)
		{
			int lineOffset = dy < 0 ? 1 : -1;

			int srcLine = dy < 0 ? scroll_rect.top() : scroll_rect.bottom() - 1;
			int dstLine = dy < 0 ? dstRect.top() : dstRect.bottom() - 1;

			int i = 0;
			while (i < scroll_rect.height())
			{
				if (srcLine >= scroll_rect.top() && dstLine >= scroll_rect.top() && srcLine < scroll_rect.bottom() && dstLine < scroll_rect.bottom())
				{
					byte *srcMem = byteData + srcLine * tex->GetLockPitch() + scroll_rect.left() * pixelSize;
					byte *dstMem = byteData + dstLine * tex->GetLockPitch() + scroll_rect.left() * pixelSize;
					size_t bytesToCopy = scroll_rect.width() * pixelSize;

					#ifndef FINAL_BUILD
						//	Paranoid memory overrun check
						r3d_assert(dstMem + bytesToCopy <= byteData + tex->GetHeight() * tex->GetLockPitch());
					#endif

					memcpy_s(dstMem, bytesToCopy, srcMem, bytesToCopy);
				}

				++i;
				srcLine += lineOffset;
				dstLine += lineOffset;
			}
		}

		//	X Scroll
		if (dx != 0)
		{
			Berkelium::Rect r = scroll_rect.intersect(dstRect);

			size_t tmpBufSize = r.width() * pixelSize;
			byte *tmpBuf = reinterpret_cast<byte*>(_alloca(tmpBufSize));

			int srcOffset = r3dTL::Clamp(scroll_rect.left() - dx, 0, scroll_rect.right());

			for (int i = r.top(); i < r.bottom(); ++i)
			{
				byte *srcData = byteData + i * tex->GetLockPitch() + srcOffset * pixelSize;
				byte *dstData = byteData + i * tex->GetLockPitch() + r.left() * pixelSize;
				memcpy_s(tmpBuf, tmpBufSize, srcData, tmpBufSize);

				#ifndef FINAL_BUILD
					//	Paranoid memory overrun check
					r3d_assert(dstData + tmpBufSize <= byteData + tex->GetHeight() * tex->GetLockPitch());
				#endif

				memcpy_s(dstData, tmpBufSize, tmpBuf, tmpBufSize);
			}
		}
	}
/** Handles an onPaint call by mapping the results into an OpenGL texture. The
 *  first parameters are the same as Berkelium::WindowDelegate::onPaint.  The
 *  additional parameters and return value are:
 *  \param dest_texture - the OpenGL texture handle for the texture to render
 *                        the results into.
 *  \param dest_texture_width - width of destination texture
 *  \param dest_texture_height - height of destination texture
 *  \param ignore_partial - if true, ignore any partial updates.  This is useful
 *         if you have loaded a new page, but updates for the old page have not
 *         completed yet.
 *  \param scroll_buffer - a temporary workspace used for scroll data.  Must be
 *         at least dest_texture_width * dest_texture_height * 4 bytes large.
 *  \returns true if the texture was updated, false otherwiase
 */
bool ofxBerkelium::mapOnPaintToTexture(
						 Berkelium::Window *wini,
						 const unsigned char* bitmap_in, const Berkelium::Rect& bitmap_rect,
						 size_t num_copy_rects, const Berkelium::Rect *copy_rects,
						 int dx, int dy,
						 const Berkelium::Rect& scroll_rect,
						 bool ignore_partial) {

    glBindTexture(GL_TEXTURE_2D, web_texture);

    const int kBytesPerPixel = 4;

    // If we've reloaded the page and need a full update, ignore updates
    // until a full one comes in.  This handles out of date updates due to
    // delays in event processing.
    if (ignore_partial) {
        if (bitmap_rect.left() != 0 ||
            bitmap_rect.top() != 0 ||
            bitmap_rect.right() != width ||
            bitmap_rect.bottom() != height) {
            return false;
        }

        glTexImage2D(GL_TEXTURE_2D, 0, kBytesPerPixel, width, height, 0,
					 GL_BGRA, GL_UNSIGNED_BYTE, bitmap_in);
        ignore_partial = false;
        return true;
    }


    // Now, we first handle scrolling. We need to do this first since it
    // requires shifting existing data, some of which will be overwritten by
    // the regular dirty rect update.
    if (dx != 0 || dy != 0) {
        // scroll_rect contains the Rect we need to move
        // First we figure out where the the data is moved to by translating it
        Berkelium::Rect scrolled_rect = scroll_rect.translate(-dx, -dy);
        // Next we figure out where they intersect, giving the scrolled
        // region
        Berkelium::Rect scrolled_shared_rect = scroll_rect.intersect(scrolled_rect);
        // Only do scrolling if they have non-zero intersection
        if (scrolled_shared_rect.width() > 0 && scrolled_shared_rect.height() > 0) {
            // And the scroll is performed by moving shared_rect by (dx,dy)
            Berkelium::Rect shared_rect = scrolled_shared_rect.translate(dx, dy);

            int wid = scrolled_shared_rect.width();
            int hig = scrolled_shared_rect.height();
            if (DEBUG_PAINT) {
				std::cout << "Scroll rect: w=" << wid << ", h=" << hig << ", ("
				<< scrolled_shared_rect.left() << "," << scrolled_shared_rect.top()
				<< ") by (" << dx << "," << dy << ")" << std::endl;
            }
            int inc = 1;
            char *outputBuffer = scroll_buffer;
            // source data is offset by 1 line to prevent memcpy aliasing
            // In this case, it can happen if dy==0 and dx!=0.
            char *inputBuffer = scroll_buffer+(width*1*kBytesPerPixel);
            int jj = 0;
            if (dy > 0) {
                // Here, we need to shift the buffer around so that we start in the
                // extra row at the end, and then copy in reverse so that we
                // don't clobber source data before copying it.
                outputBuffer = scroll_buffer+(
											  (scrolled_shared_rect.top()+hig+1)*width
											  - hig*wid)*kBytesPerPixel;
                inputBuffer = scroll_buffer;
                inc = -1;
                jj = hig-1;
            }

            // Copy the data out of the texture
            glGetTexImage(
						  GL_TEXTURE_2D, 0,
						  GL_BGRA, GL_UNSIGNED_BYTE,
						  inputBuffer
						  );

            // Annoyingly, OpenGL doesn't provide convenient primitives, so
            // we manually copy out the region to the beginning of the
            // buffer
            for(; jj < hig && jj >= 0; jj+=inc) {
                memcpy(
					   outputBuffer + (jj*wid) * kBytesPerPixel,
					   //scroll_buffer + (jj*wid * kBytesPerPixel),
					   inputBuffer + (
									  (scrolled_shared_rect.top()+jj)*width
									  + scrolled_shared_rect.left()) * kBytesPerPixel,
					   wid*kBytesPerPixel
					   );
            }

            // And finally, we push it back into the texture in the right
            // location
            glTexSubImage2D(GL_TEXTURE_2D, 0,
							shared_rect.left(), shared_rect.top(),
							shared_rect.width(), shared_rect.height(),
							GL_BGRA, GL_UNSIGNED_BYTE, outputBuffer
							);
        }
    }

    if (DEBUG_PAINT) {
		std::cout << "Bitmap rect: w="
		<< bitmap_rect.width()<<", h="<<bitmap_rect.height()
		<<", ("<<bitmap_rect.top()<<","<<bitmap_rect.left()
		<<") tex size "<<width<<"x"<<height
		<<std::endl;
    }
    for (size_t i = 0; i < num_copy_rects; i++) {
        int wid = copy_rects[i].width();
        int hig = copy_rects[i].height();
        int top = copy_rects[i].top() - bitmap_rect.top();
        int left = copy_rects[i].left() - bitmap_rect.left();
        if (DEBUG_PAINT) {
            std::cout << "Copy rect: w=" << wid << ", h=" << hig << ", ("
			<< top << "," << left << ")" << std::endl;
        }
        for(int jj = 0; jj < hig; jj++) {
            memcpy(
				   scroll_buffer + jj*wid*kBytesPerPixel,
				   bitmap_in + (left + (jj+top)*bitmap_rect.width())*kBytesPerPixel,
				   wid*kBytesPerPixel
				   );
        }

        // Finally, we perform the main update, just copying the rect that is
        // marked as dirty but not from scrolled data.
        glTexSubImage2D(GL_TEXTURE_2D, 0,
                        copy_rects[i].left(), copy_rects[i].top(),
                        wid, hig,
                        GL_BGRA, GL_UNSIGNED_BYTE, scroll_buffer
						);
    }

    glBindTexture(GL_TEXTURE_2D, 0);

    return true;
}
Example #11
0
void browser::onPaint( Berkelium::Window* wini,
                        const unsigned char* bitmap_in,
                        const Berkelium::Rect& bitmap_rect,
                        size_t num_copy_rects,
                        const Berkelium::Rect* copy_rects,
                        int dx,
                        int dy,
                        const Berkelium::Rect& scroll_rect )
{
  const int bytes_per_pixel = 4;

#ifdef BROWSER_USE_EXCEPTIONS
  try
#endif
  {
    browser_instance& w = *instances.at( wini );

    glBindTexture( GL_TEXTURE_2D, w.browser_texture );

    if( w.full_refresh )
    {
      if( bitmap_rect.left() != 0 ||
          bitmap_rect.top() != 0 ||
          bitmap_rect.right() != w.screen.x ||
          bitmap_rect.bottom() != w.screen.y )
      {
        return;
      }
      else
      {
        glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, w.screen.x, w.screen.y, 0, GL_BGRA, GL_UNSIGNED_BYTE, (void*)bitmap_in );
        w.full_refresh = false;
        return;
      }
    }

    if( dx != 0 || dy != 0 )
    {
      Berkelium::Rect scrolled_rect = scroll_rect.translate( -dx, -dy );
      Berkelium::Rect scrolled_shared_rect = scroll_rect.intersect( scrolled_rect );

      if( scrolled_shared_rect.width() > 0 && scrolled_shared_rect.height() > 0 )
      {
        Berkelium::Rect shared_rect = scrolled_shared_rect.translate( dx, dy );

        int wid = scrolled_shared_rect.width();
        int hig = scrolled_shared_rect.height();

        int inc = 1;
        char* output_buffer = w.scroll_buffer;
        char* input_buffer = w.scroll_buffer + ( w.screen.x * 1 * bytes_per_pixel );

        int jj = 0;

        if( dy > 0 )
        {
          output_buffer = w.scroll_buffer + ( ( scrolled_shared_rect.top() + hig + 1 ) * w.screen.x - hig * wid ) * bytes_per_pixel;
          input_buffer = w.scroll_buffer;
          inc = -1;
          jj = hig - 1;
        }

        glGetTexImage( GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, input_buffer );

        for( ; jj < hig && jj >= 0; jj += inc )
        {
          memcpy( output_buffer + ( jj * wid ) * bytes_per_pixel,
                  input_buffer + ( ( scrolled_shared_rect.top() + jj ) * w.screen.x + scrolled_shared_rect.left() ) * bytes_per_pixel,
                  wid * bytes_per_pixel );
        }

        glTexSubImage2D( GL_TEXTURE_2D, 0, shared_rect.left(), shared_rect.top(), shared_rect.width(), shared_rect.height(), GL_BGRA, GL_UNSIGNED_BYTE, output_buffer );
      }
    }

    for( size_t i = 0; i < num_copy_rects; i++ )
    {
      int wid = copy_rects[i].width();
      int hig = copy_rects[i].height();
      int top = copy_rects[i].top() - bitmap_rect.top();
      int left = copy_rects[i].left() - bitmap_rect.left();

      for( int jj = 0; jj < hig; jj++ )
      {
        memcpy( w.scroll_buffer + jj * wid * bytes_per_pixel,
                bitmap_in + ( left + ( jj + top ) * bitmap_rect.width() ) * bytes_per_pixel,
                wid * bytes_per_pixel );
      }

      glTexSubImage2D( GL_TEXTURE_2D, 0, copy_rects[i].left(), copy_rects[i].top(), wid, hig, GL_BGRA, GL_UNSIGNED_BYTE, w.scroll_buffer );
    }

    w.full_refresh = false;
  }
#ifdef BROWSER_USE_EXCEPTIONS
  catch( ... )
  {
  }
#endif
}
void UnityBerkeliumWindow::onPaint(Berkelium::Window *win, const unsigned char *sourceBuffer, const Berkelium::Rect &sourceBufferRect, size_t numCopyRects, const Berkelium::Rect *copyRects, int dx, int dy, const Berkelium::Rect &scrollRect)
{
#ifdef DEBUG
	cerr << "[UnityBerkeliumWindow] onPaint called (window: " << win << ")" << endl;
	cerr << "  sourceBuffer: " << (void *) sourceBuffer << endl;
	cerr << "  sourceBufferRect: (left=" << sourceBufferRect.left() << ", width=" << sourceBufferRect.width() << ", top=" << sourceBufferRect.top() << ", height=" << sourceBufferRect.height() << ")" << endl;
	cerr << "  num dirty rects: " << numCopyRects << endl;
	for(size_t i = 0; i < numCopyRects; ++i)
		cerr << "  rect " << i << ": (left=" << copyRects[i].left() << ", width=" << copyRects[i].width() << ", top=" << copyRects[i].top() << ", height=" << copyRects[i].height() << ")" << endl;
#endif

	//! @todo Handle Scrolling
	if(dx != 0 || dy != 0)
	{
	}

	// Apply the dirty rectangles
	for(size_t i = 0; i < numCopyRects; ++i)
	{
		convertColors(copyRects[i], sourceBuffer);
		m_lastDirtyRect = copyRects[i];

		if(m_setPixelsFunc)
			m_setPixelsFunc(/*rect.left(), rect.top(), rect.width(), rect.height()*/);
	}

	// Call the paint callback
	if(m_applyTextureFunc)
		m_applyTextureFunc();
}