void X11Graphics::drawRect( int left, int top, int width, int height, uint32_t color ) { // Update the mask with the rectangle addHSegmentInRegion( m_mask, left, left + width, top ); addHSegmentInRegion( m_mask, left, left + width, top + height ); addVSegmentInRegion( m_mask, top, top + height, left ); addVSegmentInRegion( m_mask, top, top + height, left + width ); // Draw the rectangle XGCValues gcVal; gcVal.foreground = m_rDisplay.getPixelValue( color >> 16, color >> 8, color ); XChangeGC( XDISPLAY, m_gc, GCForeground, &gcVal ); XSetRegion( XDISPLAY, m_gc, m_mask ); XDrawRectangle( XDISPLAY, m_pixmap, m_gc, left, top, width - 1, height - 1 ); }
void X11Graphics::drawBitmap( const GenericBitmap &rBitmap, int xSrc, int ySrc, int xDest, int yDest, int width, int height, bool blend ) { // Get the bitmap size if necessary if( width == -1 ) { width = rBitmap.getWidth(); } else if( width > rBitmap.getWidth() ) { msg_Dbg( getIntf(), "bitmap width too small (%i)", rBitmap.getWidth() ); width = rBitmap.getWidth(); } if( height == -1 ) { height = rBitmap.getHeight(); } else if( height > rBitmap.getHeight() ) { msg_Dbg( getIntf(), "bitmap height too small (%i)", rBitmap.getHeight() ); height = rBitmap.getHeight(); } // Nothing to draw if width or height is null if( width == 0 || height == 0 ) { return; } // Safety check for debugging purpose if( xDest + width > m_width || yDest + height > m_height ) { msg_Dbg( getIntf(), "bitmap too large" ); return; } // Get a buffer on the image data uint8_t *pBmpData = rBitmap.getData(); if( pBmpData == NULL ) { // Nothing to draw return; } // Get the image from the pixmap XImage *pImage = XGetImage( XDISPLAY, m_pixmap, xDest, yDest, width, height, AllPlanes, ZPixmap ); if( pImage == NULL ) { msg_Dbg( getIntf(), "XGetImage returned NULL" ); return; } char *pData = pImage->data; // Get the padding of this image int pad = pImage->bitmap_pad >> 3; int shift = ( pad - ( (width * XPIXELSIZE) % pad ) ) % pad; // Mask for transparency Region mask = XCreateRegion(); // Get a pointer on the right X11Display::makePixel method X11Display::MakePixelFunc_t makePixelFunc = ( blend ? m_rDisplay.getBlendPixel() : m_rDisplay.getPutPixel() ); // Skip the first lines of the image pBmpData += 4 * ySrc * rBitmap.getWidth(); // Copy the bitmap on the image and compute the mask for( int y = 0; y < height; y++ ) { // Skip uninteresting bytes at the beginning of the line pBmpData += 4 * xSrc; // Flag to say whether the previous pixel on the line was visible bool wasVisible = false; // Beginning of the current visible segment on the line int visibleSegmentStart = 0; for( int x = 0; x < width; x++ ) { uint8_t b = *(pBmpData++); uint8_t g = *(pBmpData++); uint8_t r = *(pBmpData++); uint8_t a = *(pBmpData++); // Draw the pixel (m_rDisplay.*makePixelFunc)( (uint8_t*)pData, r, g, b, a ); pData += XPIXELSIZE; if( a > 0 ) { // Pixel is visible if( ! wasVisible ) { // Beginning of a visible segment visibleSegmentStart = x; } wasVisible = true; } else { // Pixel is transparent if( wasVisible ) { // End of a visible segment: add it to the mask addHSegmentInRegion( mask, visibleSegmentStart, x, y ); } wasVisible = false; } } if( wasVisible ) { // End of a visible segment: add it to the mask addHSegmentInRegion( mask, visibleSegmentStart, width, y ); } pData += shift; // Skip uninteresting bytes at the end of the line pBmpData += 4 * (rBitmap.getWidth() - width - xSrc); } // Apply the mask to the graphics context XOffsetRegion( mask, xDest, yDest ); XSetRegion( XDISPLAY, m_gc, mask ); // Copy the image on the pixmap XPutImage( XDISPLAY, m_pixmap, m_gc, pImage, 0, 0, xDest, yDest, width, height); XDestroyImage( pImage ); // Add the bitmap mask to the global graphics mask Region newMask = XCreateRegion(); XUnionRegion( mask, m_mask, newMask ); XDestroyRegion( m_mask ); m_mask = newMask; XDestroyRegion( mask ); }
void X11Graphics::drawBitmap( const GenericBitmap &rBitmap, int xSrc, int ySrc, int xDest, int yDest, int width, int height, bool blend ) { // check and adapt to source if needed if( !checkBoundaries( 0, 0, rBitmap.getWidth(), rBitmap.getHeight(), xSrc, ySrc, width, height ) ) { msg_Err( getIntf(), "empty source! pls, debug your skin" ); return; } // check destination if( !checkBoundaries( 0, 0, m_width, m_height, xDest, yDest, width, height ) ) { msg_Err( getIntf(), "out of reach destination! pls, debug your skin" ); return; } // Get a buffer on the image data uint8_t *pBmpData = rBitmap.getData(); if( pBmpData == NULL ) { // Nothing to draw return; } // Force pending XCopyArea to be sent to the X Server // before issuing an XGetImage. XSync( XDISPLAY, False ); // Get the image from the pixmap XImage *pImage = XGetImage( XDISPLAY, m_pixmap, xDest, yDest, width, height, AllPlanes, ZPixmap ); if( pImage == NULL ) { msg_Dbg( getIntf(), "XGetImage returned NULL" ); return; } char *pData = pImage->data; // Get the padding of this image int pad = pImage->bitmap_pad >> 3; int shift = ( pad - ( (width * XPIXELSIZE) % pad ) ) % pad; // Mask for transparency Region mask = XCreateRegion(); // Get a pointer on the right X11Display::makePixel method X11Display::MakePixelFunc_t makePixelFunc = ( blend ? m_rDisplay.getBlendPixel() : m_rDisplay.getPutPixel() ); // Skip the first lines of the image pBmpData += 4 * ySrc * rBitmap.getWidth(); // Copy the bitmap on the image and compute the mask for( int y = 0; y < height; y++ ) { // Skip uninteresting bytes at the beginning of the line pBmpData += 4 * xSrc; // Flag to say whether the previous pixel on the line was visible bool wasVisible = false; // Beginning of the current visible segment on the line int visibleSegmentStart = 0; for( int x = 0; x < width; x++ ) { uint8_t b = *(pBmpData++); uint8_t g = *(pBmpData++); uint8_t r = *(pBmpData++); uint8_t a = *(pBmpData++); // Draw the pixel (m_rDisplay.*makePixelFunc)( (uint8_t*)pData, r, g, b, a ); pData += XPIXELSIZE; if( a > 0 ) { // Pixel is visible if( ! wasVisible ) { // Beginning of a visible segment visibleSegmentStart = x; } wasVisible = true; } else { // Pixel is transparent if( wasVisible ) { // End of a visible segment: add it to the mask addHSegmentInRegion( mask, visibleSegmentStart, x, y ); } wasVisible = false; } } if( wasVisible ) { // End of a visible segment: add it to the mask addHSegmentInRegion( mask, visibleSegmentStart, width, y ); } pData += shift; // Skip uninteresting bytes at the end of the line pBmpData += 4 * (rBitmap.getWidth() - width - xSrc); } // Apply the mask to the graphics context XOffsetRegion( mask, xDest, yDest ); XSetRegion( XDISPLAY, m_gc, mask ); // Copy the image on the pixmap XPutImage( XDISPLAY, m_pixmap, m_gc, pImage, 0, 0, xDest, yDest, width, height); XDestroyImage( pImage ); // Add the bitmap mask to the global graphics mask Region newMask = XCreateRegion(); XUnionRegion( mask, m_mask, newMask ); XDestroyRegion( m_mask ); m_mask = newMask; XDestroyRegion( mask ); }