Big background problem

TGH
Posts: 11
Joined: Tue Oct 18, 2011 10:34 am

Re: Big background problem

Post by TGH » Fri Oct 21, 2011 8:42 pm

dmacopy() also doesn't give me any option to only copy sectors of a bitmap to the memory so I'm kinda stuck.
Other dmacopy() functions also doesn't gave the solution, or am I missing something...?

TGH
Posts: 11
Joined: Tue Oct 18, 2011 10:34 am

Re: Big background problem

Post by TGH » Sat Oct 22, 2011 5:46 pm

Ok, I have a small breakthrough. I have successfully copied my image to the buffer in the correct order. Only my image is shown diagonal...

Code: Select all

void create_buffers()
{
	main_buffer = (Color*)calloc(SCREEN_PIXEL_COUNT, sizeof(Color));
	sub_buffer = (Color*)calloc(SCREEN_PIXEL_COUNT, sizeof(Color));

}



void init_displays()
{
	// Enable both screens for 2D graphics
	powerOn(POWER_2D_A);
	powerOn(POWER_2D_B);

	// Enable VBLANK interrupt
	irqEnable(IRQ_VBLANK);

	// Set up main screen (mode 5 -> two bitmap layers)
	REG_DISPCNT = MODE_5_2D | DISPLAY_BG3_ACTIVE;

	// Map memory banks to the screens
	VRAM_A_CR = VRAM_ENABLE | VRAM_A_MAIN_BG;
	VRAM_B_CR = VRAM_ENABLE | VRAM_B_MAIN_BG;

	// Main screen on the bottem
	lcdMainOnBottom();

}

void init_video()
{
	init_displays();
	//init_backgrounds();
}



void copy_comic_to_buffer( Comic *comic, Color *buffer )
{
	s16 x_pos, y_pos;

	for(y_pos = 0; y_pos < SCREEN_HEIGHT; y_pos++)
	{
		for(x_pos = 0; x_pos < SCREEN_WIDTH; x_pos++)
		{
			buffer[(y_pos * SCREEN_WIDTH) + x_pos ] = comic->image[(y_pos * comic->image_width) + (x_pos + comic->offset_x)];
		}
	}

}


void scroll_comic(Comic* comic, u8 speed)
{
	// Main screen background (16 bit bitmap -> 256x256 pixels)
	REG_BG3CNT = BG_BMP16_256x256 | BG_BMP_BASE(0) | BG_PRIORITY(1);

	// Set background: no scaling, rotation and offset
	REG_BG3PA = (1 << 8); // Scale X (1.0 = 0)
	REG_BG3PB = 0; // X rotation
	REG_BG3PC = 0; // Y rotation
	REG_BG3PD = (1 << 8); // Scale Y (1.0 = 0)
	REG_BG3X = comic->offset_x; // X position
	REG_BG3Y = 0; // Y position

	comic->offset_x = comic->offset_x + speed;
	int i = 0;
	for(i=0; i<3; i++)
	{
		swiWaitForVBlank();
	}

}


int main()
{
	consoleDemoInit();
	Comic comic1 = {COMICBMP, 952, 0};

	//init_backgrounds();
	create_buffers();
	init_video();
	while(1)
	{
		copy_comic_to_buffer(&comic1, MAIN_BACKGROUND);
		scroll_comic(&comic1, 1);
	}




	return 0;
}
What's wrong?

mtheall
Posts: 210
Joined: Thu Feb 03, 2011 10:47 pm

Re: Big background problem

Post by mtheall » Sun Oct 23, 2011 5:43 am

I can say a couple of things about your code. First, you're performing a lot of steps that are automatically done before main() begins and setting up registers that are easier done with the libnds API. Here are some snippets that would be equivalent to what you have:

Code: Select all

void init_displays()
{
   // Enable both screens for 2D graphics -- done before main()
   // Enable VBLANK interrupt -- done before main()
   // Set up main screen (mode 5 -> two bitmap layers)
   setVideoMode(MODE_5_2D);

   // Map memory banks to the screens
   vramSetBankA(VRAM_A_MAIN_BG);
   vramSetBankB(VRAM_B_MAIN_BG);

   // Main screen on the bottom
   lcdMainOnBottom();

   // Main screen background (16 bit bitmap -> 256x256 pixels -- moved here because you only need to do it once
   bgInit(3, BgType_Bmp16, BgSize_B16_256x256, 0, 0);
}

