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 > C loops on GBA

#171724 - cy.bear - Thu Dec 17, 2009 5:53 pm

Hi,
eventhough i'm not new to programming (not that skilled in c though) loops on the gba are giving me a hard time.

First thing i don't really understand: I'm using mode 4 on BG2 and want to display an image in fullscreen. (The image was converted using dovoto's pcx2gba, result header file contains 1 palette and 1 (1d) data array).

I load the palette using:
Code:

   int x, y;
   for(x = 0; x < 256; x++)
      paletteMem[x] = titlePalette[x];


For drawing (fullscreen; 240 x 160 px) I use:

Code:

   for(y = 0; y < 160; y++){
      for(x = 0; x < 240/2; x++){
         plotPixel(x,y,titleData[y*240/2+x]);
      }
   }


I know this works (works really great actually) but i don't see why I have to half the width of my screen. I read somewhere that the GBA writes 2 pixels at once. But that doesn't really make sense as it would only show half of the picture then anyway.
The loops say "for each line of all 160 and half of the elements per line draw the specified pixel".

Does every entry in my data array specify two pixels? how would i draw an uneven number of pixels then?

Second thing that goes terribly wrong: I want to crete a 2d array as a map. I have tiles of type int defined as tileWall and tileFloor. (Tilesize 16x16px so 15 x 10 for fullscreen).
i have a map[][] array (large enough). And supply values mapHeight and mapWidth. To generate the map I use the following code:

Code:

for(y = 0; y < mapHeight; y++){
   for(x = 0; x < mapWidth; x++){
      if(y == 0 || y == mapHeight-1 || x == 0 || x == mapWidth-1){
         // tile is border make it a wall
         map[y][x] = tileWall;
      } else if(y == 1 || y == (mapHeight -2) || x == 1 || x == (mapWidth -2)){
         // tile next to outer border, so it's a floor
         map[y][x] = tileFloor;
      } else {
         // decide randomly if tile is to be wall or floor (about 1/3 walls)
         // for now: floor
         map[y][x] = tileFloor;
      }
      
   }
}


The map is supposed to look like this * <- wall

Quote:
***************
*.............*
*.............*
*.............*
*.............*
*.............*
*.............*
*.............*
*.............*
***************


Yet the output is terribly crippled: [Images not permitted - Click here to view it]

I think the drawing code could also be responsible for this result so here it is:
Code:
int xOffset = 0;
int yOffset = 0;
const u16 * graphxData;
for(y=0; y < lastMapHeight; y++){
   for(x=0; x < lastMapWidth; x++){
      switch (map[y][x]){
         case tileFloor:   ;
                     graphxData = floorData;
                     break;
         case tileWall:   ;
                     graphxData = wallData;
                     break;
         default:      ;
                     graphxData = blankData;
                     break;
      }
      
      
      int tileData_x, tileData_y;
      for(tileData_y = 0; tileData_y < tileHeight; tileData_y++){
         for(tileData_x = 0; tileData_x < tileWidth/2; tileData_x++){
            plotPixel(tileData_x+xOffset, tileData_y+yOffset, graphxData[tileData_y*tileWidth/2 +tileData_x]);
         }
      }
      xOffset += tileWidth;
   }
   xOffset = 0;
   yOffset += tileHeight;
}


Any ideas about my problem? Any references to tutorials, websites ?
I'm glad about everything that can help me.

Thanks in advance and greetings
cy

PS: Already spent hours searching ;)

EDIT: Forgot to mention that plotPixel is as simple as this:
Code:

void plotPixel(int x,int y, unsigned short int c){
   videoBuffer[(y) *120 + (x)] = (c);
}


Just noticed that this also sees lines of 120 which supports the assumption that image data array holds info on 2px width for each entry.


Last edited by cy.bear on Thu Dec 17, 2009 6:20 pm; edited 1 time in total

#171726 - DiscoStew - Thu Dec 17, 2009 6:19 pm

With the format you are using, you are displaying an 8-bit image, which has a palette of up to 256 colors, and each pixel is 1 byte each. The reason why you must write 2 pixels at once is because the VRAM doesn't allow 1-byte writes to it, so you must use 2 byte writes, which means you end up writing 2 pixels each time. The data of the image itself is most likely in the format of 2 bytes per array element, so to ensure that it works, you dividing the width of the array by the element size, which is 2.

Hope that helps. I'll see what I can do about your other questions later, but for now, I got to study for a final.
_________________
DS - It's all about DiscoStew

#171727 - cy.bear - Thu Dec 17, 2009 6:33 pm

OK, that explains the thing quite good. Thank you.

Addition to the second Problem: The screenshot shows 2 things i don't really understand.
1) every second column of tiles starts drawing at y = 1.
2) the rightmost line of walls should be in the last column. The weird thing here is that the conditions for bottom line of walls and for right column of walls are identical (except for x / y of course).

EDIT:
Another screenshot. In this version the thrid case (which should pick a tile randomly) in the map generate code is changed so a black tile is used instead of a floor.

Result: [Images not permitted - Click here to view it]

#171728 - DiscoStew - Thu Dec 17, 2009 8:14 pm

Took me a bit to understand the situation, but I believe a single change will fix this.

Code:
Change
   xOffset += tileWidth;
to
   xOffset += tileWidth / 2;


The reasoning behind this is because, as was said before, writing to the videoBuffer can only be done 2 bytes at a time, so therefore, to fix some problems, you divide the width by that much. but, when you increment the xOffset by tileWidth, you are actually incrementing it by a total of 32 pixels instead of 16. Remember, videoBuffer is 2 bytes per element, so 16 * 2 = 32.

What is happening in your program is that you end up skipping every other horizontal tile because of this, and because the buffer wraps across the screen every 240 pixels (120 bytes), it causes the rest of your tiles being written to be pushed down by 1 pixel, and this is also causing the odd ordering of your tiles (specifically your right wall).

Code:
This is how it should look like
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14

This is what your program is doing
00    01    02    03    04    05    06    07   
   08    09    10    11    12    13    14

but because wrapping over just increments by 1 pixel vertically, it almost looks like this
00 08 01 09 02 10 03 11 04 12 05 13 06 14 07


So, just make that simple change, and it should look fine.
_________________
DS - It's all about DiscoStew

#171730 - cy.bear - Thu Dec 17, 2009 8:20 pm

wow. You're right, that just fixed it.
Thanks again.
Never would have thought that it was just a single line.