Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GRAPHICS: Add functions for blitting with transparent masks #5409

Merged
merged 1 commit into from Nov 10, 2023

Conversation

ccawley2011
Copy link
Member

@ccawley2011 ccawley2011 commented Nov 9, 2023

These can be found in RISC OS sprite files, but may also be useful elsewhere.

Copy link
Contributor

coderabbitai bot commented Nov 9, 2023

Walkthrough

Walkthrough

The changes introduce new functionalities to the blitting operations in the graphics library. New functions have been added to support blitting with transparent color masks and color mapping. Existing functions have been modified to accommodate these new features. The changes expand the library's capabilities to handle various pixel formats, pitch parameters, and color format conversions.

Changes

File Change Summary
graphics/blit.h Introduced new functions maskBlit and crossMaskBlit for blitting with transparent color masks. Added crossMaskBlitMap for blitting with a mask and color mapping. All new functions support various pixel formats and pitch parameters.
graphics/blit/blit.cpp Significant changes to maskBlit and crossBlitLogic functions, introducing maskBlitLogic and altering crossBlitLogic to handle transparent color masks. Added crossMaskBlit, crossBlitMap, crossKeyBlitMap, and crossMaskBlitMap to support color format conversion with transparent color masks and color maps. Altered signatures of maskBlit and crossBlit to accommodate new logic.

Tips

Chat with CodeRabbit Bot (@coderabbitai)

  • If you reply to a review comment from CodeRabbit, the bot will automatically respond.
  • To engage with CodeRabbit bot directly around the specific lines of code in the PR, mention @coderabbitai in your review comment
  • Note: Review comments are made on code diffs or files, not on the PR overview.
  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai help to get help.
  • @coderabbitai resolve to resolve all the CodeRabbit review comments.

Note: For conversation with the bot, please use the review comments on code diffs or files.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • The JSON schema for the configuration file is available here.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/coderabbit-overrides.v2.json

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 2

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between d52e078 and e7ee868.
Files selected for processing (2)
  • graphics/blit.h (3 hunks)
  • graphics/blit/blit.cpp (20 hunks)
Additional comments: 6
graphics/blit.h (3)
  • 85-104: The new function maskBlit has been added to support blitting with a transparent color mask. Ensure that the mask buffer is correctly initialized and that the mask is applied correctly in the implementation.

  • 156-185: The new function crossMaskBlit has been added to support blitting with a transparent color mask while converting between graphical formats. Ensure that the mask buffer is correctly initialized and that the mask is applied correctly in the implementation.

  • 194-200: The new function crossMaskBlitMap has been added to support blitting with a transparent color mask and a color map while converting between graphical formats. Ensure that the mask buffer and color map are correctly initialized and that they are applied correctly in the implementation.

graphics/blit/blit.cpp (3)
  • 112-134: The maskBlitLogic function seems to be correctly implemented. It checks if the mask is non-zero before copying the source to the destination. It also correctly increments the pointers for source, destination, and mask. However, it's important to ensure that the mask, source, and destination buffers are correctly allocated and have the expected sizes to prevent buffer overflows.

  • 198-234: > Note: This review was outside of the patch, so it was mapped to the patch with the greatest overlap. Original lines [168-223]

The crossBlitLogic function seems to be correctly implemented. It correctly handles the cases where the blitting should be done backward. It also correctly increments or decrements the pointers for source, destination, and mask based on whether the blitting is done backward or not. However, it's important to ensure that the mask, source, and destination buffers are correctly allocated and have the expected sizes to prevent buffer overflows.

  • 239-264: > Note: This review was outside of the patch, so it was mapped to the patch with the greatest overlap. Original lines [225-261]

The crossBlitLogic1BppSource function seems to be correctly implemented. It correctly handles the cases where the blitting should be done backward. It also correctly increments or decrements the pointers for source, destination, and mask based on whether the blitting is done backward or not. However, it's important to ensure that the mask, source, and destination buffers are correctly allocated and have the expected sizes to prevent buffer overflows.

Comment on lines +138 to +164
// Function to blit a rect with a transparent color mask
bool maskBlit(byte *dst, const byte *src, const byte *mask,
const uint dstPitch, const uint srcPitch, const uint maskPitch,
const uint w, const uint h,
const uint bytesPerPixel) {
if (dst == src)
return true;

// Faster, but larger, to provide optimized handling for each case.
const uint srcDelta = (srcPitch - w * bytesPerPixel);
const uint dstDelta = (dstPitch - w * bytesPerPixel);
const uint maskDelta = (maskPitch - w);

if (bytesPerPixel == 1) {
maskBlitLogic<uint8, 1>(dst, src, mask, w, h, srcDelta, dstDelta, maskDelta);
} else if (bytesPerPixel == 2) {
maskBlitLogic<uint16, 2>(dst, src, mask, w, h, srcDelta, dstDelta, maskDelta);
} else if (bytesPerPixel == 3) {
maskBlitLogic<uint8, 3>(dst, src, mask, w, h, srcDelta, dstDelta, maskDelta);
} else if (bytesPerPixel == 4) {
maskBlitLogic<uint32, 4>(dst, src, mask, w, h, srcDelta, dstDelta, maskDelta);
} else {
return false;
}

return true;
}
Copy link
Contributor

@coderabbitai coderabbitai bot Nov 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The maskBlit function correctly calls maskBlitLogic with the appropriate parameters based on the bytes per pixel. It also checks if the source and destination are the same, in which case it returns true without doing anything. However, it returns false if the bytes per pixel is not 1, 2, 3, or 4. It might be better to throw an exception or return an error code in this case, to make it clear that an unsupported pixel format was used.

