gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

Beginners > Mode 4 - Writing a single pixel

#5298 - Foz - Thu Apr 24, 2003 8:01 pm

Hi all,

I'm a bit of a noob with a small background with Mode 13h(DOS). I am trying to plot a single pixel to the GBA screen, and I'm having a heck of a time.
Code:
#define SCREEN_WIDTH   240
#define SCREEN_HEIGHT   160
#define FrontBuffer       (u16*)0x6000000
#define BackBuffer      (u16*)0x600A000

//GLOBALS///////////////////////////////////////////////////////

u16* videoBuffer;

////////////////////////////////////////////////////////////////////
void setMode(u16 mode)
{
REG_DISPCNT = mode;
}

void writePixel(int x,int y, u8 color)
{
   videoBuffer[(y*SCREEN_WIDTH) + x] = (u8)color;

} // end writePixel

void Flip(void)
{
  if(REG_DISPCNT & BACK_BUFFER)
  {
   REG_DISPCNT &= ~BACK_BUFFER; 
   videoBuffer = BackBuffer; 
  }
  else
  {
   REG_DISPCNT |= BACK_BUFFER; 
   videoBuffer = FrontBuffer; 
   }
}

int main(void)
{
   u8 i;
   u16 color;
   
        //I suspect the problem is here
       u16 *palette = (u16 *)0x05000000;
      
   setMode(MODE_4|BG_2);
   
   for(i=0; i<256; i++)
   {
   color=31;
   palette[i] =(u16)color;
   }   

   while(1)
   {
   writePixel(10,50,1);
   Flip();
   }
   return 0;
}

This fills the entire screen with red. I am using VGBA as my emulator(vgba8). Incidentally, if I comment out the writePixel function it fills the screen anywayand if I set color to a math function it doesn't display anything. I've looked around, and searched the forums but the docs on Mode 4 seem to be light. I know that I have to write to VRAM two bytes at a time, but the palette should be an 8-bit index. I thought I'd get two pixels. I'm confused. Any help would be appreciated. Be gentle. ;) Thanks.

#5299 - niltsair - Thu Apr 24, 2003 8:11 pm

First, Color 0 of the palette is the background color, thus you get the red color even though you don't write any pixel. (It is also the transparent color when used for tiles/sprites)

Secondly, the video memory can only be accessed using 16bits pointers. You just tried to write a 8bits value. You need to Write 2 pixels at a time by basicly doing this

u16 pix = (pixA<<8) | pixB;

There, pix contains the value of both pixels (pixA and pixB). You can now write pix to the video memory at you location.

To find a position, you alos have to remember that 1 entry of the video memory represent 2 pixels, thus to find the position it would be :

u16 pos = (240/2)*Line + Col/2

(Put clearly, but there's more optimized way to write it)

To access a pixel in a even Column, you take the 8High bits, for the Odd Column, you pick the LowBits (or vice-versa)

#5341 - Foz - Fri Apr 25, 2003 6:23 pm

Thank you niltsair. That's the first time I've seen it put so concisely. I'll give that a try.

That makes sense about Color 0. I should have realized that one. I guess that means that I properly populated the palette.

If I take the 8 high bits for the pixel on the left (even or odd) will the pixel next to it be filled with the background color? I guess I could flag it as transparent :)

Anyway, thanks again you've been more of a help than you know.

-Foz

#5343 - niltsair - Fri Apr 25, 2003 6:42 pm

Yes, if you leave it to 0, it'll take the background color. In mode 3,4,5 we can't really say 'transparent' for the background, since there's only 1 layer.

In mode 0,1-2 you use maps, and can have 4 layer stacked, so then you have a 'transparent' color.

The sprites though are showed above the background in mode 3,4,5 and they use their own palette. If you set one fo their pixel to 0, you'll see the background behing it. (Sprites are also used with mode 0-1-2, and beware, in mode 3,4,5 only the sprite tiles of 512 and up are accessible)

#5356 - Foz - Fri Apr 25, 2003 11:42 pm

It all makes perfect sense now. There's no need for a transparent color in Mode 4 unless your using sprites. The halfword writes are more of a blessing than a hinderance. There's one bit shift operation and a logical OR and two colors can be sent to the screen at the same time.

I here people talk about Mode 4 being a little slower but I used to send one color at a time in 13h, it seems this would be a little faster.

It's so satisfying plotting that first pixel. Thanks again.

#6565 - hzx - Thu May 29, 2003 8:50 am

Foz wrote:
It all makes perfect sense now. There's no need for a transparent color in Mode 4 unless your using sprites. The halfword writes are more of a blessing than a hinderance. There's one bit shift operation and a logical OR and two colors can be sent to the screen at the same time.

I here people talk about Mode 4 being a little slower but I used to send one color at a time in 13h, it seems this would be a little faster.


Yes, if you know both colors. But in practice you usually need to write only one pixel and you have to save the other one. So my plotpixel is:

- calculate pixel position in video buffer
- read the u16
- decide if your pixel goes into the lower or into the higher byte
- modify the u16 respecively
- write it back

You can speed it up by using bit shifting in calculating the pixel position, and bit ops to calculate the byte position in the u16.
_________________
.hzx

#6698 - hnager - Mon Jun 02, 2003 2:06 am

I fumbled around with that same problem - this is where I ended up...In terms of 13h it's near identical you how you would use WORD sized bytes:

void PlotPixel(int x, int y, char color){

if(x & 0x0001){
VideoBuffer[(y*(SCREEN_WIDTH/2)) + (x>>1)] = color << 8;
}else{
VideoBuffer[(y*(SCREEN_WIDTH/2)) + (x>>1)] = color;
}

}

#6703 - niltsair - Mon Jun 02, 2003 3:22 am

I'm thinking that this last tidbit of code is wrong. You can't only write 8Bits, you need to write 16bits...

With this : VideoBuffer[(y*(SCREEN_WIDTH/2)) + (x>>1)] = color << 8
You Lose the lower value.

And with this : VideoBuffer[(y*(SCREEN_WIDTH/2)) + (x>>1)] = color
You lose the upper value.

You have to get the current value first, overwrite the part you want to write, and the copy it back.

Something like this :
Code:
void PlotPixel(int x, int y, u8 color)
{
u16* vidMem;

    vidMem = &VideoBuffer[  ((y*SCREEN_WIDTH) + x)>>1 ];

    if(x % 2)
        *vidMem = (*vidMem & 0x00FF) | (color<<8);
    else
        *vidMem = (*vidMem & 0xFF00) | color;
}

#6705 - hnager - Mon Jun 02, 2003 3:43 am

hmmm, I haven't had a problem plotting a pixel at an x value of 10 and then 11 - they both show up. But I'll try your recommendation and see what happens.

#6706 - niltsair - Mon Jun 02, 2003 3:49 am

That would be because your emulator allow 8bits access. I'm thinking it wouldn't work on hardware. Not 100% certain though.

The reason i created a pointer instead of using an index, was for speed sake, since we're accessing it 3 times.

Take note that i haven't tested the code, so small adjustements might be required, but should do the trick.


Last edited by niltsair on Mon Jun 02, 2003 3:53 am; edited 1 time in total

#6707 - hnager - Mon Jun 02, 2003 3:52 am

Not to worry - I just tested it out and it seems to work well - thanks for the tip :)

#6708 - niltsair - Mon Jun 02, 2003 3:54 am

Better yet, declare this code as inline or a define, you'll get better speed still (no function calling overhead)