Tutorial 4: Cursors

In this fourth Wii programming tutorial, I will cover displaying a cursor by drawing a small square, movement of the cursor and then using the Wii IR to move the cursor. Before reading this tutorial I’m assuming you have picked up a few things and therefore I won’t be re-explaining the common code in the zip file or initial steps in detail. You can grab the PDF of this tutorial here: codemii-tutorial-4

Firstly download this tutorial4-blank which will contain the required files to get us started. Extract this zip file in C:\devkitPro\examples\gamecube. Open up tutorial4.pnproj and then click on main.c to show the source code.

From tutorial 3, we know how to incorporate the controller in our source code, so now all we need to use a cursor in our application, is to draw one. The source code below is our drawing functions. I’m not sure whose code it but thanks to the person whom made it.

[sourcecode language=’c’]void DrawHLine (int x1, int x2, int y, int color) {
int i;
y = 320 * y;
x1 >>= 1;
x2 >>= 1;
for (i = x1; i <= x2; i++) { u32 *tmpfb = xfb; tmpfb[y+i] = color; } } void DrawVLine (int x, int y1, int y2, int color) { int i; x >>= 1;
for (i = y1; i <= y2; i++) { u32 *tmpfb = xfb; tmpfb[x + (640 * i) / 2] = color; } } void DrawBox (int x1, int y1, int x2, int y2, int color) { DrawHLine (x1, x2, y1, color); DrawHLine (x1, x2, y2, color); DrawVLine (x1, y1, y2, color); DrawVLine (x2, y1, y2, color); }[/sourcecode] Place the above code after the Initialise function. We will be calling the DrawBox function and passing 5 parameters to it. The parameters of DrawBox are the first x co-ordinate, the first y co-ordinate, the second x co-ordinate, the second y co-ordinate and the colour of the lines as shown below: [sourcecode language='c']DrawBox (5, 20, 50, 200, COLOR_WHITE); [/sourcecode] When drawing things on the screen, x = 0 and y = 0 means that we would be at the top left of the screen. If we put the following code as shown above, we would get a line that looks something like:

Once we call the DrawBox function, it breaks the square that we want to draw into 4 lines, which are 2 horizontal and 2 vertical lines. The DrawHLine and DrawVLine functions write to the frame buffer which will be displayed on the screen that we want a certain dot on the screen to be a certain colour. The loop is used so that we go through every dot that we want to change to a certain colour.

tutorial4-draw-square is the finished source code if you need it. Compile the source code (Alt + 1) and run the dol file with gcube. You should see a similar screen to the one shown below.

Moving the Cursor

We now wish to draw a smaller square which will represent our cursor. You can use something like:

[sourcecode language=’c’]DrawBox (300, 250, 301, 251, COLOR_WHITE); [/sourcecode]

Now that we’ve got our cursor set up, we need to be able to use the controls to move the cursor. To do this we need to use variables to control the cursor’s x and y co-ordinates on the screen.

We can have two variables, one for the x axis named cursor_x and one for the y axis named cursor_y. These variables will have the default value of 200 and 200, so that it’s near the centre of the screen.

[sourcecode language=’c’]int cursor_x = 300;
int cursor_y = 250; [/sourcecode]

The next thing to do is to capture the movement of the joystick, so when we move the joystick up or down it modifies the cursor_y variable and when we move it left or right it modifies the cursor_x variable. We can do this by either de-incrementing (subtracting 1) or incrementing (adding 1 to) the variables.