Code: Select all

void scroll_comic(Comic* comic, u8 speed)
{
   // Set background: no scaling, rotation and offset
   // pretty sure affine matrix is initialized to identity matrix before main()
   bgSetScroll(3, comic->offset_x, 0);

   comic->offset_x = comic->offset_x + speed;
   int i = 0;
   for(i=0; i<3; i++)
   {
      swiWaitForVBlank();
   }

}
Second, your code to copy from buffer to buffer is buggy. You take into account the dimensions of the target buffer, but not the source buffer. You need to pay attention to the edges of the source buffer if you want it to be copied correctly. You can either bound the scroll to make sure you never draw anything outside of the image, or you can check for out-of-bounds pixels and blank those pixels. Additionally, I assume your Comic.image and Color types are 16-bit RGB.
TGH wrote:dmacopy() also doesn't give me any option to only copy sectors of a bitmap to the memory so I'm kinda stuck.
Other dmacopy() functions also doesn't gave the solution, or am I missing something...?
Of course dmaCopy() gives you the option to copy sectors of a bitmap to the memory. You just need to figure out how to break it up into multiple copies, where each copy source/target begins, and the length of each copy. It's semantically no different than memcpy() if you make sure you are cache-correct. As a hint, I will tell you that each copy will replace the inner loop in your for-loop copy (the x part).

TGH
Posts: 11
Joined: Tue Oct 18, 2011 10:34 am

Re: Big background problem

Post by TGH » Sun Oct 23, 2011 2:01 pm

mtheall wrote:I can say a couple of things about your code. First, you're performing a lot of steps that are automatically done before main() begins and setting up registers that are easier done with the libnds API. Here are some snippets that would be equivalent to what you have:

Code: Select all

void init_displays()
{
   // Enable both screens for 2D graphics -- done before main()
   // Enable VBLANK interrupt -- done before main()
   // Set up main screen (mode 5 -> two bitmap layers)
   setVideoMode(MODE_5_2D);

   // Map memory banks to the screens
   vramSetBankA(VRAM_A_MAIN_BG);
   vramSetBankB(VRAM_B_MAIN_BG);

   // Main screen on the bottom
   lcdMainOnBottom();

   // Main screen background (16 bit bitmap -> 256x256 pixels -- moved here because you only need to do it once
   bgInit(3, BgType_Bmp16, BgSize_B16_256x256, 0, 0);
}

Code: Select all

void scroll_comic(Comic* comic, u8 speed)
{
   // Set background: no scaling, rotation and offset
   // pretty sure affine matrix is initialized to identity matrix before main()
   bgSetScroll(3, comic->offset_x, 0);

   comic->offset_x = comic->offset_x + speed;
   int i = 0;
   for(i=0; i<3; i++)
   {
      swiWaitForVBlank();
   }

}
Second, your code to copy from buffer to buffer is buggy. You take into account the dimensions of the target buffer, but not the source buffer. You need to pay attention to the edges of the source buffer if you want it to be copied correctly. You can either bound the scroll to make sure you never draw anything outside of the image, or you can check for out-of-bounds pixels and blank those pixels. Additionally, I assume your Comic.image and Color types are 16-bit RGB.

TGH wrote:dmacopy() also doesn't give me any option to only copy sectors of a bitmap to the memory so I'm kinda stuck.
Other dmacopy() functions also doesn't gave the solution, or am I missing something...?
Of course dmaCopy() gives you the option to copy sectors of a bitmap to the memory. You just need to figure out how to break it up into multiple copies, where each copy source/target begins, and the length of each copy. It's semantically no different than memcpy() if you make sure you are cache-correct. As a hint, I will tell you that each copy will replace the inner loop in your for-loop copy (the x part).

Thanks for the reaction. I see what you did with cleaning the code, it was indeed a mess.

I'm so goddamn stuck and I'm not coming further with your advice, because I don't see it. It's frustrating me so hard.
The bold pieces are the things I don't fully understand, plus, i don't know how to do it.

mtheall
Posts: 210
Joined: Thu Feb 03, 2011 10:47 pm

Re: Big background problem

Post by mtheall » Sun Oct 23, 2011 6:36 pm

Oops, I forgot that when you use the background API, such as bgSetScroll(), you need to call bgUpdate() for it to take effect:

