Allegro direct vidmem access help

Started by
5 comments, last by kratz 14 years, 5 months ago
Can anyone see what I'm doing wrong here? I'm trying to read each line of the screen bitmap, test and fade each pixel. I'm trying to do this by reading 32bits at a time (following the exflame example) but I'm doing something wrong because only half of the screen is being faded. Color depth is 16bpp

unsigned short buffer[SCREEN_W];
unsigned long address;
.
.
.
.
//Direct video memory access
//Check each pixel, if it has color, reduce color
for(int i = 0; i < SCREEN_H; i++)
{
       //Get the video memory address for reading
        address = bmp_read_line(screen, i);
        for(int j = 0; j < SCREEN_W; j+= sizeof(uint32_t))
	{
	     *((uint32_t *)&buffer[j]) = bmp_read32(address+j);
	} 
	//Fade the color
	for(int j = 0; j< SCREEN_W; j++)
	    if(buffer[j] > 0)
		buffer[j]--;

	//Get the video memory address for writing
	address = bmp_write_line(screen, i);
	for(int j = 0; j < SCREEN_W; j+= sizeof(uint32_t))
	{
	   bmp_write32(address+j, *((uint32_t *)&buffer[j]));
	}
}

Also could someone put the left side of this into English for me. *((uint32_t *)&buffer[j]) = bmp_read32(address+j); Thanks in advance, kratz
---------------------------Noobies have feelings too!!----------------------------
Advertisement
Try changing the type of the buffer variable to be a unsigned byte array, instead of an unsigned short one (like in the exflame example).
(If this isn't viable because you use buffer elsewhere, instead change both *((uint32_t *)&buffer[j]) to *((uint32_t *)&buffer[j / 2])).

Currently when do you *((uint32_t *)&buffer[j]) you are moving over 8 bytes of the buffer for every 4 from the screen bitmap.

Quote:Original post by kratz
Also could someone put the left side of this into English for me.
*((uint32_t *)&buffer[j]) = bmp_read32(address+j);


Start from the innermost part:
buffer is obviously your temporary array
buffer[j] is the j'th item in this array (note that it is indexed by item (so unsigned short in this case), not bytes!)
&buffer[j] is a pointer to the above item
(uint32_t *)&buffer[j] casts the pointer so that it has unsigned long width
*((uint32_t *)&buffer[j]) refers to an unsigned long at this location.

[Edited by - mattd on October 27, 2009 1:33:08 AM]
Thanks for the reply matt but I tried your suggestion and it doesn't work. Besides, don't I need each item in buffer[] to be 16 bits since they represent each pixel in 16 bit depth?

Also, I think uint32_t is defined as unsigned int = 4 bytes right?

Thanks,
kratz
---------------------------Noobies have feelings too!!----------------------------
Quote:Besides, don't I need each item in buffer[] to be 16 bits since they represent each pixel in 16 bit depth?


Well, when you cast the buffer pointer to (uint32_t *) you are treating it as an unsigned int array, so it should make no difference. But yes, it will make processing the data after reading it easier.

Quote:Also, I think uint32_t is defined as unsigned int = 4 bytes right?


Yes it is, sorry :)


Having another read of your code, I think this is the problem after all:
for(int j = 0; j < SCREEN_W; j+= sizeof(uint32_t))

The exflame code runs in 8-bit colour, so since 1 pixel fits in 1 byte, we can just treat the offset j as a pixel width as well, so we need to range j from 0 to SCREEN_W, so the comparison j < SCREEN_W is valid.

But with 16-bit mode in your application, 1 pixel fits in 2 bytes, so we need to make the offset j range from 0 to SCREEN_W * 2 to get all SCREEN_W pixels, so the comparison needs to be j < SCREEN_W * 2.

Try changing the comparison in both for loops. Note that you'll still want to have changed both *((uint32_t *)&buffer[j]) to *((uint32_t *)&buffer[j / 2])), otherwise you'll overwrite buffer with this newly expanded offset range.


Also, note that you will probably want to do something like this to process the pixel data to fade it, since you are using 16-bit pixels, not 8-bit:
	for(int j = 0; j< SCREEN_W; j++)            buffer[j] = makecol16(max(0, getr16(buffer[j]) - 1), max(0, getg16(buffer[j]) - 1), max(0, getb16(buffer[j]) - 1));

I.e., treat each of the R, G, B components seperately.
I don't think that will work either since buffer is buffer[SCREEN_W] I can't let j be over SCREEN_W. I could change the size of the buffer but I don't think that makes sense either. It should be the perfect size to hold 1 line of the screen.

Thanks for the help,
kratz
---------------------------Noobies have feelings too!!----------------------------
But note:

Quote:
Note that you'll still want to have changed both *((uint32_t *)&buffer[j]) to *((uint32_t *)&buffer[j / 2])), otherwise you'll overwrite buffer with this newly expanded offset range.


The / 2 converts back from offset to pixel width.
Oh I get it now.... Sorry I missed that. It works perfectly.

Thanks for the pointers matt

Rating++
---------------------------Noobies have feelings too!!----------------------------

This topic is closed to new replies.

Advertisement