[sourcecode language=’c’]if (PAD_StickY(0) > 18) {
cursor_y–;
}
if (PAD_StickY(0) < -18) { cursor_y++; } if (PAD_StickX(0) > 18) {
cursor_x++;
}
if (PAD_StickX(0) < -18) { cursor_x--; }[/sourcecode] The -- means de-increment and the ++ means increment. As an example, if we move the joystick up, we would de-increment cursor_y. So if cursor_y was 200 and we moved the joystick up, cursor_y’s value would be 199. All that’s left now is to change where the image is being displayed every time we move the cursor. This is easily accomplished by using our variables with the DrawBox function as shown below: [sourcecode language='c']DrawBox (cursor_x, cursor_y, cursor_x + 1, cursor_y + 1, COLOR_WHITE); [/sourcecode] What we’ve done is used our cursor_x and cursor_y in place instead of the 300 (x1) and 250 (y1) values and have added 1 to the cursor to that the values will be 301 (x2) and 251 (y2) in order to draw a square. The next thing to do is to clear the screen to black before showing the cursor and then using waiting for vertical sync. The reason we are clearing the screen is so that our cursor is cleared every time we move it. If we didn’t clear the screen, then you will see the movement of the cursor stay on the screen. The code below shows the complete controller code in a while loop with the screen being cleared: [sourcecode language='c']int cursor_x = 300; int cursor_y = 250; while(1) { PAD_ScanPads(); if (PAD_StickY(0) > 18) {
cursor_y–;
}
if (PAD_StickY(0) < -18) { cursor_y++; } if (PAD_StickX(0) > 18) {
cursor_x++;
}
if (PAD_StickX(0) < -18) { cursor_x--; } VIDEO_ClearFrameBuffer (rmode, xfb, COLOR_BLACK); DrawBox (cursor_x, cursor_y, cursor_x + 1, cursor_y + 1, COLOR_WHITE); VIDEO_WaitVSync(); }[/sourcecode] The reason behind placing VIDEO_ClearFrameBuffer before DrawBox is so we don’t clear the screen and then waste time doing other functions and then draw the cursor. If you had a lot of code which took a considerable amount of time to execute, you wouldn’t see your cursor all of the time and it would be blinking. Instead we do the functions, clear the screen, draw the cursor and repeat the while loop, so therefore the cursor will stay on the screen all the time. tutorial4-moving-cursor is what our source now looks like. Go ahead and re-compile the source and run the dol with gcube and use the Numpad up, down, left and right to move the small square which is our cursor.

Converting source to use Wii IR

We are now good to change our project to compile on the Wii instead of the gamecube. As per the last tutorial open your makefile and change the gamecube_rules to wii_rules in line that reads:
[sourcecode language=’c’]include $(DEVKITPPC)/gamecube_rules[/sourcecode]

Add the Wii and the Bluetooth libraries to our compiler as shown below:
[sourcecode language=’c’]LIBS := -lwiiuse -lbte -logc -lm[/sourcecode]

In main.c include section include the wiiuse file:
[sourcecode language=’c’]#include [/sourcecode]

As usual we will need to add a W in front of all the PAD_ commands and remove references to PAD_Substick.

When using the Wiimote, we firstly have to tell the system that we want to capture all the Wiimote’s functionality which includes the Infra-red (IR) and the accelerometer. Another thing to tell the system is the resolution we want to bound the IR to. Both these commands are shown below and should be after the WPAD_Init function:

[sourcecode language=’c’]WPAD_SetVRes(0, 640, 480);
WPAD_SetDataFormat(WPAD_CHAN_0, WPAD_FMT_BTNS_ACC_IR); [/sourcecode]

The Wiimote’s IR has a data structure which tells us things like are the co-ordinates valid, the x and y axis, the rotation and so forth. This information can be found in “C:\devkitPro\libogc\include\wiiuse\wiiuse.h”.

We need to assign a variable to hold this data structure. We do this by naming the data structure which is ir_t and then assigning that data structure to our variable which is ir. The code below needs to be placed below the #includes which are at the top.

The reason we place the variable up the top is so that our variable will be a global which means it can be called and accessed from anywhere within our source code. If we were to assign it within a function, then the variable would only exist whilst inside that function and could not be called from anywhere else.

[sourcecode language=’c’]ir_t ir; [/sourcecode]

So now that we have assigned ir as the data structure ir_t, we need to constantly update the ir variable to get the latest readings from the Wiimote. This is done by using the below code:

[sourcecode language=’c’]WPAD_IR(0, &ir); [/sourcecode]

We are updating channel 0 (the first Wiimote’s) IR data and feeding all that information into our ir variable.

The final step involved is to change the variables in the DrawBox function to use ir.x and ir.y instead of cursor_x and cursor_y. As you recall ir is our variable which contains different data structures, one of them being the x and y co-ordinates. As these are like variables in the ir variable, we reference them by using a dot between our main variable (ir) and the data structure variable (ir.x or ir.y).