Code: Select all

void scroll_comic(Comic* comic, u8 speed)
{
   // Set background: no scaling, rotation and offset
   // pretty sure affine matrix is initialized to identity matrix before main()
   bgSetScroll(3, comic->offset_x, 0);

   comic->offset_x = comic->offset_x + speed; // <-- this is one place you can do bounds checking
   int i = 0;
   for(i=0; i<3; i++)
   {
      swiWaitForVBlank();
      bgUpdate(); // <--- put it here so it takes effect on the next frame and not three frames later
   }
}
This is because the bg API writes to a buffer, and you wait until vblank to flush it with bgUpdate().

As for the first bold point, I'm not sure how to explain that without saying it the way I said it. Maybe I can make a more clear explanation later. But for the second bold point, I'll make it more evident:

Code: Select all

void copy_comic_to_buffer( Comic *comic, Color *buffer )
{
   s16 x_pos, y_pos;

   for(y_pos = 0; y_pos < SCREEN_HEIGHT; y_pos++)
   {
      /* replace this inner loop with memcpy() (or dmaCopy() if you know what kinds of problems to expect and how to fix/avoid them).
       * This is one place you can do bounds checking, but simply switching to memcpy() or dmaCopy() will not solve it for you.
       * If you do choose to perform bounds checking elsewhere, you will still require code here if you have images that are smaller than
       * 256x192, i.e. you need to make sure you don't draw stuff where the image doesn't exist (or maybe better to clear those areas).
       */
      /* for(x_pos = 0; x_pos < SCREEN_WIDTH; x_pos++)
      {
         buffer[(y_pos * SCREEN_WIDTH) + x_pos ] = comic->image[(y_pos * comic->image_width) + (x_pos + comic->offset_x)];
      } */
   }
}
I will say that it's not really necessary to switch the inner loop to a memcpy()/dmaCopy(), I was just making sure you knew that it's possible.

TGH
Posts: 11
Joined: Tue Oct 18, 2011 10:34 am

Re: Big background problem

Post by TGH » Sun Oct 23, 2011 10:05 pm

Thanks for the reply, but I think that isn't really the problem.

Image

As you can see here the image is actually copied to the buffer, only it is drawn wrong, the image is rotated, but i didn't rotated it at all.

elhobbs
Posts: 358
Joined: Thu Jul 02, 2009 1:19 pm

Re: Big background problem

Post by elhobbs » Sun Oct 23, 2011 10:34 pm

It looks more sheared than rotated. I suspect that you are off by one when determining the new source line.

mtheall
Posts: 210
Joined: Thu Feb 03, 2011 10:47 pm

Re: Big background problem

Post by mtheall » Sun Oct 23, 2011 10:43 pm

Actually, it looks like you have multiple problems here:

1. It looks like your image is mirrored horizontally.
2. It looks like you're off-by-one or off-by-one-and-a-half actually.
3. The color looks like it should be only black and white (XKCD I assume), but you have a gradient.
4. There is some junk at the top line. Are you sure you stripped the header from the source image? Are you loading this from a BMP?

#2 and #3 might actually be the same thing. Are you sure the source image matches the bit-depth of the target buffer? I'm assuming you are using a 16bpp target buffer. The color may be shifted if your source image is 24bpp, which would also explain the shearing (off-by-one-and-a-half).

TGH
Posts: 11
Joined: Tue Oct 18, 2011 10:34 am

Re: Big background problem

Post by TGH » Mon Oct 24, 2011 10:42 am

Image

This is the original image.

1: My image is indeed mirrored. I see it now.
2: That can be true, I don't know.
3: The color is good, look at the source image.
4: Im copying a BMP image, so I presume i missed the header.

Am I copying it wrong to the buffer or something?

User avatar
vuurrobin
Posts: 219
Joined: Fri Jul 11, 2008 8:49 pm
Location: The Netherlands
Contact:

Re: Big background problem

Post by vuurrobin » Mon Oct 24, 2011 12:27 pm

The image is 954 pixels width, but your code says 952 pixels.
Look on wikipedia for how bmp headers are stored so you can ignore the header and write the correct pixel data (or you can use the header to find out the hight and width of the image, among other things).
IIRC, bmp image data can be stored upside down. That can explain the mirroring.

Post Reply

Who is online

Users browsing this forum: No registered users and 21 guests