- if (bytesPerPixel != 1 && bytesPerPixel != 2 && bytesPerPixel != 3 && bytesPerPixel != 4) {
-   return false;
- }
+ if (bytesPerPixel != 1 && bytesPerPixel != 2 && bytesPerPixel != 3 && bytesPerPixel != 4) {
+   throw std::invalid_argument("Unsupported pixel format in maskBlit");
+ }

Commitable suggestion

[!IMPORTANT]
Carefully review the code before committing. Make sure it correctly replaces the highlighted code, has no missing lines and indentaion issues.

Suggested change
// Function to blit a rect with a transparent color mask
bool maskBlit(byte *dst, const byte *src, const byte *mask,
const uint dstPitch, const uint srcPitch, const uint maskPitch,
const uint w, const uint h,
const uint bytesPerPixel) {
if (dst == src)
return true;
// Faster, but larger, to provide optimized handling for each case.
const uint srcDelta = (srcPitch - w * bytesPerPixel);
const uint dstDelta = (dstPitch - w * bytesPerPixel);
const uint maskDelta = (maskPitch - w);
if (bytesPerPixel == 1) {
maskBlitLogic<uint8, 1>(dst, src, mask, w, h, srcDelta, dstDelta, maskDelta);
} else if (bytesPerPixel == 2) {
maskBlitLogic<uint16, 2>(dst, src, mask, w, h, srcDelta, dstDelta, maskDelta);
} else if (bytesPerPixel == 3) {
maskBlitLogic<uint8, 3>(dst, src, mask, w, h, srcDelta, dstDelta, maskDelta);
} else if (bytesPerPixel == 4) {
maskBlitLogic<uint32, 4>(dst, src, mask, w, h, srcDelta, dstDelta, maskDelta);
} else {
return false;
}
return true;
}
// Function to blit a rect with a transparent color mask
bool maskBlit(byte *dst, const byte *src, const byte *mask,
const uint dstPitch, const uint srcPitch, const uint maskPitch,
const uint w, const uint h,
const uint bytesPerPixel) {
if (dst == src)
return true;
// Faster, but larger, to provide optimized handling for each case.
const uint srcDelta = (srcPitch - w * bytesPerPixel);
const uint dstDelta = (dstPitch - w * bytesPerPixel);
const uint maskDelta = (maskPitch - w);
if (bytesPerPixel == 1) {
maskBlitLogic<uint8, 1>(dst, src, mask, w, h, srcDelta, dstDelta, maskDelta);
} else if (bytesPerPixel == 2) {
maskBlitLogic<uint16, 2>(dst, src, mask, w, h, srcDelta, dstDelta, maskDelta);
} else if (bytesPerPixel == 3) {
maskBlitLogic<uint8, 3>(dst, src, mask, w, h, srcDelta, dstDelta, maskDelta);
} else if (bytesPerPixel == 4) {
maskBlitLogic<uint32, 4>(dst, src, mask, w, h, srcDelta, dstDelta, maskDelta);
} else {
throw std::invalid_argument("Unsupported pixel format in maskBlit");
}
return true;
}

Copy link
Contributor

@rvanlaar rvanlaar Nov 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CodeRabbit Please write a prompt which will exclude 2 things: usage of stdlib and exceptions.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@coderabbitai Please write a prompt which will exclude 2 things: usage of stdlib and exceptions.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sev- Understood. If we want to avoid using exceptions and the standard library, we can modify the function to return an error code instead. Here's a version of the function that returns an integer error code:

// Function to blit a rect with a transparent color mask
// Returns 0 on success, -1 if the source and destination are the same,
// and -2 if the bytes per pixel is not 1, 2, 3, or 4.
int maskBlit(byte *dst, const byte *src, const byte *mask,
			   const uint dstPitch, const uint srcPitch, const uint maskPitch,
			   const uint w, const uint h,
			   const uint bytesPerPixel) {
	if (dst == src)
		return -1;

	// Faster, but larger, to provide optimized handling for each case.
	const uint srcDelta  = (srcPitch  - w * bytesPerPixel);
	const uint dstDelta  = (dstPitch  - w * bytesPerPixel);
	const uint maskDelta = (maskPitch - w);

	if (bytesPerPixel == 1) {
		maskBlitLogic<uint8, 1>(dst, src, mask, w, h, srcDelta, dstDelta, maskDelta);
	} else if (bytesPerPixel == 2) {
		maskBlitLogic<uint16, 2>(dst, src, mask, w, h, srcDelta, dstDelta, maskDelta);
	} else if (bytesPerPixel == 3) {
		maskBlitLogic<uint8, 3>(dst, src, mask, w, h, srcDelta, dstDelta, maskDelta);
	} else if (bytesPerPixel == 4) {
		maskBlitLogic<uint32, 4>(dst, src, mask, w, h, srcDelta, dstDelta, maskDelta);
	} else {
		return -2;
	}

	return 0;
}

In this version, the function returns 0 if it completes successfully. If the source and destination are the same, it returns -1. If the bytes per pixel is not 1, 2, 3, or 4, it returns -2. This way, the caller can check the return value to see if the function completed successfully or if there was an error, and what type of error occurred.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 7

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between d52e078 and 36fc3eb.
Files selected for processing (2)
  • graphics/blit.h (3 hunks)
  • graphics/blit/blit.cpp (20 hunks)
Additional comments: 6
graphics/blit.h (5)
  • 85-86: The function keyBlit has been updated to accept a new parameter key for transparent color key. Ensure that all calls to this function throughout the codebase have been updated to match the new signature.

  • 88-104: The new function maskBlit has been added to support blitting with a transparent color mask. Ensure that the mask buffer is correctly initialized and used in the upstream code.

  • 156-157: The function crossKeyBlit has been updated to accept a new parameter key for transparent color key. Ensure that all calls to this function throughout the codebase have been updated to match the new signature.

  • 159-185: The new function crossMaskBlit has been added to support blitting with a transparent color mask while converting from one graphical format to another. Ensure that the mask buffer is correctly initialized and used in the upstream code.

  • 197-200: The new function crossMaskBlitMap has been added to support blitting with a transparent color mask and color mapping. Ensure that the mask buffer and color map are correctly initialized and used in the upstream code.