[sourcecode language=’c’]DrawBox (ir.x, ir.y, ir.x + 1, ir.y + 1, COLOR_WHITE); [/sourcecode]

We can remove the cursor_x and cursor_y variables. The while loop looks as shown below:

[sourcecode language=’c’]while(1) {

WPAD_ScanPads();
u32 pressed = WPAD_ButtonsDown(0);

// IR Movement
WPAD_IR(0, &ir);

if (pressed & WPAD_BUTTON_HOME) {
exit(0);
}

VIDEO_ClearFrameBuffer (rmode, xfb, COLOR_BLACK);

DrawBox (ir.x, ir.y, ir.x + 1, ir.y + 1, COLOR_WHITE);

VIDEO_WaitVSync();
}[/sourcecode]

tutorial4-wii-ir is what our source now looks like. Clean the source code, re-compile and tutorialr.elf to boot.elf and place it in a directory called tutorialr under the /apps/ directory of your SD card and load it with the homebrew channel. You will be able to control the dot on your screen with the Wiimote.

34 Responses to “Tutorial 4: Cursors”

  1. Fennec says:

    Great work on these tutorials. They are really helping me develop my own wii homebrew. Keep up the awesome work.

  2. Jake says:

    Great tutorials! I started out with knowing nothing but these tutorials actually make sense and make you learn! Good stuff!

  3. Speggy says:

    there’s really are great but could you add more code sections as i was left wondering how you got from

    PAD_ScanPads();

    if (PAD_StickY(0) > 18) {
    cursor_y–;
    }
    if (PAD_StickY(0) 18) {
    cursor_x++;
    }
    if (PAD_StickX(0) < -18) {
    cursor_x–;
    }

    to

    WPAD_ScanPads();
    u32 pressed = WPAD_ButtonsDown(0);

    // IR Movement
    WPAD_IR(0, &ir);

    if (pressed & WPAD_BUTTON_HOME) {
    exit(0);
    }

    as i left all the Stick X/Y areas and simply changed them to WPAD until i saw the next set of code

  4. teknecal says:

    All the PAD_Substick functions are related to the Gamecube, as the Wiimote has no joystick we remove these Substick commands. For more in depth information about the “pressed” variable and the WPAD_BUTTON_HOME you need to read the programming tutorial 3 – http://www.codemii.com/2008/08/24/tutorial-3-controller-input/

  5. Speggy says:

    i’ve read all of them, it’s just you never mentioned removing the the Substick Commands Just to change PAD to WPAD

  6. lakotajames says:

    Speggy: He did mention removing the substick commands. In tutorial 3, he said that the wii has no sticks so you have to remove the stick commands if you use wiimode. When he said, “We are now good to change our project to compile on the Wii instead of the gamecube,” he assumed that you had read tutorial 3 and knew to remove the commands before you compile.

  7. nathan says:

    I was looking forward to making some wiibrew, but noticed that the thumbstick on the nunchuck is not supported? What’s that about? How come the IR was figured out, but not the thumbstick?

  8. teknecal says:

    The nunchuck has been figured out and can be used in Masteroids. I just haven’t gotten around to using it to be able to put it in the tutorials.

  9. nathan says:

    I also don’t see it in the wpad.h include file

    #define WPAD_NUNCHUK_BUTTON_Z (0x0001<<16)
    #define WPAD_NUNCHUK_BUTTON_C (0x0002<<16)

    That’s it for the nunchuck!

  10. teknecal says:

    You can have a read of this topic that has example nunchuck code: http://forum.wiibrew.org/read.php?11,1334

  11. Deozaan says:

    I like your tutorials. They’re a little confusing though because you introduce new code to type in but you don’t always say where it belongs.

    Thanks for what you’re doing!

  12. Ibrahim says:

    Hi, I was reading your tutorials and they’re pretty nice, so far they’re the only tutorials I can find on Wii development. One thing I was wondering though, you don’t have any error checking code for if the cursor goes off screen, if you try writing to the framebuffer at a negative value won’t that mess with the RAM or something? I haven’t done much C programming, mostly Java, so this stuff is useful for me to learn the Wii stuff since the syntax is more or less the same between C and Java. Thanks again, and hopefully you’ll see some releases from me in the not too distant future.

  13. teknecal says:

    I do recall once that I did get a codedump on the Wii by going too far left or right. Easiest way would be to just change it a bit.

    if (PAD_StickY(0) > 18 && cursor_y > 0) {
    cursor_y–;
    }
    if (PAD_StickY(0) < -18 && cursor_y < 480) { cursor_y++; } etc.

  14. chris says:

    Souldn’t the line xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode)); be xfb = (u32*)MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode));?
    As far as I know xfb is of the type u32* while MEM_K0_TO_K1 returns void*, which should be cast to u32* in order to assign it to xfb.
    While your code seems to work in C, changing it as I suggested will fix compatibility to C++.

  15. AndyTheAngel says:

    Hi! I tryed to modify the code so the cursor leaves a line on the screen, and to use the A button so everytime I press it the cursor change color between 3 programmed colours.
    I obtained the line on the screen, but not the change of colour: it starts in red, when I press A it should change to gray, but it change directly to Blue, and I can’t change it anymore. Here is the code (hope you can explain me where I am wrong…):

    int main() {

    Initialise();

    int color = COLOR_RED;

    while(1){
    WPAD_ScanPads();

    u32 pressed = WPAD_ButtonsDown(0);
    WPAD_IR(0, &ir);

    if(pressed & WPAD_BUTTON_HOME){
    exit(0);
    }

    u32 ButtonUp = WPAD_ButtonsUp(0);
    if(ButtonUp & WPAD_BUTTON_A){
    if(color == COLOR_BLUE){
    color = COLOR_RED;
    }
    if(color == COLOR_RED){
    color = COLOR_GRAY;
    }
    if(color == COLOR_GRAY){
    color = COLOR_BLUE;
    }
    }

    /*VIDEO_ClearFrameBuffer (rmode, xfb, COLOR_BLACK);*/
    DrawBox (ir.x,ir.y,ir.x+1,ir.y+1,color);

    VIDEO_WaitVSync();
    }
    return 0;
    }

  16. teknecal says:

    Hi,

    The problem is your if statements. You need to use if and else if statements instead as currently it just executes all the if statements when you press the button.

    Using if and else if just means it will either execute only one if statement in the lot of if and else if statements.

    if(color == COLOR_BLUE){
    color = COLOR_RED;
    }
    else if(color == COLOR_RED){
    color = COLOR_GRAY;
    }
    else if(color == COLOR_GRAY){
    color = COLOR_BLUE;
    }

  17. AndyTheAngel says:

    By the way, another question… I’ve read all your previous tutorials, but I can’t find anywhere what type of variables are u32 and u16… Can you rapidly explain it, please?

  18. Jacic says:

    Great tut! The only thing i could suggest is to include more about where to put the code, i was confused at first. Also, I think the download with the gamecube stick moving the dot is the wrong link, it looks just like the part of the tut just before we make it able to move.

  19. kedest says:

    what are
    x1 >>= 1;
    x2 >>= 1;
    for in the line functions?

    • teknecal says:

      I’ve never really taken a good look at that but it’s a bitwise operator that shifts all the bits x times to the right. I’ve never had to use this one myself.

      For example:
      An integer (x) with a value of 5 would have the bits 00000101.
      Doing x >>= 1 would make that value 00000010. It has just moved all the bits one to the right.

      For more information you can check this link.

  20. north says:

    Hello,

    I downloaded the Gamecube project to test out, tutorial4-moving-cursor
    and when I clean/make then try to run, I’m getting this error:

    > “make” run
    psoload tutorial4.dol
    “make”: psoload: Command not found
    “make”: *** [run] Error 127

    > Process Exit Code: 2
    > Time Taken: 00:00

    I’ve been able to run the template file no prob, just can’t get past this for this example.

    Any suggestions? The tutorials are great by the way

    -north

    • teknecal says:

      If you are running it on the gamecube, you can just open up the dol file directly and then assign it to open with the gcube program found in devkitPro\emulators\gcube,

      For the Wii, you can download/copy wiiload.exe to your tutorial4 directory and then change the run part of the makefile to read:

      run:
      wiiload $(TARGET).dol

  21. Michele says:

    Doing this:

    For the Wii, you can download/copy wiiload.exe to your tutorial4 directory and then change the run part of the makefile to read:

    run:
    wiiload $(TARGET).dol

    I get (on the hbc) the message that’s not a valid wii application?!
    This happen for the next tutorial too!

    Any idea?

  22. n0phear says:

    Hi.
    Thanks so much for these tuorials. I am a developer and am just starting to write apps for the wii.

    I would appreciate to have an article on how to download a file (an xml file for exemple) from the wifi connection. I am sure it would be simple to use the cURL library for this, and how to manage exceptions such as : the internet connexion isn’t configured, the connexion is broken, etc…

  23. BLUWAK says:

    Is there a way to change the dot to a JPEG image?

  24. h0ffman says:

    Great tutorials, I recently started learning C# .BLOAT so this stuff is really similar. Thought I would do a little amendment so when you press and hold the A button on the WiiMote, it draws a box..

    int main() {

    Initialise();

    WPAD_Init();

    WPAD_SetVRes(0, 640, 480);
    WPAD_SetDataFormat(WPAD_CHAN_0, WPAD_FMT_BTNS_ACC_IR);

    int nCursX = 0;
    int nCursY = 0;

    while(1) {

    WPAD_ScanPads();

    u32 pressed = WPAD_ButtonsDown(0);
    u32 held = WPAD_ButtonsHeld(0);

    if (pressed & WPAD_BUTTON_HOME){
    exit(0);};

    WPAD_IR(0, &ir);

    if (pressed & WPAD_BUTTON_A){
    nCursX = ir.x;
    nCursY = ir.y;
    };

    VIDEO_ClearFrameBuffer (rmode, xfb, COLOR_BLACK);

    if (held & WPAD_BUTTON_A){
    DrawBox (nCursX, nCursY, ir.x, ir.y, COLOR_WHITE);
    }
    else{
    DrawBox (ir.x, ir.y, ir.x + 1, ir.y + 1, COLOR_WHITE);};

    VIDEO_WaitVSync();
    };
    return 0;
    }

  25. Dudester says:

    Help!

    ain.c
    linking … tutorial4.elf
    main.o: In function `Initialise’:
    c:/devkitPro/examples/wii/tutorial4/source/main.c:18: undefined reference to `WPAD_Init’
    c:/devkitPro/examples/wii/tutorial4/source/main.c:19: undefined reference to `WPAD_SetVRes’
    c:/devkitPro/examples/wii/tutorial4/source/main.c:20: undefined reference to `WPAD_SetDataFormat’
    main.o: In function `main’:
    c:/devkitPro/examples/wii/tutorial4/source/main.c:69: undefined reference to `WPAD_ScanPads’
    c:/devkitPro/examples/wii/tutorial4/source/main.c:70: undefined reference to `WPAD_ButtonsDown’
    c:/devkitPro/examples/wii/tutorial4/source/main.c:73: undefined reference to `WPAD_IR’
    collect2.exe: error: ld returned 1 exit status
    make[1]: *** [/c/devkitPro/examples/wii/tutorial4/tutorial4.elf] Error 1
    “make”: *** [build] Error 2

  26. someonewhoprograms says:

    I do not know what this means…
    main.c
    C:/devkitPro/examples/gamecube/tutorial4/source/main.c:65:2: error: expected ‘;’, identifier or ‘(‘ before ‘void’
    65 | void spawner (int x, int y) {
    | ^~~~
    C:/devkitPro/examples/gamecube/tutorial4/source/main.c: In function ‘spawner’:
    C:/devkitPro/examples/gamecube/tutorial4/source/main.c:74:1: error: ‘particle’ undeclared (first use in this function); did you mean ‘particles’?
    74 | particle[k].x = x;
    | ^~~~~~~~
    | particles
    C:/devkitPro/examples/gamecube/tutorial4/source/main.c:74:1: note: each undeclared identifier is reported only once for each function it appears in
    C:/devkitPro/examples/gamecube/tutorial4/source/main.c:69:23: warning: unused variable ‘particles’ [-Wunused-variable]
    69 | struct ParticleStruct particles[i];
    | ^~~~~~~~~
    make[1]: *** [/opt/devkitpro/devkitPPC/base_rules:18: main.o] Error 1
    make: *** [Makefile:100: build] Error 2

    by the way…
    This is not the actual tutorial, this is just a program i made

Leave a Reply for lakotajames