Bitmap mask ignored when given to newBitmap

I'm a little confused about what I should expect here, but this simple C code doesn't render nothing as I would expect:

static int update(void* userdata)
{
	PlaydateAPI* pd = userdata;

	const LCDPattern grey_masked = {
		// Bitmap
		0b10101010,
		0b01010101,
		0b10101010,
		0b01010101,
		0b10101010,
		0b01010101,
		0b10101010,
		0b01010101,

		// Mask
		0b00000000,
		0b00000000,
		0b00000000,
		0b00000000,
		0b00000000,
		0b00000000,
		0b00000000,
		0b00000000,
	};

	pd->graphics->clear(kColorWhite);
	LCDBitmap* bitmap = pd->graphics->newBitmap(64, 64, (LCDColor)grey_masked);
	pd->graphics->setDrawMode(kDrawModeCopy);
	pd->graphics->drawBitmap(bitmap, 0, 0, kBitmapUnflipped);
	pd->graphics->freeBitmap(bitmap);

	return 1;
}

This produces a white frame with a black square:

Is this a bug? Why is this? Surely a blank mask should mean nothing should render.

My assumption is the mask part is ignored for some reason in newBitmap, and setBitmapMask is expected to be used? But this feels unexpected.

Sorry for the delay! We've been super busy with Season 2, but now that it's out I can get back to developer support. :relieved:

You're right, the problem is newBitmap only creates an image with a mask if the background color is kColorClear, doesn't check if it's a pattern. I'll be easy to add that, will file it now. In the mean time though.. I'm not sure what the best workaround is.. Probably create an image with clear background, draw the bitmap part with one pattern then draw the mask pattern into the image returned by getBitmapMask(). Maybe there's a more concise way to do it but it's not coming to me right now.

static int update(void* userdata)
{
	PlaydateAPI* pd = userdata;

	const LCDPattern image_pattern = LCDOpaquePattern(
		// Bitmap
		0b10101010,
		0b01010101,
		0b10101010,
		0b01010101,
		0b10101010,
		0b01010101,
		0b10101010,
		0b01010101
	);

	const LCDPattern mask_pattern = LCDOpaquePattern(
		// Mask
		0b00010000,
		0b00111000,
		0b01111100,
		0b11111110,
		0b01111100,
		0b00111000,
		0b00010000,
		0b00000000
	);

	pd->graphics->clear(kColorWhite);
	LCDBitmap* bitmap = pd->graphics->newBitmap(64, 64, kColorClear);
	pd->graphics->pushContext(bitmap);
	pd->graphics->fillRect(0,0,64,64,(LCDColor)image_pattern);
	pd->graphics->popContext();

	pd->graphics->pushContext(pd->graphics->getBitmapMask(bitmap));
	pd->graphics->fillRect(0,0,64,64,(LCDColor)mask_pattern);
	pd->graphics->popContext();

	pd->graphics->setDrawMode(kDrawModeCopy);
	pd->graphics->drawBitmap(bitmap, 0, 0, kBitmapUnflipped);
	pd->graphics->freeBitmap(bitmap);

	return 1;
}

Awesome thanks for the great work and confirmation.

Yup, I think in my code I've opted to create the clear bitmap and use a stencil of the pattern, but the end result is the same.

1 Like

It’s better with a stencil imo because the dithering will be static (it will not move with the sprite) thus eliminating flickering.

1 Like