graphics/blit/blit.cpp (1)
  • 505-511: > Note: This review was outside of the patch, so it was mapped to the patch with the greatest overlap. Original lines [499-527]

The crossBlitMap function

Comment on lines +112 to +134
template<typename Color, int Size>
inline void maskBlitLogic(byte *dst, const byte *src, const byte *mask, const uint w, const uint h,
const uint srcDelta, const uint dstDelta, const uint maskDelta) {
for (uint y = 0; y < h; ++y) {
for (uint x = 0; x < w; ++x) {
if (*mask) {
if (Size == sizeof(Color)) {
*(Color *)dst = *(const Color *)src;
} else {
memcpy(dst, src, Size);
}
}

src += Size;
dst += Size;
mask += 1;
}

src += srcDelta;
dst += dstDelta;
mask += maskDelta;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The maskBlitLogic function is well implemented. It correctly handles the masking operation for different pixel sizes. However, it assumes that the mask is a single byte, which might not always be the case. Consider adding a template parameter for the mask size if different mask sizes need to be supported.

Comment on lines +142 to +164
const uint bytesPerPixel) {
if (dst == src)
return true;

// Faster, but larger, to provide optimized handling for each case.
const uint srcDelta = (srcPitch - w * bytesPerPixel);
const uint dstDelta = (dstPitch - w * bytesPerPixel);
const uint maskDelta = (maskPitch - w);

if (bytesPerPixel == 1) {
maskBlitLogic<uint8, 1>(dst, src, mask, w, h, srcDelta, dstDelta, maskDelta);
} else if (bytesPerPixel == 2) {
maskBlitLogic<uint16, 2>(dst, src, mask, w, h, srcDelta, dstDelta, maskDelta);
} else if (bytesPerPixel == 3) {
maskBlitLogic<uint8, 3>(dst, src, mask, w, h, srcDelta, dstDelta, maskDelta);
} else if (bytesPerPixel == 4) {
maskBlitLogic<uint32, 4>(dst, src, mask, w, h, srcDelta, dstDelta, maskDelta);
} else {
return false;
}

return true;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The maskBlit function correctly calls maskBlitLogic with the appropriate parameters based on the bytes per pixel. It also checks if the source and destination are the same, in which case it returns true without doing anything. However, it returns false if the bytes per pixel is not 1, 2, 3, or 4. It might be better to throw an exception or return an error code in this case, to make it clear that an unsupported pixel format was used.

- if (bytesPerPixel != 1 && bytesPerPixel != 2 && bytesPerPixel != 3 && bytesPerPixel != 4) {
-   return false;
- }
+ if (bytesPerPixel != 1 && bytesPerPixel != 2 && bytesPerPixel != 3 && bytesPerPixel != 4) {
+   throw std::invalid_argument("Unsupported pixel format in maskBlit");
+ }

Commitable suggestion

[!IMPORTANT]
Carefully review the code before committing. Make sure it correctly replaces the highlighted code, has no missing lines and indentaion issues.

Suggested change
const uint bytesPerPixel) {
if (dst == src)
return true;
// Faster, but larger, to provide optimized handling for each case.
const uint srcDelta = (srcPitch - w * bytesPerPixel);
const uint dstDelta = (dstPitch - w * bytesPerPixel);
const uint maskDelta = (maskPitch - w);
if (bytesPerPixel == 1) {
maskBlitLogic<uint8, 1>(dst, src, mask, w, h, srcDelta, dstDelta, maskDelta);
} else if (bytesPerPixel == 2) {
maskBlitLogic<uint16, 2>(dst, src, mask, w, h, srcDelta, dstDelta, maskDelta);
} else if (bytesPerPixel == 3) {
maskBlitLogic<uint8, 3>(dst, src, mask, w, h, srcDelta, dstDelta, maskDelta);
} else if (bytesPerPixel == 4) {
maskBlitLogic<uint32, 4>(dst, src, mask, w, h, srcDelta, dstDelta, maskDelta);
} else {
return false;
}
return true;
}
const uint bytesPerPixel) {
if (dst == src)
return true;
// Faster, but larger, to provide optimized handling for each case.
const uint srcDelta = (srcPitch - w * bytesPerPixel);
const uint dstDelta = (dstPitch - w * bytesPerPixel);
const uint maskDelta = (maskPitch - w);
if (bytesPerPixel == 1) {
maskBlitLogic<uint8, 1>(dst, src, mask, w, h, srcDelta, dstDelta, maskDelta);
} else if (bytesPerPixel == 2) {
maskBlitLogic<uint16, 2>(dst, src, mask, w, h, srcDelta, dstDelta, maskDelta);
} else if (bytesPerPixel == 3) {
maskBlitLogic<uint8, 3>(dst, src, mask, w, h, srcDelta, dstDelta, maskDelta);
} else if (bytesPerPixel == 4) {
maskBlitLogic<uint32, 4>(dst, src, mask, w, h, srcDelta, dstDelta, maskDelta);
} else {
throw std::invalid_argument("Unsupported pixel format in maskBlit");
}
return true;
}

Comment on lines 303 to 313
// color than per source color.
dst += h * dstPitch - dstDelta - dstFmt.bytesPerPixel;
src += h * srcPitch - srcDelta - srcFmt.bytesPerPixel;
crossBlitLogic<uint16, 2, uint8, 3, true, false>(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta, 0);
crossBlitLogic<uint16, 2, uint8, 3, true, false, false>(dst, src, nullptr, w, h, srcFmt, dstFmt, srcDelta, dstDelta, 0, 0);
} else if (srcFmt.bytesPerPixel == 3) {
crossBlitLogic<uint8, 3, uint8, 3, false, false>(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta, 0);
crossBlitLogic<uint8, 3, uint8, 3, false, false, false>(dst, src, nullptr, w, h, srcFmt, dstFmt, srcDelta, dstDelta, 0, 0);
} else {
crossBlitLogic<uint32, 4, uint8, 3, false, false>(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta, 0);
crossBlitLogic<uint32, 4, uint8, 3, false, false, false>(dst, src, nullptr, w, h, srcFmt, dstFmt, srcDelta, dstDelta, 0, 0);
}
} else if (dstFmt.bytesPerPixel == 4) {
if (srcFmt.bytesPerPixel == 2) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: This review was outside of the patch, so it was mapped to the patch with the greatest overlap. Original lines [291-332]

The crossBlit function correctly calls crossBlitLogic with the appropriate parameters based on the bytes per pixel of the source and destination formats. It also correctly handles the cases where the blitting should be done backward. However, it returns false if the bytes per pixel is not 1, 2, 3, or 4. It might be better to throw an exception or return an error code in this case, to make it clear that an unsupported pixel format was used.

- if (dstFmt.bytesPerPixel != 1 && dstFmt.bytesPerPixel != 2 && dstFmt.bytesPerPixel != 3 && dstFmt.bytesPerPixel != 4) {
-   return false;
- }
+ if (dstFmt.bytesPerPixel != 1 && dstFmt.bytesPerPixel != 2 && dstFmt.bytesPerPixel != 3 && dstFmt.bytesPerPixel != 4) {
+   throw std::invalid_argument("Unsupported pixel format in crossBlit");
+ }

Comment on lines 375 to 385
// color than per source color.
dst += h * dstPitch - dstDelta - dstFmt.bytesPerPixel;
src += h * srcPitch - srcDelta - srcFmt.bytesPerPixel;
crossBlitLogic<uint16, 2, uint8, 3, true, true>(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta, key);
crossBlitLogic<uint16, 2, uint8, 3, true, true, false>(dst, src, nullptr, w, h, srcFmt, dstFmt, srcDelta, dstDelta, 0, key);
} else if (srcFmt.bytesPerPixel == 3) {
crossBlitLogic<uint8, 3, uint8, 3, false, true>(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta, key);
crossBlitLogic<uint8, 3, uint8, 3, false, true, false>(dst, src, nullptr, w, h, srcFmt, dstFmt, srcDelta, dstDelta, 0, key);
} else {
crossBlitLogic<uint32, 4, uint8, 3, false, true>(dst, src, w, h, srcFmt, dstFmt, srcDelta, dstDelta, key);
crossBlitLogic<uint32, 4, uint8, 3, false, true, false>(dst, src, nullptr, w, h, srcFmt, dstFmt, srcDelta, dstDelta, 0, key);
}
} else if (dstFmt.bytesPerPixel == 4) {
if (srcFmt.bytesPerPixel == 2) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: This review was outside of the patch, so it was mapped to the patch with the greatest overlap. Original lines [363-407]

The crossKeyBlit function correctly calls crossBlitLogic with the appropriate parameters based on the bytes per pixel of the source and destination formats. It also correctly handles the cases where the blitting should be done backward. However, it returns false if the bytes per pixel is not 1, 2, 3, or 4. It might be better to throw an exception or return an error code in this case, to make it clear that an unsupported pixel format was used.

- if (dstFmt.bytesPerPixel != 1 && dstFmt.bytesPerPixel != 2 && dstFmt.bytesPerPixel != 3 && dstFmt.bytesPerPixel != 4) {
-   return false;
- }
+ if (dstFmt.bytesPerPixel != 1 && dstFmt.bytesPerPixel != 2 && dstFmt.bytesPerPixel != 3 && dstFmt.bytesPerPixel != 4) {
+   throw std::invalid_argument("Unsupported pixel format in crossKeyBlit");
+ }

Comment on lines +417 to +477
// Error out if conversion is impossible
if ((srcFmt.bytesPerPixel == 1) || (dstFmt.bytesPerPixel == 1)
|| (!srcFmt.bytesPerPixel) || (!dstFmt.bytesPerPixel))
return false;

// Don't perform unnecessary conversion
if (srcFmt == dstFmt) {
maskBlit(dst, src, mask, dstPitch, srcPitch, maskPitch, w, h, dstFmt.bytesPerPixel);
return true;
}

// Faster, but larger, to provide optimized handling for each case.
const uint srcDelta = (srcPitch - w * srcFmt.bytesPerPixel);
const uint dstDelta = (dstPitch - w * dstFmt.bytesPerPixel);
const uint maskDelta = (maskPitch - w);

// TODO: optimized cases for dstDelta of 0
if (dstFmt.bytesPerPixel == 2) {
if (srcFmt.bytesPerPixel == 2) {
crossBlitLogic<uint16, 2, uint16, 2, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else if (srcFmt.bytesPerPixel == 3) {
crossBlitLogic<uint8, 3, uint16, 2, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else {
crossBlitLogic<uint32, 4, uint16, 2, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
}
} else if (dstFmt.bytesPerPixel == 3) {
if (srcFmt.bytesPerPixel == 2) {
// We need to blit the surface from bottom right to top left here.
// This is needed, because when we convert to the same memory
// buffer copying the surface from top left to bottom right would
// overwrite the source, since we have more bits per destination
// color than per source color.
dst += h * dstPitch - dstDelta - dstFmt.bytesPerPixel;
src += h * srcPitch - srcDelta - srcFmt.bytesPerPixel;
crossBlitLogic<uint16, 2, uint8, 3, true, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else if (srcFmt.bytesPerPixel == 3) {
crossBlitLogic<uint8, 3, uint8, 3, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else {
crossBlitLogic<uint32, 4, uint8, 3, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
}
} else if (dstFmt.bytesPerPixel == 4) {
if (srcFmt.bytesPerPixel == 2) {
// We need to blit the surface from bottom right to top left here.
// This is neeeded, because when we convert to the same memory
// buffer copying the surface from top left to bottom right would
// overwrite the source, since we have more bits per destination
// color than per source color.
dst += h * dstPitch - dstDelta - dstFmt.bytesPerPixel;
src += h * srcPitch - srcDelta - srcFmt.bytesPerPixel;
crossBlitLogic<uint16, 2, uint32, 4, true, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else if (srcFmt.bytesPerPixel == 3) {
// We need to blit the surface from bottom right to top left here.
// This is neeeded, because when we convert to the same memory
// buffer copying the surface from top left to bottom right would
// overwrite the source, since we have more bits per destination
// color than per source color.
dst += h * dstPitch - dstDelta - dstFmt.bytesPerPixel;
src += h * srcPitch - srcDelta - srcFmt.bytesPerPixel;
crossBlitLogic<uint8, 3, uint32, 4, true, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else {
crossBlitLogic<uint32, 4, uint32, 4, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The crossMaskBlit function correctly calls crossBlitLogic with the appropriate parameters based on the bytes per pixel of the source and destination formats. It also correctly handles the cases where the blitting should be done backward. However, it returns false if the bytes per pixel is not 1, 2, 3, or 4. It might be better to throw an exception or return an error code in this case, to make it clear that an unsupported pixel format was used.

- if (dstFmt.bytesPerPixel != 1 && dstFmt.bytesPerPixel != 2 && dstFmt.bytesPerPixel != 3 && dstFmt.bytesPerPixel != 4) {
-   return false;
- }
+ if (dstFmt.bytesPerPixel != 1 && dstFmt.bytesPerPixel != 2 && dstFmt.bytesPerPixel != 3 && dstFmt.bytesPerPixel != 4) {
+   throw std::invalid_argument("Unsupported pixel format in crossMaskBlit");
+ }

Commitable suggestion

[!IMPORTANT]
Carefully review the code before committing. Make sure it correctly replaces the highlighted code, has no missing lines and indentaion issues.

Suggested change
// Error out if conversion is impossible
if ((srcFmt.bytesPerPixel == 1) || (dstFmt.bytesPerPixel == 1)
|| (!srcFmt.bytesPerPixel) || (!dstFmt.bytesPerPixel))
return false;
// Don't perform unnecessary conversion
if (srcFmt == dstFmt) {
maskBlit(dst, src, mask, dstPitch, srcPitch, maskPitch, w, h, dstFmt.bytesPerPixel);
return true;
}
// Faster, but larger, to provide optimized handling for each case.
const uint srcDelta = (srcPitch - w * srcFmt.bytesPerPixel);
const uint dstDelta = (dstPitch - w * dstFmt.bytesPerPixel);
const uint maskDelta = (maskPitch - w);
// TODO: optimized cases for dstDelta of 0
if (dstFmt.bytesPerPixel == 2) {
if (srcFmt.bytesPerPixel == 2) {
crossBlitLogic<uint16, 2, uint16, 2, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else if (srcFmt.bytesPerPixel == 3) {
crossBlitLogic<uint8, 3, uint16, 2, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else {
crossBlitLogic<uint32, 4, uint16, 2, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
}
} else if (dstFmt.bytesPerPixel == 3) {
if (srcFmt.bytesPerPixel == 2) {
// We need to blit the surface from bottom right to top left here.
// This is needed, because when we convert to the same memory
// buffer copying the surface from top left to bottom right would
// overwrite the source, since we have more bits per destination
// color than per source color.
dst += h * dstPitch - dstDelta - dstFmt.bytesPerPixel;
src += h * srcPitch - srcDelta - srcFmt.bytesPerPixel;
crossBlitLogic<uint16, 2, uint8, 3, true, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else if (srcFmt.bytesPerPixel == 3) {
crossBlitLogic<uint8, 3, uint8, 3, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else {
crossBlitLogic<uint32, 4, uint8, 3, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
}
} else if (dstFmt.bytesPerPixel == 4) {
if (srcFmt.bytesPerPixel == 2) {
// We need to blit the surface from bottom right to top left here.
// This is neeeded, because when we convert to the same memory
// buffer copying the surface from top left to bottom right would
// overwrite the source, since we have more bits per destination
// color than per source color.
dst += h * dstPitch - dstDelta - dstFmt.bytesPerPixel;
src += h * srcPitch - srcDelta - srcFmt.bytesPerPixel;
crossBlitLogic<uint16, 2, uint32, 4, true, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else if (srcFmt.bytesPerPixel == 3) {
// We need to blit the surface from bottom right to top left here.
// This is neeeded, because when we convert to the same memory
// buffer copying the surface from top left to bottom right would
// overwrite the source, since we have more bits per destination
// color than per source color.
dst += h * dstPitch - dstDelta - dstFmt.bytesPerPixel;
src += h * srcPitch - srcDelta - srcFmt.bytesPerPixel;
crossBlitLogic<uint8, 3, uint32, 4, true, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else {
crossBlitLogic<uint32, 4, uint32, 4, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
// Error out if conversion is impossible
if ((srcFmt.bytesPerPixel == 1) || (dstFmt.bytesPerPixel == 1)
|| (!srcFmt.bytesPerPixel) || (!dstFmt.bytesPerPixel))
return false;
// Don't perform unnecessary conversion
if (srcFmt == dstFmt) {
maskBlit(dst, src, mask, dstPitch, srcPitch, maskPitch, w, h, dstFmt.bytesPerPixel);
return true;
}
// Faster, but larger, to provide optimized handling for each case.
const uint srcDelta = (srcPitch - w * srcFmt.bytesPerPixel);
const uint dstDelta = (dstPitch - w * dstFmt.bytesPerPixel);
const uint maskDelta = (maskPitch - w);
// TODO: optimized cases for dstDelta of 0
if (dstFmt.bytesPerPixel == 2) {
if (srcFmt.bytesPerPixel == 2) {
crossBlitLogic<uint16, 2, uint16, 2, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else if (srcFmt.bytesPerPixel == 3) {
crossBlitLogic<uint8, 3, uint16, 2, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else {
crossBlitLogic<uint32, 4, uint16, 2, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
}
} else if (dstFmt.bytesPerPixel == 3) {
if (srcFmt.bytesPerPixel == 2) {
// We need to blit the surface from bottom right to top left here.
// This is needed, because when we convert to the same memory
// buffer copying the surface from top left to bottom right would
// overwrite the source, since we have more bits per destination
// color than per source color.
dst += h * dstPitch - dstDelta - dstFmt.bytesPerPixel;
src += h * srcPitch - srcDelta - srcFmt.bytesPerPixel;
crossBlitLogic<uint16, 2, uint8, 3, true, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else if (srcFmt.bytesPerPixel == 3) {
crossBlitLogic<uint8, 3, uint8, 3, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else {
crossBlitLogic<uint32, 4, uint8, 3, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
}
} else if (dstFmt.bytesPerPixel == 4) {
if (srcFmt.bytesPerPixel == 2) {
// We need to blit the surface from bottom right to top left here.
// This is neeeded, because when we convert to the same memory
// buffer copying the surface from top left to bottom right would
// overwrite the source, since we have more bits per destination
// color than per source color.
dst += h * dstPitch - dstDelta - dstFmt.bytesPerPixel;
src += h * srcPitch - srcDelta - srcFmt.bytesPerPixel;
crossBlitLogic<uint16, 2, uint32, 4, true, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else if (srcFmt.bytesPerPixel == 3) {
// We need to blit the surface from bottom right to top left here.
// This is neeeded, because when we convert to the same memory
// buffer copying the surface from top left to bottom right would
// overwrite the source, since we have more bits per destination
// color than per source color.
dst += h * dstPitch - dstDelta - dstFmt.bytesPerPixel;
src += h * srcPitch - srcDelta - srcFmt.bytesPerPixel;
crossBlitLogic<uint8, 3, uint32, 4, true, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else {
crossBlitLogic<uint32, 4, uint32, 4, false, false, true>(dst, src, mask, w, h, srcFmt, dst
</details>
<!-- suggestion_end -->
<!-- This is an auto-generated comment by CodeRabbit -->

Comment on lines 198 to 234
if (backward) {
src -= SrcSize;
dst -= DstSize;
if (hasMask)
mask -= 1;
} else {
src += SrcSize;
dst += DstSize;
if (hasMask)
mask += 1;
}
}

if (backward) {
src -= srcDelta;
dst -= dstDelta;
if (hasMask)
mask -= maskDelta;
} else {
src += srcDelta;
dst += dstDelta;
if (hasMask)
mask += maskDelta;
}
}
}

template<typename DstColor, int DstSize, bool backward, bool hasKey>
inline void crossBlitLogic1BppSource(byte *dst, const byte *src, const uint w, const uint h,
const uint srcDelta, const uint dstDelta, const uint32 *map, const uint32 key) {
template<typename DstColor, int DstSize, bool backward, bool hasKey, bool hasMask>
inline void crossBlitLogic1BppSource(byte *dst, const byte *src, const byte *mask, const uint w, const uint h,
const uint srcDelta, const uint dstDelta, const uint maskDelta, const uint32 *map, const uint32 key) {
for (uint y = 0; y < h; ++y) {
for (uint x = 0; x < w; ++x) {
const byte color = *src;
if (!hasKey || color != key) {
if ((!hasKey || color != key) && (!hasMask || *mask != 0)) {
if (DstSize == sizeof(DstColor)) {
*(DstColor *)dst = map[color];
} else {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: This review was outside of the patch, so it was mapped to the patch with the greatest overlap. Original lines [168-223]

The crossBlitLogic function is complex and handles many cases. It might be beneficial to break it down into smaller, more manageable functions. This would improve readability and maintainability.

Comment on lines 239 to 264
if (backward) {
src -= 1;
dst -= DstSize;
if (hasMask)
mask -= 1;
} else {
src += 1;
dst += DstSize;
if (hasMask)
mask += 1;
}
}

if (backward) {
src -= srcDelta;
dst -= dstDelta;
if (hasMask)
mask -= maskDelta;
} else {
src += srcDelta;
dst += dstDelta;
if (hasMask)
mask += maskDelta;
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: This review was outside of the patch, so it was mapped to the patch with the greatest overlap. Original lines [226-261]

The crossBlitLogic1BppSource function is well implemented. It correctly handles the blitting operation for different pixel sizes. However, it assumes that the mask is a single byte, which might not always be the case. Consider adding a template parameter for the mask size if different mask sizes need to be supported.

Comment on lines 553 to 559
// color than per source color.
dst += h * dstPitch - dstDelta - bytesPerPixel;
src += h * srcPitch - srcDelta - 1;
crossBlitLogic1BppSource<uint16, 2, true, true>(dst, src, w, h, srcDelta, dstDelta, map, key);
crossBlitLogic1BppSource<uint16, 2, true, true, false>(dst, src, nullptr, w, h, srcDelta, dstDelta, 0, map, key);
} else if (bytesPerPixel == 3) {
// We need to blit the surface from bottom right to top left here.
// This is needed, because when we convert to the same memory
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: This review was outside of the patch, so it was mapped to the patch with the greatest overlap. Original lines [547-575]

These sections of code are repetitive and could be simplified by creating a helper function that takes the bytes per pixel as a parameter and calls the appropriate crossBlitLogic or crossBlitLogic1BppSource function.

Comment on lines +412 to +477
// Function to blit a rect from one color format to another with a transparent color mask
bool crossMaskBlit(byte *dst, const byte *src, const byte *mask,
const uint dstPitch, const uint srcPitch, const uint maskPitch,
const uint w, const uint h,
const Graphics::PixelFormat &dstFmt, const Graphics::PixelFormat &srcFmt) {
// Error out if conversion is impossible
if ((srcFmt.bytesPerPixel == 1) || (dstFmt.bytesPerPixel == 1)
|| (!srcFmt.bytesPerPixel) || (!dstFmt.bytesPerPixel))
return false;

// Don't perform unnecessary conversion
if (srcFmt == dstFmt) {
maskBlit(dst, src, mask, dstPitch, srcPitch, maskPitch, w, h, dstFmt.bytesPerPixel);
return true;
}

// Faster, but larger, to provide optimized handling for each case.
const uint srcDelta = (srcPitch - w * srcFmt.bytesPerPixel);
const uint dstDelta = (dstPitch - w * dstFmt.bytesPerPixel);
const uint maskDelta = (maskPitch - w);

// TODO: optimized cases for dstDelta of 0
if (dstFmt.bytesPerPixel == 2) {
if (srcFmt.bytesPerPixel == 2) {
crossBlitLogic<uint16, 2, uint16, 2, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else if (srcFmt.bytesPerPixel == 3) {
crossBlitLogic<uint8, 3, uint16, 2, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else {
crossBlitLogic<uint32, 4, uint16, 2, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
}
} else if (dstFmt.bytesPerPixel == 3) {
if (srcFmt.bytesPerPixel == 2) {
// We need to blit the surface from bottom right to top left here.
// This is needed, because when we convert to the same memory
// buffer copying the surface from top left to bottom right would
// overwrite the source, since we have more bits per destination
// color than per source color.
dst += h * dstPitch - dstDelta - dstFmt.bytesPerPixel;
src += h * srcPitch - srcDelta - srcFmt.bytesPerPixel;
crossBlitLogic<uint16, 2, uint8, 3, true, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else if (srcFmt.bytesPerPixel == 3) {
crossBlitLogic<uint8, 3, uint8, 3, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else {
crossBlitLogic<uint32, 4, uint8, 3, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
}
} else if (dstFmt.bytesPerPixel == 4) {
if (srcFmt.bytesPerPixel == 2) {
// We need to blit the surface from bottom right to top left here.
// This is neeeded, because when we convert to the same memory
// buffer copying the surface from top left to bottom right would
// overwrite the source, since we have more bits per destination
// color than per source color.
dst += h * dstPitch - dstDelta - dstFmt.bytesPerPixel;
src += h * srcPitch - srcDelta - srcFmt.bytesPerPixel;
crossBlitLogic<uint16, 2, uint32, 4, true, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else if (srcFmt.bytesPerPixel == 3) {
// We need to blit the surface from bottom right to top left here.
// This is neeeded, because when we convert to the same memory
// buffer copying the surface from top left to bottom right would
// overwrite the source, since we have more bits per destination
// color than per source color.
dst += h * dstPitch - dstDelta - dstFmt.bytesPerPixel;
src += h * srcPitch - srcDelta - srcFmt.bytesPerPixel;
crossBlitLogic<uint8, 3, uint32, 4, true, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else {
crossBlitLogic<uint32, 4, uint32, 4, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The crossMaskBlit function correctly calls crossBlitLogic with the appropriate parameters based on the bytes per pixel. It also checks if the source and destination are the same, in which case it returns true without doing anything. However, it returns false if the bytes per pixel is not 1, 2, 3, or 4. It might be better to throw an exception or return an error code in this case, to make it clear that an unsupported pixel format was used.

- if (bytesPerPixel != 1 && bytesPerPixel != 2 && bytesPerPixel != 3 && bytesPerPixel != 4) {
-   return false;
- }
+ if (bytesPerPixel != 1 && bytesPerPixel != 2 && bytesPerPixel != 3 && bytesPerPixel != 4) {
+   throw std::invalid_argument("Unsupported pixel format in crossMaskBlit");
+ }

Commitable suggestion

[!IMPORTANT]
Carefully review the code before committing. Make sure it correctly replaces the highlighted code, has no missing lines and indentaion issues.

Suggested change
// Function to blit a rect from one color format to another with a transparent color mask
bool crossMaskBlit(byte *dst, const byte *src, const byte *mask,
const uint dstPitch, const uint srcPitch, const uint maskPitch,
const uint w, const uint h,
const Graphics::PixelFormat &dstFmt, const Graphics::PixelFormat &srcFmt) {
// Error out if conversion is impossible
if ((srcFmt.bytesPerPixel == 1) || (dstFmt.bytesPerPixel == 1)
|| (!srcFmt.bytesPerPixel) || (!dstFmt.bytesPerPixel))
return false;
// Don't perform unnecessary conversion
if (srcFmt == dstFmt) {
maskBlit(dst, src, mask, dstPitch, srcPitch, maskPitch, w, h, dstFmt.bytesPerPixel);
return true;
}
// Faster, but larger, to provide optimized handling for each case.
const uint srcDelta = (srcPitch - w * srcFmt.bytesPerPixel);
const uint dstDelta = (dstPitch - w * dstFmt.bytesPerPixel);
const uint maskDelta = (maskPitch - w);
// TODO: optimized cases for dstDelta of 0
if (dstFmt.bytesPerPixel == 2) {
if (srcFmt.bytesPerPixel == 2) {
crossBlitLogic<uint16, 2, uint16, 2, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else if (srcFmt.bytesPerPixel == 3) {
crossBlitLogic<uint8, 3, uint16, 2, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else {
crossBlitLogic<uint32, 4, uint16, 2, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
}
} else if (dstFmt.bytesPerPixel == 3) {
if (srcFmt.bytesPerPixel == 2) {
// We need to blit the surface from bottom right to top left here.
// This is needed, because when we convert to the same memory
// buffer copying the surface from top left to bottom right would
// overwrite the source, since we have more bits per destination
// color than per source color.
dst += h * dstPitch - dstDelta - dstFmt.bytesPerPixel;
src += h * srcPitch - srcDelta - srcFmt.bytesPerPixel;
crossBlitLogic<uint16, 2, uint8, 3, true, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else if (srcFmt.bytesPerPixel == 3) {
crossBlitLogic<uint8, 3, uint8, 3, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else {
crossBlitLogic<uint32, 4, uint8, 3, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
}
} else if (dstFmt.bytesPerPixel == 4) {
if (srcFmt.bytesPerPixel == 2) {
// We need to blit the surface from bottom right to top left here.
// This is neeeded, because when we convert to the same memory
// buffer copying the surface from top left to bottom right would
// overwrite the source, since we have more bits per destination
// color than per source color.
dst += h * dstPitch - dstDelta - dstFmt.bytesPerPixel;
src += h * srcPitch - srcDelta - srcFmt.bytesPerPixel;
crossBlitLogic<uint16, 2, uint32, 4, true, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else if (srcFmt.bytesPerPixel == 3) {
// We need to blit the surface from bottom right to top left here.
// This is neeeded, because when we convert to the same memory
// buffer copying the surface from top left to bottom right would
// overwrite the source, since we have more bits per destination
// color than per source color.
dst += h * dstPitch - dstDelta - dstFmt.bytesPerPixel;
src += h * srcPitch - srcDelta - srcFmt.bytesPerPixel;
crossBlitLogic<uint8, 3, uint32, 4, true, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else {
crossBlitLogic<uint32, 4, uint32, 4, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
// Function to blit a rect from one color format to another with a transparent color mask
bool crossMaskBlit(byte *dst, const byte *src, const byte *mask,
const uint dstPitch, const uint srcPitch, const uint maskPitch,
const uint w, const uint h,
const Graphics::PixelFormat &dstFmt, const Graphics::PixelFormat &srcFmt) {
// Error out if conversion is impossible
if ((srcFmt.bytesPerPixel == 1) || (dstFmt.bytesPerPixel == 1)
|| (!srcFmt.bytesPerPixel) || (!dstFmt.bytesPerPixel))
throw std::invalid_argument("Unsupported pixel format in crossMaskBlit");
// Don't perform unnecessary conversion
if (srcFmt == dstFmt) {
maskBlit(dst, src, mask, dstPitch, srcPitch, maskPitch, w, h, dstFmt.bytesPerPixel);
return true;
}
// Faster, but larger, to provide optimized handling for each case.
const uint srcDelta = (srcPitch - w * srcFmt.bytesPerPixel);
const uint dstDelta = (dstPitch - w * dstFmt.bytesPerPixel);
const uint maskDelta = (maskPitch - w);
// TODO: optimized cases for dstDelta of 0
if (dstFmt.bytesPerPixel == 2) {
if (srcFmt.bytesPerPixel == 2) {
crossBlitLogic<uint16, 2, uint16, 2, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else if (srcFmt.bytesPerPixel == 3) {
crossBlitLogic<uint8, 3, uint16, 2, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else {
crossBlitLogic<uint32, 4, uint16, 2, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
}
} else if (dstFmt.bytesPerPixel == 3) {
if (srcFmt.bytesPerPixel == 2) {
// We need to blit the surface from bottom right to top left here.
// This is needed, because when we convert to the same memory
// buffer copying the surface from top left to bottom right would
// overwrite the source, since we have more bits per destination
// color than per source color.
dst += h * dstPitch - dstDelta - dstFmt.bytesPerPixel;
src += h * srcPitch - srcDelta - srcFmt.bytesPerPixel;
crossBlitLogic<uint16, 2, uint8, 3, true, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else if (srcFmt.bytesPerPixel == 3) {
crossBlitLogic<uint8, 3, uint8, 3, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else {
crossBlitLogic<uint32, 4, uint8, 3, false, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
}
} else if (dstFmt.bytesPerPixel == 4) {
if (srcFmt.bytesPerPixel == 2) {
// We need to blit the surface from bottom right to top left here.
// This is neeeded, because when we convert to the same memory
// buffer copying the surface from top left to bottom right would
// overwrite the source, since we have more bits per destination
// color than per source color.
dst += h * dstPitch - dstDelta - dstFmt.bytesPerPixel;
src += h * srcPitch - srcDelta - srcFmt.bytesPerPixel;
crossBlitLogic<uint16, 2, uint32, 4, true, false, true>(dst, src, mask, w, h, srcFmt, dstFmt, srcDelta, dstDelta, maskDelta, 0);
} else if (srcFmt.bytesPerPixel == 3) {
// We need to blit the surface from bottom right to top left here.
// This is neeeded, because when we convert to the same memory
// buffer copying the surface from top left to bottom right would
// overwrite the source, since we have more bits per destination
// color than per source color.
dst += h * dstPitch - dstDelta - dstFmt.bytesPerPixel;
src += h * srcPitch - srcDelta - srcFmt.bytesPerPixel;
c
</details>
<!-- suggestion_end -->
<!-- This is an auto-generated comment by CodeRabbit -->

@sev-
Copy link
Member

sev- commented Nov 10, 2023

Thanks!

@sev- sev- merged commit c878250 into scummvm:master Nov 10, 2023
8 checks passed
@ccawley2011 ccawley2011 deleted the blit-masks branch November 10, 2023 13:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants