that's quite interesting, and i suspect you've discovered a bug.
actually two bugs, maybe. one has to deal with drawing alpha-blended
images, the other with drawing using RGBA32...

the simplest way to trigger the second bug, which may or may not be
related to the first, is to draw using black, RGBA32 channel and full
alpha:

the following draws fine on the screen:
b = allocimage(display, Rect(0, 0, Dx(screen->r), Dy(screen->r)),
ARGB32, 0, DBlack);
draw(screen, screen->r, b, nil, ZP);

but the following draws incorrectly as blue:
allocimage(display, Rect(0, 0, Dx(screen->r), Dy(screen->r)), RGBA32,
0, DBlack);
draw(screen, screen->r, b, nil, ZP);

at this point i would suspect an endianness issue. setalpha doesn't
care about endianness, but libmemdraw does.

to add a bit more information i've taken the liberty of modifying your
program. the code attached exhibits all sorts of issues with alpha
blending and illustrates them more fully (i've also used a few of the
tricks in /sys/src/libdraw/arith.c to show the correct usage of Pt(),
ZP, color names and the like)

in this example everything is drawn over a black screen image to avoid
any effects of conversion to the real bpp of the screen. the base
image's channel type is fixed at ABGR32 because this particular
channel does not exhibit the behaviour of switching from black to blue
described at the beginning of this email. i've included a screencap
with the black image using RGBA32 so you can see the difference.

the program shows 4 different columns of 256 lines with varying levels
of alpha-blendedness (from 0xFF on top to 0x00 on bottom). the first
column draws white, second red, third green and fourth blue.

below the column a single line is drawn twice: once on the black
screen and once on the display screen directly. in the two attached
snapshots the line (created with ARGB23) is drawn correctly both on
the black image and on the display when the black image is ARGB32, but
if we switch to RGBA32 for the black image the first line gets mangled
when the whole image is displayed.

i'll leave the bit/byte swap analysis to the readers :)

ps: are you using this on native terminal? it would be very
interesting to test the program there for different values of ARGB32,
RGBA32 and ABGR32 (there's no BGRA32) and possibly under display depth
of 32bpp. i only have 9vx and drawterm to test with, unfortunately,
although i will try with osx's drawterm when i get home: that one runs
in 32bpp at all times.

cheers!
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <cursor.h>

Image *col;
Image *black;

void
main(void) {
	int i;
	ulong type = ARGB32;

	newwindow("-r 0 0 800 400");
	if(initdraw(nil, nil, "tri") < 0)
		exits("initdraw");

	black = allocimage(display, Rect(0, 0, Dx(screen->r), Dy(screen->r)), ARGB32, 0, DBlack);

	for(i = 0; i < 0xff; i++) {
		col = allocimage(display, Rect(0,0,1,1), type, 1, setalpha(DWhite, 0xff-i));
		draw(black, Rect(0,i,200,i+1), col, nil, ZP);
		freeimage(col);

		col = allocimage(display, Rect(0,0,1,1), type, 1, setalpha(DRed, 0xff-i));
		draw(black, Rect(200,i,400,i+1), col, nil, ZP);
		freeimage(col);
		col = allocimage(display, Rect(0,0,1,1), type, 1, setalpha(DGreen, 0xff-i));
		draw(black, Rect(400,i,600,i+1), col, nil, ZP);
		freeimage(col);
		col = allocimage(display, Rect(0,0,1,1), type, 1, setalpha(DBlue, 0xff-i));
		draw(black, Rect(600,i,800,i+1), col, nil, ZP);
		freeimage(col);	
	}
	col = allocimage(display, Rect(0, 0, 1, 1), type, 1, DBlack);
	draw(black, Rect(0, 260, 800, 300), col, nil, ZP);
	draw(screen, screen->r, black, nil, ZP);

	draw(screen, Rect(0, 360, 800, 400), col, nil, ZP);


	flushimage(display, 1);
	sleep(10000);
	closedisplay(display);
}

<<attachment: RGBA32.png>>

<<attachment: ARGB32.png>>

Reply via email to