|
|
|
|
Quelle macosx_graphics.mm Sprache: unbekannt
|
|
Spracherkennung für: .mm vermutete Sprache: Masm {Masm[60] ABAP[36] Cobol[36]} [Methode: maximale Elemente, drei Dimensionen]
/*****************************************************************************
* macosx_graphics.mm
*****************************************************************************
* Copyright (C) 2026 the VideoLAN team
*
* Authors: Fletcher Holt <fletcherholt649@gmail.com>
* Felix Paul Kühne <fkuehne@videolan.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#import <Cocoa/Cocoa.h>
#import <CoreGraphics/CoreGraphics.h>
#include "macosx_graphics.hpp"
#include "macosx_window.hpp"
#include "../src/generic_bitmap.hpp"
#include <cstring>
@protocol VLCHitTestGraphics
- (void)setHitTestGraphics:(const MacOSXGraphics *)pGraphics;
@end
MacOSXGraphics::MacOSXGraphics( intf_thread_t *pIntf, int width, int height ):
OSGraphics( pIntf ), m_width( width ), m_height( height )
{
// Allocate BGRA pixel buffer
m_bytesPerRow = width * 4;
m_pData = new uint8_t[m_bytesPerRow * height];
memset( m_pData, 0, m_bytesPerRow * height );
m_colorSpace = CGColorSpaceCreateDeviceRGB();
}
MacOSXGraphics::~MacOSXGraphics()
{
CGColorSpaceRelease( m_colorSpace );
delete[] m_pData;
}
void MacOSXGraphics::clear( int xDest, int yDest, int width, int height )
{
if( width == -1 )
width = m_width;
if( height == -1 )
height = m_height;
// Clamp to valid range
if( xDest < 0 )
{
width += xDest;
xDest = 0;
}
if( yDest < 0 )
{
height += yDest;
yDest = 0;
}
if( xDest + width > m_width )
width = m_width - xDest;
if( yDest + height > m_height )
height = m_height - yDest;
if( width <= 0 || height <= 0 )
return;
// Clear the specified region to transparent
for( int y = yDest; y < yDest + height; y++ )
{
memset( m_pData + y * m_bytesPerRow + xDest * 4, 0, width * 4 );
}
}
void MacOSXGraphics::drawGraphics( const OSGraphics &rGraphics,
int xSrc, int ySrc,
int xDest, int yDest,
int width, int height )
{
const MacOSXGraphics &rSrc = static_cast<const MacOSXGraphics&>(rGraphics);
if( width == -1 )
width = rSrc.getWidth();
if( height == -1 )
height = rSrc.getHeight();
int srcWidth = rSrc.getWidth();
int srcHeight = rSrc.getHeight();
if( !checkBoundaries( xSrc, ySrc, srcWidth, srcHeight,
xDest, yDest, width, height ) )
return;
const uint8_t *pSrcData = rSrc.getData();
// Copy pixel data with alpha blending
for( int y = 0; y < height; y++ )
{
for( int x = 0; x < width; x++ )
{
int srcOffset = (ySrc + y) * rSrc.m_bytesPerRow + (xSrc + x) * 4;
int dstOffset = (yDest + y) * m_bytesPerRow + (xDest + x) * 4;
// Simple copy (source over destination)
uint8_t srcAlpha = pSrcData[srcOffset + 3];
if( srcAlpha == 255 )
{
// Fully opaque - just copy
memcpy( m_pData + dstOffset, pSrcData + srcOffset, 4 );
}
else if( srcAlpha > 0 )
{
// Alpha blend
uint8_t dstAlpha = m_pData[dstOffset + 3];
uint8_t outAlpha = srcAlpha + (dstAlpha * (255 - srcAlpha)) / 255;
if( outAlpha > 0 )
{
for( int c = 0; c < 3; c++ )
{
m_pData[dstOffset + c] = (uint8_t)(
(pSrcData[srcOffset + c] * srcAlpha +
m_pData[dstOffset + c] * dstAlpha * (255 - srcAlpha) / 255) / outAlpha
);
}
m_pData[dstOffset + 3] = outAlpha;
}
}
}
}
}
void MacOSXGraphics::drawBitmap( const GenericBitmap &rBitmap,
int xSrc, int ySrc,
int xDest, int yDest,
int width, int height,
bool blend )
{
int srcWidth = rBitmap.getWidth();
int srcHeight = rBitmap.getHeight();
if( width == -1 )
width = srcWidth;
if( height == -1 )
height = srcHeight;
if( !checkBoundaries( xSrc, ySrc, srcWidth, srcHeight,
xDest, yDest, width, height ) )
return;
// Get bitmap data
uint8_t *pBmpData = rBitmap.getData();
if( !pBmpData )
return;
int bmpBytesPerRow = srcWidth * 4;
// Copy/blend pixel data
for( int y = 0; y < height; y++ )
{
for( int x = 0; x < width; x++ )
{
int srcOffset = (ySrc + y) * bmpBytesPerRow + (xSrc + x) * 4;
int dstOffset = (yDest + y) * m_bytesPerRow + (xDest + x) * 4;
uint8_t srcAlpha = pBmpData[srcOffset + 3];
if( !blend || srcAlpha == 255 )
{
// Direct copy
m_pData[dstOffset + 0] = pBmpData[srcOffset + 0]; // B
m_pData[dstOffset + 1] = pBmpData[srcOffset + 1]; // G
m_pData[dstOffset + 2] = pBmpData[srcOffset + 2]; // R
m_pData[dstOffset + 3] = srcAlpha;
}
else if( srcAlpha > 0 )
{
// Alpha blend
uint8_t dstAlpha = m_pData[dstOffset + 3];
uint8_t outAlpha = srcAlpha + (dstAlpha * (255 - srcAlpha)) / 255;
if( outAlpha > 0 )
{
for( int c = 0; c < 3; c++ )
{
m_pData[dstOffset + c] = (uint8_t)(
(pBmpData[srcOffset + c] * srcAlpha +
m_pData[dstOffset + c] * dstAlpha * (255 - srcAlpha) / 255) / outAlpha
);
}
m_pData[dstOffset + 3] = outAlpha;
}
}
}
}
}
void MacOSXGraphics::fillRect( int left, int top, int width, int height,
uint32_t color )
{
// Clamp to valid range
if( left < 0 )
{
width += left;
left = 0;
}
if( top < 0 )
{
height += top;
top = 0;
}
if( left + width > m_width )
width = m_width - left;
if( top + height > m_height )
height = m_height - top;
if( width <= 0 || height <= 0 )
return;
// Extract color components (color is #RRGGBB)
uint8_t r = (color >> 16) & 0xFF;
uint8_t g = (color >> 8) & 0xFF;
uint8_t b = color & 0xFF;
// Fill the rectangle
for( int y = top; y < top + height; y++ )
{
for( int x = left; x < left + width; x++ )
{
int offset = y * m_bytesPerRow + x * 4;
m_pData[offset + 0] = b;
m_pData[offset + 1] = g;
m_pData[offset + 2] = r;
m_pData[offset + 3] = 255;
}
}
}
void MacOSXGraphics::drawRect( int left, int top, int width, int height,
uint32_t color )
{
// Extract color components
uint8_t r = (color >> 16) & 0xFF;
uint8_t g = (color >> 8) & 0xFF;
uint8_t b = color & 0xFF;
// Draw the rectangle outline
// Top and bottom edges
for( int x = left; x < left + width && x < m_width; x++ )
{
if( x >= 0 )
{
if( top >= 0 && top < m_height )
{
int offset = top * m_bytesPerRow + x * 4;
m_pData[offset + 0] = b;
m_pData[offset + 1] = g;
m_pData[offset + 2] = r;
m_pData[offset + 3] = 255;
}
if( top + height - 1 >= 0 && top + height - 1 < m_height )
{
int offset = (top + height - 1) * m_bytesPerRow + x * 4;
m_pData[offset + 0] = b;
m_pData[offset + 1] = g;
m_pData[offset + 2] = r;
m_pData[offset + 3] = 255;
}
}
}
// Left and right edges
for( int y = top; y < top + height && y < m_height; y++ )
{
if( y >= 0 )
{
if( left >= 0 && left < m_width )
{
int offset = y * m_bytesPerRow + left * 4;
m_pData[offset + 0] = b;
m_pData[offset + 1] = g;
m_pData[offset + 2] = r;
m_pData[offset + 3] = 255;
}
if( left + width - 1 >= 0 && left + width - 1 < m_width )
{
int offset = y * m_bytesPerRow + (left + width - 1) * 4;
m_pData[offset + 0] = b;
m_pData[offset + 1] = g;
m_pData[offset + 2] = r;
m_pData[offset + 3] = 255;
}
}
}
}
void MacOSXGraphics::applyMaskToWindow( OSWindow &rWindow )
{
@autoreleasepool {
MacOSXWindow &rMacWindow = static_cast<MacOSXWindow&>(rWindow);
NSWindow<VLCHitTestGraphics> *nsWindow = (NSWindow<VLCHitTestGraphics> *)rMacWindow.getNSWindow();
if( nsWindow && [nsWindow respondsToSelector:@selector(setHitTestGraphics:)] )
{
[nsWindow setHitTestGraphics:this];
}
}
}
void MacOSXGraphics::copyToWindow( OSWindow &rWindow, int xSrc, int ySrc,
int width, int height,
int xDest, int yDest )
{
MacOSXWindow &rMacWindow = static_cast<MacOSXWindow&>(rWindow);
NSWindow *nsWindow = rMacWindow.getNSWindow();
if( !nsWindow )
return;
// Create CGImage from our pixel data (non-premultiplied alpha)
CGDataProviderRef provider = CGDataProviderCreateWithData(
NULL, m_pData, m_bytesPerRow * m_height, NULL );
CGImageRef image = CGImageCreate(
m_width, m_height, 8, 32, m_bytesPerRow, m_colorSpace,
kCGImageAlphaFirst | kCGBitmapByteOrder32Little,
provider, NULL, false, kCGRenderingIntentDefault );
CGDataProviderRelease( provider );
if( !image )
return;
// Create subimage if needed
CGImageRef subImage = NULL;
if( xSrc != 0 || ySrc != 0 || width != m_width || height != m_height )
{
CGRect subRect = CGRectMake( xSrc, ySrc, width, height );
subImage = CGImageCreateWithImageInRect( image, subRect );
}
CGImageRef displayImage = subImage ? subImage : image;
CGImageRetain( displayImage );
if( subImage )
CGImageRelease( subImage );
CGImageRelease( image );
void (^updateBlock)(void) = ^{
@autoreleasepool {
NSView *contentView = [nsWindow contentView];
if( [contentView isKindOfClass:[NSImageView class]] )
{
NSImage *nsImage = [[NSImage alloc] initWithCGImage:displayImage
size:NSMakeSize(width, height)];
[(NSImageView *)contentView setImage:nsImage];
[contentView displayIfNeeded];
}
CGImageRelease( displayImage );
}
};
if( [NSThread isMainThread] )
updateBlock();
else
dispatch_async(dispatch_get_main_queue(), updateBlock);
}
bool MacOSXGraphics::hit( int x, int y ) const
{
if( x < 0 || y < 0 || x >= m_width || y >= m_height )
return false;
// Check if the pixel has non-zero alpha
int offset = y * m_bytesPerRow + x * 4;
return m_pData[offset + 3] > 0;
}
CGImageRef MacOSXGraphics::getImage() const
{
@autoreleasepool {
CGDataProviderRef provider = CGDataProviderCreateWithData(
NULL, m_pData, m_bytesPerRow * m_height, NULL );
CGImageRef image = CGImageCreate(
m_width, m_height, 8, 32, m_bytesPerRow, m_colorSpace,
kCGImageAlphaFirst | kCGBitmapByteOrder32Little,
provider, NULL, false, kCGRenderingIntentDefault );
CGDataProviderRelease( provider );
return image;
}
}
bool MacOSXGraphics::checkBoundaries( int& x_src, int& y_src, int w_src, int h_src,
int& x_target, int& y_target,
int& w_target, int& h_target )
{
// Check for valid source
if( x_src < 0 || y_src < 0 )
return false;
// Adjust for source boundaries
if( x_src + w_target > w_src )
w_target = w_src - x_src;
if( y_src + h_target > h_src )
h_target = h_src - y_src;
// Adjust for negative destination (advance source accordingly)
if( x_target < 0 )
{
w_target += x_target;
x_src -= x_target;
x_target = 0;
}
if( y_target < 0 )
{
h_target += y_target;
y_src -= y_target;
y_target = 0;
}
// Adjust for destination boundaries
if( x_target + w_target > m_width )
w_target = m_width - x_target;
if( y_target + h_target > m_height )
h_target = m_height - y_target;
return w_target > 0 && h_target > 0;
}
[Dauer der Verarbeitung: 0.3 Sekunden, vorverarbeitet 2026-10-24]
|
2026-11-04
|
|
|
|
|
Neuigkeiten |
| Aktuelles |
| Motto des Tages |
|
Open Source Software |
|
|
|
Jenseits des Üblichen ....
|
|
Besucherstatistik |
|
|
| Statistik |
| #Sources=1104857 |
| #Domains=438735 |
|
|