📄 blt.c
字号:
yDMajor = yDMinor - 2 * yDMajor;
yAccum = yShrink ? (2 * Height - SourceHeight) : (3 * SourceHeight - 2 * Height);
}
}
// Clipping. We only clip against a single rectangle
if (Parameters->ClipRect) {
memcpy(&ClippedDestRect, DestRect, sizeof(RECT));
if (ClippedDestRect.left < Parameters->ClipRect->left) {
ClippedDestRect.left = Parameters->ClipRect->left;
}
if (ClippedDestRect.top < Parameters->ClipRect->top) {
ClippedDestRect.top = Parameters->ClipRect->top;
}
if (ClippedDestRect.bottom > Parameters->ClipRect->bottom) {
ClippedDestRect.bottom = Parameters->ClipRect->bottom;
}
if (ClippedDestRect.right > Parameters->ClipRect->right) {
ClippedDestRect.right = Parameters->ClipRect->right;
}
if (ClippedDestRect.right <= ClippedDestRect.left ||
ClippedDestRect.bottom <= ClippedDestRect.top) {
// We've clipped our destination completely away. Consequently, we're
// done.
return TRUE;
}
DestXStartSkip = DestXPositive ? (ClippedDestRect.left - DestRect->left) : (DestRect->right - ClippedDestRect.right);
DestYStartSkip = DestYPositive ? (ClippedDestRect.top - DestRect->top) : (DestRect->bottom - ClippedDestRect.bottom);
Width = RectWidth(&ClippedDestRect);
Height = RectHeight(&ClippedDestRect);
}
// Finish preparing the stretching parameters in light of the clipping
// rectangle.
if (Parameters->Source) {
if (xShrink) {
while (RowXAccum < 0) {
RowXAccum += xDMinor;
SourceXStartSkip++;
}
RowXAccum += xDMajor;
}
for (SkipCount = DestXStartSkip; SkipCount != 0; SkipCount--) {
if (xShrink) {
while (RowXAccum < 0) {
RowXAccum += xDMinor;
SourceXStartSkip++;
}
// This is the Source Skip inherent with a Destination Skip.
SourceXStartSkip++;
RowXAccum += xDMajor;
}
else if (xStretch) {
if (RowXAccum < 0) RowXAccum += xDMinor;
else {
RowXAccum += xDMajor;
SourceXStartSkip++;
}
}
else SourceXStartSkip++;
}
if (yShrink) {
yAccum += DestYStartSkip * yDMajor;
// This is the Source Skip inherent with a Destination Skip.
SourceYStartSkip += DestYStartSkip;
}
else if (yStretch) {
for (SkipCount = DestYStartSkip; SkipCount != 0; SkipCount--) {
if (yAccum < 0) yAccum += yDMinor;
else {
yAccum += yDMajor;
SourceYStartSkip++;
}
}
}
else SourceYStartSkip += DestYStartSkip;
}
if (Parameters->ColorKeyType == NoColorKey) {
DoSourceColorKey = FALSE;
DoDestColorKey = FALSE;
}
else {
DoSourceColorKey = (BOOL)(Parameters->ColorKeyType == SourceColorKey ||
Parameters->ColorKeyType == SourceAndDestColorKey);
DoDestColorKey = (BOOL)(Parameters->ColorKeyType == DestColorKey ||
Parameters->ColorKeyType == SourceAndDestColorKey);
if (DoSourceColorKey) {
if (Parameters->SourceColorKey->LowValue ==
Parameters->SourceColorKey->HighValue) {
SourceColorKeyValue = Parameters->SourceColorKey->LowValue;
}
else {
// We only support a single key, not color spaces...
return FALSE;
}
}
if (DoDestColorKey) {
if (Parameters->DestColorKey->LowValue ==
Parameters->DestColorKey->HighValue) {
DestColorKeyValue = Parameters->DestColorKey->LowValue;
}
else {
// We only support a single key, not color spaces...
return FALSE;
}
}
}
if (Parameters->Brush) {
// Calculate an rclBrush so that the correct starting pixel is chosen
// for the brush iterator.
BrushTopIndent = (Parameters->BrushOrigin) ? (Parameters->Brush->Size.cy - Parameters->BrushOrigin->y) : 0;
BrushLeftIndent = (Parameters->BrushOrigin) ? (Parameters->Brush->Size.cx - Parameters->BrushOrigin->x) : 0;
BrushRect.left = (BrushLeftIndent + DestRect->left) % Parameters->Brush->Size.cx;
BrushRect.right = (BrushRect.left + Parameters->Brush->Size.cx - 1) % Parameters->Brush->Size.cx;
BrushRect.top = (BrushTopIndent + DestRect->top) % Parameters->Brush->Size.cy;
BrushRect.bottom = (BrushRect.top + Parameters->Brush->Size.cy - 1 ) % Parameters->Brush->Size.cy;
}
Source.Ptr = Source.RowPtr =
Mask.Ptr = Mask.RowPtr =
Brush.Ptr = Brush.RowPtr = NULL;
if (Parameters->Source) {
InitPixelBuffer(&Source,
Parameters->Source,
Parameters->ScanXPositive,
Parameters->ScanYPositive,
Parameters->SourceRect,
SourceXStartSkip,
SourceYStartSkip);
// Check for color conversion.
DoColorConvert = !IsSameFormat(Parameters->Source->Format,
Parameters->Destination->Format);
if (DoColorConvert) {
InitColorConverter(Parameters->Source->Format,
Parameters->Destination->Format);
}
}
if (Parameters->Brush) {
InitBrushPixelBuffer(&Brush,
Parameters->Brush,
Parameters->ScanXPositive,
Parameters->ScanYPositive,
&BrushRect);
}
if ((MaskedRop3 != UnmaskedRop3) && (Parameters->Mask == NULL)) {
// ROP indicates we need a mask, but we don't have one.
return FALSE;
}
if (Parameters->Mask) {
InitPixelBuffer(&Mask,
Parameters->Mask,
Parameters->ScanXPositive,
Parameters->ScanYPositive,
Parameters->MaskRect,
SourceXStartSkip,
SourceYStartSkip);
}
else Mask.RowIncrement = 0;
if ((Dest.Bpp = Parameters->Destination->Format->BitsPerPixel) >= 8) {
QuickWrite = TRUE;
if (!DestYPositive) {
Dest.RowIncrement = -Parameters->Destination->Stride;
Dest.RowPtr = (BYTE *)Parameters->Destination->Ptr + Parameters->Destination->Stride * (DestRect->bottom - 1 - DestYStartSkip);
}
else {
Dest.RowIncrement = Parameters->Destination->Stride;
Dest.RowPtr = (BYTE *)Parameters->Destination->Ptr + Parameters->Destination->Stride * (DestYStartSkip + DestRect->top);
}
if (!DestXPositive) {
Dest.BytesPerAccess = -(LONG)(Dest.Bpp / 8);
Dest.RowPtr -= Dest.BytesPerAccess * (DestRect->right - 1 - DestXStartSkip);
}
else {
Dest.BytesPerAccess = Dest.Bpp / 8;
Dest.RowPtr += Dest.BytesPerAccess * (DestXStartSkip + DestRect->left);
}
Dest.Mask = (2 << (Dest.Bpp - 1)) - 1;
Dest.CacheState = 0;
}
else {
InitPixelBuffer(&Dest,
Parameters->Destination,
DestXPositive,
DestYPositive,
DestRect,
DestXStartSkip,
DestYStartSkip);
}
if (yShrinkStretch) {
// Back up the source and mask row increments because they will be
// altered dynamically.
OriginalMaskRowInc = Mask.RowIncrement;
OriginalSrcRowInc = Source.RowIncrement;
}
if (Parameters->Rop == 0x0000) {
Source.Value = 0;
}
else if (Parameters->Rop == 0xffff) {
Source.Value = Dest.Mask;
}
else {
Source.Value = Parameters->FillValue & Dest.Mask;
if ((MaskedRop3 != UnmaskedRop3) ||
DoSourceColorKey ||
DoDestColorKey ||
xShrinkStretch ||
(Rop3 != 0xCC && (Rop3 != 0xF0 || Parameters->Brush))) {
ComplexBlt = TRUE;
}
}
Brush.Value = Source.Value;
while (Height--) {
// Handle y Shrinking or stretching.
if (yShrinkStretch) {
if (yShrink) {
// Skip source line(s) if shrinking.
while (yAccum < 0) {
Source.RowPtr += Source.RowIncrement;
Mask.RowPtr += Mask.RowIncrement;
yAccum += yDMinor;
}
yAccum += yDMajor;
}
else {
if (yAccum < 0) {
// Repeat source line if stretching.
// yDMinor is a small +ve number.
yAccum += yDMinor;
if (yStretch) {
Source.RowIncrement = 0;
Mask.RowIncrement = 0;
}
}
else {
// Switch to next source line (after this row)
// yDMajor is a large -ve value (i.e. |yDMajor| > |yDMinor| )
yAccum += yDMajor;
Source.RowIncrement = OriginalSrcRowInc;
Mask.RowIncrement = OriginalMaskRowInc;
}
}
}
// Move all buffers to next line.
if (Source.RowPtr) {
Source.Ptr = Source.RowPtr;
Source.RowPtr += Source.RowIncrement;
if (!Source.Is24Bit) {
Source.Cache = *(ULONG *)Source.Ptr;
Source.CacheState = Source.CacheStateNewRow;
}
}
if (Mask.RowPtr) {
Mask.Ptr = Mask.RowPtr;
Mask.RowPtr += Mask.RowIncrement;
Mask.Cache = *(UNALIGNED ULONG *)Mask.Ptr;
Mask.CacheState = Mask.CacheStateNewRow;
}
if (Brush.RowPtr) {
Brush.Ptr = Brush.RowPtr;
Brush.LeftRowPtr = Brush.Ptr - (Brush.FirstRowPtr - (BYTE *)(Parameters->Brush->Ptr));
if (--Brush.RowsRemaining) {
Brush.RowPtr += Brush.RowIncrement;
}
else {
Brush.RowPtr = Brush.FirstRowPtr;
Brush.RowsRemaining = Brush.Rows;
}
Brush.Cache = *(ULONG *)Brush.Ptr;
Brush.CacheState = Brush.CacheStateNewRow;
Brush.PixelsRemaining = Brush.RowInitialPixelsRemaining;
}
Dest.Ptr = Dest.RowPtr;
Dest.RowPtr += Dest.RowIncrement;
if (!QuickWrite) {
Dest.Cache = *(ULONG *)Dest.Ptr;
Dest.CacheState = Dest.CacheStateNewRow;
}
if (xStretch) {
PrevMaskPtr = Mask.Ptr;
PrevMaskCache = Mask.Cache;
PrevMaskCacheState = Mask.CacheState;
PrevSrcPtr = Source.Ptr;
PrevSrcCache = Source.Cache;
PrevSrcCacheState = Source.CacheState;
}
xAccum = RowXAccum;
for (x = 0; x < Width; x++) {
if (Source.Ptr) {
// Read the next pixel in and convert to same depth as destination.
if (Source.Is24Bit) {
// Since 24-bit packed pixels cross dword boundaries:
Source.Value = (*(Source.Ptr + 2) << 16) + (*(Source.Ptr + 1) << 8) + *(Source.Ptr);
Source.Ptr += Source.BytesPerAccess;
}
else {
// Check bits remaining in src.Cache.
if (!(Source.CacheState & 0x00ff00)) {
Source.Ptr += Source.BytesPerAccess;
Source.CacheState = Source.CacheStateNewDWord;
Source.Cache = *(ULONG *)Source.Ptr;
}
Source.Value = Source.Cache >> ((Source.CacheState >> 16) ^ Source.MaskShiftXor);
Source.CacheState += Source.CacheStateIncrement;
}
OriginalSrc = (Source.Value &= Source.Mask);
if (DoColorConvert) {
Source.Value = ColorConvert(Source.Value);
}
}
if (ComplexBlt) { // Brush, masked, color key, unusual rop3, etc...
if (Brush.Ptr) {
// Note that the brush should have already been converted to the same
// depth as the destination (if they weren't the same).
// Check for wrapping off right edge of pattern
if (!(Brush.PixelsRemaining--)) {
Brush.Ptr = Brush.LeftRowPtr;
Brush.PixelsRemaining = Brush.PixelsPerRow - 1;
Brush.CacheState = Brush.CacheStateNewDWord;
Brush.Cache = *(ULONG *)Brush.Ptr;
}
// Check bits remaining in brush.Cache
else if (!(Brush.CacheState & 0x00ff00)) {
Brush.Ptr += Brush.BytesPerAccess;
Brush.CacheState = Brush.CacheStateNewDWord;
Brush.Cache = *(ULONG *)Brush.Ptr;
}
Brush.Value = Brush.Cache >> ((Brush.CacheState >> 16) ^ Brush.MaskShiftXor);
Brush.CacheState += Brush.CacheStateIncrement;
}
// Use the mask to select between two ROPs.
if (Mask.Ptr) {
// Check bits remaining in mask cache
if (!(Mask.CacheState & 0x00ff00)) {
Mask.Ptr += Mask.BytesPerAccess; // == +/- 4
Mask.CacheState = Mask.CacheStateNewDWord;
Mask.Cache = *(UNALIGNED ULONG *)Mask.Ptr;
}
Rop3 = (Mask.Cache & (1 << ((Mask.CacheState >> 16) ^ Mask.MaskShiftXor))) ? UnmaskedRop3 : MaskedRop3;
Mask.CacheState += Mask.CacheStateIncrement;
}
if (xShrinkStretch) {
// Handle x Stretching.
if (xStretch) {
if (xAccum < 0) { // Repeat this pixel
xAccum += xDMinor;
Mask.Ptr = PrevMaskPtr;
Mask.Cache = PrevMaskCache;
Mask.CacheState = PrevMaskCacheState;
Source.Ptr = PrevSrcPtr;
Source.Cache = PrevSrcCache;
Source.CacheState = PrevSrcCacheState;
}
else { // OK to move to next source pixel after this
xAccum += xDMajor;
PrevMaskPtr = Mask.Ptr;
PrevMaskCache = Mask.Cache;
PrevMaskCacheState = Mask.CacheState;
PrevSrcPtr = Source.Ptr;
PrevSrcCache = Source.Cache;
PrevSrcCacheState = Source.CacheState;
}
}
else { // xShrink
while (xAccum < 0) { // Skip pixel(s)
// Move to next Source pixel.
if (Source.Is24Bit) {
// Since 24-bit packed pixels cross dword boundaries:
Source.Ptr += Source.BytesPerAccess;
}
else {
// Check bits remaining in src.Cache.
if (!(Source.CacheState & 0x00ff00)) {
Source.Ptr += Source.BytesPerAccess;
Source.CacheState = Source.CacheStateNewDWord;
if (x != Width - 1) {
Source.Cache = *(ULONG *)Source.Ptr;
}
}
Source.CacheState += Source.CacheStateIncrement;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -