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 > Newbie seeking some help

#117361 - jonathanc - Sun Feb 04, 2007 5:06 am

Hi there, letme first introduce a little about myself. Recently started a course in computing tech and I have to do a module on GBA programming. Very hectic and demanding module >< Well, I have really tried looking and asking around (some people are really selfish in sharing knowledge as this is a competitive course) but I am afraid I am getting no where :( So I turn to this forums for some help.

Ok, to the point then. I am supposed to write a basic macro or function for the devadvkit environment that takes a value between 0-31 and convert it into 16 bit bgr format (mode 3). I am supposed to use this macro to draw a yellow pixel in the middle of the screen and use the D pads to move it around the boundaries of the screen and also A and B buttons to change the colors.

I have read through millions of guides and tutorials but I still fail at producing a working example. I am wondering if anyone could give me some help here. Thanks and much appreciated!

I have found a method of using this code:
#include "toolbox.h"

int main()
{
REG_DISPCNT= DCNT_MODE3 | DCNT_BG2_ON;

m3_plot( 120, 80, RGB15(31, 31, 0) ); // or CLR_RED


while(1);

return 0;
}

which of course needs this header file:

// toolbox.h:

#ifndef TOOLBOX_H
#define TOOLBOX_H

// === (from types.h) ================================================

typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;

typedef u16 COLOR;

#define INLINE static inline

// === (from regs.h) ==================================================

#define MEM_IO 0x04000000
#define MEM_VRAM 0x06000000

#define REG_DISPCNT *((volatile u32*)(MEM_IO+0x0000))

// === (from vid.h) ===================================================

#define VID_WIDTH 240
#define VID_HEIGHT 160

#define vid_mem ((u16*)MEM_VRAM)

// --- some REG_DISPCNT #defines ---
#define _DCNT_MODE0 0x0000
#define DCNT_MODE1 0x0001
#define DCNT_MODE2 0x0002
#define DCNT_MODE3 0x0003
#define DCNT_MODE4 0x0004
#define DCNT_MODE5 0x0005
// layers
#define DCNT_BG0_ON 0x0100
#define DCNT_BG1_ON 0x0200
#define DCNT_BG2_ON 0x0400
#define DCNT_BG3_ON 0x0800
#define DCNT_OBJ_ON 0x1000

INLINE void m3_plot(int x, int y, COLOR clr)
{ vid_mem[y*VID_WIDTH+x]= clr; }

// === (from color.h) =================================================

#define CLR_BLACK 0x0000
#define CLR_RED 0x001F
#define CLR_LIME 0x03E0
#define CLR_YELLOW 0x03FF
#define CLR_BLUE 0x7C00
#define CLR_MAG 0x7C1F
#define CLR_CYAN 0x7FE0
#define CLR_WHITE 0x7FFF

INLINE COLOR RGB15(u32 rr, u32 gg, u32 bb)
{ return (rr&31) | ((gg&31)<<5) | ((bb&31)<<10); }

#endif // TOOLBOX_H

However, I am not sure if I am on the right track as I think I am required to write something in this format:

u16 BGR(u16 b, u16 g, u16 r);

Please advice as I am quite confused.

#117372 - Cearn - Sun Feb 04, 2007 11:40 am

jonathanc wrote:
I am supposed to write a basic macro or function for the devadvkit environment

Devkitpro is better. Time and professors permitting, use that devkit instead.

jonathanc wrote:
that takes a value between 0-31 and convert it into 16 bit bgr format (mode 3). I am supposed to use this macro to draw a yellow pixel in the middle of the screen and use the D pads to move it around the boundaries of the screen and also A and B buttons to change the colors.

I have found a method of using this code:
Code:
#include "toolbox.h"

int main()
{
    REG_DISPCNT= DCNT_MODE3 | DCNT_BG2_ON;

    m3_plot( 120, 80, RGB15(31, 31, 0) ); // or CLR_RED


    while(1);

    return 0;
}

This should already give you a yellow pixel in the middle of the screen (not red, change the comment after m3_plot() :P ). Is this what you see?
Also, if you want to keep the layout of your code, use the [code] tags.

Quote:
However, I am not sure if I am on the right track as I think I am required to write something in this format:

u16 BGR(u16 b, u16 g, u16 r);

Pretty much. But you already have a function like that, it's just called RGB15() instead of BGR(). Masking with 31 is just a safety measure; if you're sure no one's ever going to input values above 31, you can remove the '&31' parts. Plotting a mode-3 pixel at a specific position is done with m3_plot().

As for the rest ...
jonathanc wrote:
... and use the D pads to move it around the boundaries of the screen and also A and B buttons to change the colors.

The buttons are covered in a later chapter, the tribool functions in particular should be very useful. You could also start out with no interaction: just make a loop that update the x and y coordinates in some way and plot a new pixel. If you find that everything moves way too fast, well, there are ways around that too (hint: wait for VBlank).

While I could just give you the code, I'm not going to do that and I don't expect anyone else will either. This is not about being selfish -- it just that it is your assignment, not ours. We can help, but don't expect us to do your work for you. To that end, how much programming experience do you have, in general and in C, in particular?

#117421 - jonathanc - Sun Feb 04, 2007 8:36 pm

Quote:
However, I am not sure if I am on the right track as I think I am required to write something in this format:

u16 BGR(u16 b, u16 g, u16 r);

Pretty much. But you already have a function like that, it's just called RGB15() instead of BGR(). Masking with 31 is just a safety measure; if you're sure no one's ever going to input values above 31, you can remove the '&31' parts. Plotting a mode-3 pixel at a specific position is done with m3_plot().


[/quote]

yes I fully understand that, however I am wondering if I could use my pwn function instead of m3_plot? In other words, can I do this is a simple macro instead of requiring to call toolbox.h?


Quote:


While I could just give you the code, I'm not going to do that and I don't expect anyone else will either. This is not about being selfish -- it just that it is your assignment, not ours. We can help, but don't expect us to do your work for you. To that end, how much programming experience do you have, in general and in C, in particular?


yeah i know what you mean as well mate. I don't expect to be spoon fed but would require some kind of push start if you will >< Before this I am an engineering graduate hence very little experience in C programming and the like. I have to undertake this course due to career changes. As I am the oldest in the class, I dont actually mingle well with other classmates but I guess that is another matter. Thanks for your help anyway and I will see what I can do :(

#117439 - Cearn - Sun Feb 04, 2007 9:47 pm

jonathanc wrote:
Quote:
Quote:
However, I am not sure if I am on the right track as I think I am required to write something in this format:

u16 BGR(u16 b, u16 g, u16 r);

Pretty much. But you already have a function like that, it's just called RGB15() instead of BGR(). Masking with 31 is just a safety measure; if you're sure no one's ever going to input values above 31, you can remove the '&31' parts. Plotting a mode-3 pixel at a specific position is done with m3_plot().


yes I fully understand that, however I am wondering if I could use my own function instead of m3_plot? In other words, can I do this in a simple macro instead of requiring to call toolbox.h?

Sure, you can use a macro instead of an inline function. For example:
Code:
#define FrontBuffer ((u16*)0x06000000)

#define PlotPixel(x, y, color) FrontBuffer[(y)*240 + (x)] = (color)

Or you could use the m3_mem matrix notation further down in the chapter.
Code:

typedef u16 M3_LINE[240];

#define m3_mem  ((M3_LINE*)0x06000000)

#define m3_plot_a(x, y, color)  m3_mem[y][x]= (color)

The main idea will be the same though: store a halfword into a certain address. There's little you can vary aside from the names. The reason m3_plot() is an inline function instead of a macro is that inline functions are safer.
As for 'calling' toolbox.h. It's not really a call, just an access. The #include directive effectively copies the whole file into the one that uses it. If you wanted one file, you could also just copy-paste the entire contents of toolbox.h into your source file. Or just the parts you need.
The reason these kinds of things are stored in header files is so that they can be accessible in multiple files easily. Also, having simple macros and inlines in a separate file means they won't clutter up your source files.

jonathanc wrote:
Quote:
While I could just give you the code, I'm not going to do that and I don't expect anyone else will either. This is not about being selfish -- it just that it is your assignment, not ours. We can help, but don't expect us to do your work for you. To that end, how much programming experience do you have, in general and in C, in particular?


yeah i know what you mean as well mate. I don't expect to be spoon fed but would require some kind of push start if you will >< Before this I am an engineering graduate hence very little experience in C programming and the like. I have to undertake this course due to career changes. As I am the oldest in the class, I dont actually mingle well with other classmates but I guess that is another matter. Thanks for your help anyway and I will see what I can do :(


The reason I asked for the degree of C experience was to see where any help should be directed. The funny thing about programming is that the choice of language is often of secondary importance. The basic structure of a program is usually done in pseudo-code (English that looks like code, but wouldn't actually compile). This you should be able to do for your problem; afterwards we could translate that to valid C.

For example, suppose you needed to plot a path that changed randomly. In pseudo code it might look something like this:
Code:

function main
    Positions: x=120, y=80
    Velocities: vx=1, vy=0
    Color: color= yellow

    begin loop
        synchronize framerate

        // 10% chance of changing course
        if( random between (0, 99) < 10 )
            vx= random between (-1, 1);
            vy= random between (-1, 1);
        end if

        // update positions
        x= x + vx
        y= y + vy

        // PONDER: bounds checking?
       
        plot color at (x, y)
    end loop

end main

This can be implemented almost line for line in any modern language and on any system with a graphical interface. Do this for your own assignment and you're probably halfway done already.

As for keys, there is a register at 0x04000130 called REG_KEYINPUT which contains the 'up' keystates of all the buttons. To see whether or not a button is down, invert the bits and check the bit for the button. In C, that looks like this:
Code:

#define REG_KEYINPUT   (*(vu16*)0x04000130)

~REG_KEYINPUT & bit;

#117445 - jonathanc - Sun Feb 04, 2007 10:08 pm

ok so I played around with my code and came up with this:

Code:


#include "toolbox.h"
#include "core.h"
#include <string.h>
#include "keypad.h"



int main()
{
    REG_DISPCNT= DCNT_MODE3 | DCNT_BG2_ON;

    m3_plot( 120, 80, RGB15(31, 31, 0) );    // or CLR_RED
   

while(1)
{
    vid_vsync();
    // slowing down polling to make the changes visible
    if((frame & 7) == 0)
        key_poll();
    // check state of each button
    for(ii=0; ii<10; ii++)
    {
   clr= 0;
        btn= 1<<ii;
        if(key_is_down(KEY_RIGHT))
              x += dx;
        else if(key_is_down(KEY_LEFT))
              x -= dx;
}
frame++;



}


It is a very weak code I know but I am trying my best at the moment. Obviously there are few things wrong with it. I need to declare variables of ii, clr, btn, dx and x. I have played around with a few values but it just doesn't seem to work and makes me more confused. I know I must somehow link x to my pixel on the screen so tried m3_plot but came out as error. Please advice.

I have included my keypad.h header file as well. Funny thing is that I had to remove this to make it work
Code:
 // Polling function
INLINE void key_poll()
{
    __key_prev= __key_curr;
    __key_curr= ~REG_KEYS & KEY_MASK;
}
It just came out with syntax errors if I do not remove that line.

My keypad.h file :

Code:



extern u16 __key_curr, __key_prev;

#define KEY_A        0x0001
#define KEY_B        0x0002
#define KEY_SELECT   0x0004
#define KEY_START    0x0008
#define KEY_RIGHT    0x0010
#define KEY_LEFT     0x0020
#define KEY_UP       0x0040
#define KEY_DOWN     0x0080
#define KEY_R        0x0100
#define KEY_L        0x0200


#define KEY_MASK     0x03FF
#define REG_KEYS     0400:0130h
#define KEY_DOWN_NOW(key)  (~(REG_KEYS) & key)



// Basic state checks
INLINE u32 key_curr_state()         {   return __key_curr;          }
INLINE u32 key_prev_state()         {   return __key_prev;          }
INLINE u32 key_is_down(u32 key)     {   return  __key_curr & key;   }
INLINE u32 key_is_up(u32 key)       {   return ~__key_curr & key;   }
INLINE u32 key_was_down(u32 key)    {   return  __key_prev & key;   }
INLINE u32 key_was_up(u32 key)      {   return ~__key_prev & key;   }

enum eKeyIndex
{
    KI_A=0, KI_B, KI_SELECT, KI_START,
    KI_RIGHT, KI_LEFT, KI_UP, KI_DOWN,
    KI_R, KI_L
};

// --- TRISTATES ---
INLINE int key_tri_horz()       // right/left : +/-
{   return bit_tribool(__key_curr, KI_RIGHT, KI_LEFT);  }

INLINE int key_tri_vert()       // down/up : +/-
{   return bit_tribool(__key_curr, KI_DOWN, KI_UP);     }

INLINE int key_tri_shoulder()   // R/L : +/-
{   return bit_tribool(__key_curr, KI_R, KI_L);         }

INLINE int key_tri_fire()       // B/A : -/+
{   return bit_tribool(__key_curr, KI_A, KI_B);         }


I know the header file makes use of tribool functions but I rather leave that for later.

#124429 - beamer30 - Thu Apr 05, 2007 11:13 pm

What would you use to compile psuedo-code(by that i mean change it to c or c++)

#124430 - gmiller - Thu Apr 05, 2007 11:20 pm

You would not compile the pseudo-code you would just comment out the psuedo-code and put in the equivalent in the language of choice. Without understand a language and it's syntax the pseudo-code is as far as you can go.

#124433 - beamer30 - Thu Apr 05, 2007 11:38 pm

so you basically would have to manually change the psuedo-code theres not a program that can do it for you.(that would make life alot easier for n00bs)

#124436 - Lick - Thu Apr 05, 2007 11:52 pm

Beamer: pseudo code is written differently by everyone.

I might use something like:
Code:
print "Hello World";
which is accidentally valid PHP - while someone else might use this pseudo code:
Code:
write("Hello World");
//or
out << Hello + World


The point is, pseudo code is made human-readable and therefore more easily communicates the procedure. It is not real code.
_________________
http://licklick.wordpress.com

#124473 - sgeos - Fri Apr 06, 2007 5:29 am

Pseudocode is simplified code for humans. It leave out obvious details. This algorithm generates a maze:
Code:
generateMaze(pW, pH)
{
   initCellMap(pW, pH);
   unlinkAllCells();
   linkInitialCell(random cell);
   while (unlinked cells remain)
   {
      get(random unlinked cell);
      for (every direction)
         // link to adjact cell if it is linked
         tryToLink(cell);
   }
   return maze;
}

If either pW or pH is zero, initCellMap() fails, the maze generation fails, and an error should be issued. This is standard error checking. It is not relevant to the algorithm, so it is not listed. This line:
Code:
for (every direction)

Is clever way of saying that you can use this algorithm with any number of directions- 4, 6, 8... even 26 if you want to make a wild 3d maze. This pseudocode is simple, but code that works with any number of directions would either be complicated or have complicated instructions.

A working maze generation module would probably be 200+ lines out of the box. It also may not work with your code until you modify it. If you use a different programming lanuage, it will not work at all.

Code:
so you basically would have to manually change the psuedo-code theres not a program that can do it for you. (that would make life alot easier for n00bs)

Your job is to write code. Who cares if you are new(*) at this? Learn, get better and then do your job. =)

(*) "n00b" is not listed in the dictionary. I don't think any words in the dictionary have zeros in them.

-Brendan

#124530 - Miked0801 - Fri Apr 06, 2007 5:10 pm

Come one guys, we all know about the secret program that we use behind the scenes called 'makegame.exe'. You just drag a word or text document onto it and it spits out a game. No need for silly psuedo code, though it works with that as well :)

#124562 - keldon - Fri Apr 06, 2007 10:16 pm

Miked0801 wrote:
Come one guys, we all know about the secret program that we use behind the scenes called 'makegame.exe'. You just drag a word or text document onto it and it spits out a game. No need for silly psuedo code, though it works with that as well :)


Be careful what you say, there are people out there who might not spot it's a joke and start complaining about his google search for 'makegame.exe' ^.^

#124602 - sgeos - Sat Apr 07, 2007 4:17 am

keldon wrote:
Miked0801 wrote:
Come one guys, we all know about the secret program that we use behind the scenes called 'makegame.exe'. You just drag a word or text document onto it and it spits out a game. No need for silly psuedo code, though it works with that as well :)

Be careful what you say, there are people out there who might not spot it's a joke and start complaining about his google search for 'makegame.exe' ^.^

But makegame.exe is NDA prot... =)

-Brendan