Page 1 of 1

A nudge in the right direction, please [crappy menu system]

Posted: Sat Jan 17, 2009 3:31 pm
by LBGSHI
This is primarily for testing, and so I can toy around with a skeleton menu system, before I improve all the inefficient functions and redundancies, and remake this almost entirely from scratch again. However, I still really need to know what the hell is going wrong here, heh. Here is the source to skeleton.c, a simple menu system:

Code: Select all

/*skeleton.c

Very badly designed skeleton GUI for Artemis (raw, hacky, scr_printf text on a black background, and
	screen transitions via init_scr(). Just something to get the ball rolling.) Borrowed
	scandalously (heh) from Pukko's padlib - many thanks to him for providing it, and for everyone else's
	work in improving it. Enjoy, and please - make something better!
	
					- Lazy Bastard
																				*/
				

#include <tamtypes.h>
#include <kernel.h>
#include <sifrpc.h>
#include <loadfile.h>
#include <stdio.h>
#include <debug.h>

#include "libpad.h"

#define ROM_PADMAN

#if defined&#40;ROM_PADMAN&#41; && defined&#40;NEW_PADMAN&#41;
#error Only one of ROM_PADMAN & NEW_PADMAN should be defined!
#endif

#if !defined&#40;ROM_PADMAN&#41; && !defined&#40;NEW_PADMAN&#41;
#error ROM_PADMAN or NEW_PADMAN must be defined!
#endif

static char padBuf&#91;256&#93; __attribute__&#40;&#40;aligned&#40;64&#41;&#41;&#41;;

static char actAlign&#91;6&#93;;
static int actuators;


int menuNumber;

void mainMenuS&#40;&#41; &#123;
	init_scr&#40;&#41;;

    scr_printf&#40;"\n\n\n\n\n          Project Artemis\n\n"
               "          Welcome to the Project Artemis &#40;terrible&#41; skeleton GUI.\n\n\n\n"
               "         *Start Game\n\n"
               "          Options\n\n"&#41;;
               menuNumber = 1;
			&#125;
			
void mainMenuO&#40;&#41; &#123;
	init_scr&#40;&#41;;

    scr_printf&#40;"\n\n\n\n\n          Project Artemis\n\n"
               "          Welcome to the Project Artemis &#40;terrible&#41; skeleton GUI.\n\n\n\n"
               "          Start Game\n\n"
               "         *Options\n\n"&#41;;
                menuNumber = 2;
			&#125;

void startMenu1&#40;&#41; &#123;
	init_scr&#40;&#41;;
	scr_printf&#40;"\n\n\n\n\n          Welcome to the &#40;terrible&#41; Start menu.\n\n\n\n"
				"         *Choice 1\n\n"
				"          Choice 2\n\n"
				"          Choice 3\n\n"&#41;;
				menuNumber = 3;		
			&#125;	
			
void startMenu2&#40;&#41; &#123;
	init_scr&#40;&#41;;
	scr_printf&#40;"\n\n\n\n\n          Welcome to the &#40;terrible&#41; Start menu.\n\n\n\n"
				"          Choice 1\n\n"
				"         *Choice 2\n\n"
				"          Choice 3\n\n"&#41;;
				menuNumber = 4;
			&#125;
			
void startMenu3&#40;&#41; &#123;
	init_scr&#40;&#41;;
	scr_printf&#40;"\n\n\n\n\n          Welcome to the &#40;terrible&#41; Start menu.\n\n\n\n"
				"          Choice 1\n\n"
				"          Choice 2\n\n"
				"         *Choice 3\n\n"&#41;;
				menuNumber = 5;
			&#125;
			
void optionsMenu1&#40;&#41; &#123;
	init_scr&#40;&#41;;
	scr_printf&#40;"\n\n\n\n\n          Welcome to the &#40;terrible&#41; Options menu.\n\n\n\n"
				"         *Choice 1\n\n"
				"          Choice 2\n\n"
				"          Choice 3\n\n"&#41;;
				menuNumber = 6;
			&#125;
			
void optionsMenu2&#40;&#41; &#123;
	init_scr&#40;&#41;;
	scr_printf&#40;"\n\n\n\n\n          Welcome to the &#40;terrible&#41; Options menu.\n\n\n\n"
				"          Choice 1\n\n"
				"         *Choice 2\n\n"
				"          Choice 3\n\n"&#41;;
				menuNumber = 7;
			&#125;
			
void optionsMenu3&#40;&#41; &#123;
	init_scr&#40;&#41;;
	scr_printf&#40;"\n\n\n\n\n          Welcome to the &#40;terrible&#41; Options menu.\n\n\n\n"
				"          Choice 1\n\n"
				"          Choice 2\n\n"
				"         *Choice 3\n\n"&#41;;
				menuNumber = 8;
			&#125;
			
			


/*
 * Local functions
 */

/*
 * loadModules&#40;&#41;
 */
void
loadModules&#40;void&#41;
&#123;
    int ret;

    
#ifdef ROM_PADMAN
    ret = SifLoadModule&#40;"rom0&#58;SIO2MAN", 0, NULL&#41;;
#else
    ret = SifLoadModule&#40;"rom0&#58;XSIO2MAN", 0, NULL&#41;;
#endif
    if &#40;ret < 0&#41; &#123;

        SleepThread&#40;&#41;;
    &#125;    

#ifdef ROM_PADMAN
    ret = SifLoadModule&#40;"rom0&#58;PADMAN", 0, NULL&#41;;
#else
    ret = SifLoadModule&#40;"rom0&#58;XPADMAN", 0, NULL&#41;;
#endif 
    if &#40;ret < 0&#41; &#123;
  
        SleepThread&#40;&#41;;
    &#125;
&#125;

/*
 * waitPadReady&#40;&#41;
 */
int waitPadReady&#40;int port, int slot&#41;
&#123;
    int state;
    int lastState;
    char stateString&#91;16&#93;;

    state = padGetState&#40;port, slot&#41;;
    lastState = -1;
    while&#40;&#40;state != PAD_STATE_STABLE&#41; && &#40;state != PAD_STATE_FINDCTP1&#41;&#41; &#123;
        if &#40;state != lastState&#41; &#123;
            padStateInt2String&#40;state, stateString&#41;;
    
                  
        &#125;
        lastState = state;
        state=padGetState&#40;port, slot&#41;;
    &#125;
    // Was the pad ever 'out of sync'?
    if &#40;lastState != -1&#41; &#123;
     
    &#125;
    return 0;
&#125;


/*
 * initializePad&#40;&#41;
 */
int
initializePad&#40;int port, int slot&#41;
&#123;

    int ret;
    int modes;
    int i;

    waitPadReady&#40;port, slot&#41;;

    // How many different modes can this device operate in?
    // i.e. get # entrys in the modetable
    modes = padInfoMode&#40;port, slot, PAD_MODETABLE, -1&#41;;
   

    if &#40;modes > 0&#41; &#123;
      
        for &#40;i = 0; i < modes; i++&#41; &#123;
            
        &#125;
       
    &#125;

  

    // If modes == 0, this is not a Dual shock controller 
    // &#40;it has no actuator engines&#41;
    if &#40;modes == 0&#41; &#123;
	    
        return 1;
    &#125;

    // Verify that the controller has a DUAL SHOCK mode
    i = 0;
    do &#123;
        if &#40;padInfoMode&#40;port, slot, PAD_MODETABLE, i&#41; == PAD_TYPE_DUALSHOCK&#41;
            break;
        i++;
    &#125; while &#40;i < modes&#41;;
    if &#40;i >= modes&#41; &#123;
        
        return 1;
    &#125;

    // If ExId != 0x0 => This controller has actuator engines
    // This check should always pass if the Dual Shock test above passed
    ret = padInfoMode&#40;port, slot, PAD_MODECUREXID, 0&#41;;
    if &#40;ret == 0&#41; &#123;
       
        return 1;
    &#125;

 

    // When using MMODE_LOCK, user cant change mode with Select button
    padSetMainMode&#40;port, slot, PAD_MMODE_DUALSHOCK, PAD_MMODE_LOCK&#41;;

    waitPadReady&#40;port, slot&#41;;
 

    actuators = padInfoAct&#40;port, slot, -1, 0&#41;;
 

    if &#40;actuators != 0&#41; &#123;
        actAlign&#91;0&#93; = 0;   // Enable small engine
        actAlign&#91;1&#93; = 1;   // Enable big engine
        actAlign&#91;2&#93; = 0xff;
        actAlign&#91;3&#93; = 0xff;
        actAlign&#91;4&#93; = 0xff;
        actAlign&#91;5&#93; = 0xff;

        waitPadReady&#40;port, slot&#41;;
        
    &#125;
    else &#123;
        
    &#125;

    waitPadReady&#40;port, slot&#41;;

    return 1;
&#125;





int
main&#40;&#41;
&#123;
    int ret;
    int port, slot;
    int i;
    struct padButtonStatus buttons;
    u32 paddata;
    u32 old_pad = 0;
    u32 new_pad;


    SifInitRpc&#40;0&#41;;
    
    mainMenuS&#40;&#41;; /*Load main menu text*/
    


    loadModules&#40;&#41;;

    padInit&#40;0&#41;;



    port = 0; // 0 -> Connector 1, 1 -> Connector 2
    slot = 0; // Always zero if not using multitap

   

    
    if&#40;&#40;ret = padPortOpen&#40;port, slot, padBuf&#41;&#41; == 0&#41; &#123;
        
        SleepThread&#40;&#41;;
    &#125;
    
    if&#40;!initializePad&#40;port, slot&#41;&#41; &#123;

	         SleepThread&#40;&#41;;
    &#125;
    
    for &#40;;;&#41; &#123;                /*Infinite loop to detect pad state*/
            
        i=0;
        ret=padGetState&#40;port, slot&#41;;
        while&#40;&#40;ret != PAD_STATE_STABLE&#41; && &#40;ret != PAD_STATE_FINDCTP1&#41;&#41; &#123;
            if&#40;ret==PAD_STATE_DISCONN&#41; &#123;

	                        &#125;
            ret=padGetState&#40;port, slot&#41;;
        &#125;
        if&#40;i==1&#41; &#123;
        &#125;
            
        ret = padRead&#40;port, slot, &buttons&#41;; // port, slot, buttons
            
        if &#40;ret != 0&#41; &#123;
            paddata = 0xffff ^ buttons.btns;
                
            new_pad = paddata & ~old_pad;
            old_pad = paddata;
                
            
            
            
            // Directions
            if&#40;new_pad & PAD_LEFT&#41; &#123;
            &#125;
            
            if&#40;new_pad & PAD_RIGHT&#41; &#123;
            &#125;           
            
            if&#40;&#40;new_pad & PAD_UP&#41; && &#40;menuNumber == 2&#41;&#41; &#123;
	            mainMenuS&#40;&#41;;
	    
            &#125;
                       
            if&#40;&#40;new_pad & PAD_UP&#41; && &#40;menuNumber == 4&#41;&#41; &#123;
	            startMenu1&#40;&#41;;
	            
            &#125;
            
            if&#40;&#40;new_pad & PAD_UP&#41; && &#40;menuNumber == 5&#41;&#41; &#123;
	            startMenu2&#40;&#41;;
	            
	            
	            
	            
            &#125;
                       
            if&#40;&#40;new_pad & PAD_UP&#41; && &#40;menuNumber == 7&#41;&#41; &#123;
	            optionsMenu1&#40;&#41;;	
	            
	            
	            
	                    
            &#125;
            
            if&#40;&#40;new_pad & PAD_UP&#41; && &#40;menuNumber == 8&#41;&#41; &#123;
	            optionsMenu2&#40;&#41;;
	            
	            
	            
	            
            &#125;
                        
            if&#40;&#40;new_pad & PAD_DOWN&#41; && &#40;menuNumber == 1&#41;&#41; &#123;
	            mainMenuO&#40;&#41;;
	            
	            
	            
	            
            &#125;
                       
            if&#40;&#40;new_pad & PAD_DOWN&#41; && &#40;menuNumber == 3&#41;&#41; &#123;
	            startMenu2&#40;&#41;;
	            
	           
	            
	            
            &#125;
            
            if&#40;&#40;new_pad & PAD_DOWN&#41; && &#40;menuNumber == 4&#41;&#41; &#123;
	            startMenu3&#40;&#41;;
	            
	            
	            
	            
            &#125;
                       
            if&#40;&#40;new_pad & PAD_DOWN&#41; && &#40;menuNumber == 6&#41;&#41; &#123;
	            optionsMenu2&#40;&#41;;
	            
	            
	            
	            
            &#125;
            
            if&#40;&#40;new_pad & PAD_DOWN&#41; && &#40;menuNumber == 7&#41;&#41; &#123;
	            optionsMenu3&#40;&#41;;
	            
	            
	            
	            
            &#125;
                       
            if&#40;new_pad & PAD_START&#41; &#123;
            &#125;
            
            if&#40;new_pad & PAD_R3&#41; &#123;
            &#125;
            
            if&#40;new_pad & PAD_L3&#41; &#123;
            &#125;
            
            if&#40;new_pad & PAD_SELECT&#41; &#123;
            &#125;
            
            if&#40;new_pad & PAD_SQUARE&#41; &#123;
            &#125;            
            
            if&#40;&#40;new_pad & PAD_CROSS&#41; && &#40;menuNumber == 1&#41;&#41; &#123;
               startMenu1&#40;&#41;;
               
	            
	            
	            
            &#125;
            
            if&#40;&#40;new_pad & PAD_CROSS&#41; && &#40;menuNumber == 2&#41;&#41; &#123;
               optionsMenu1&#40;&#41;;
               
	            
	            
	            
            &#125;           
            
            if&#40;new_pad & PAD_CIRCLE&#41; &#123;
               
            &#125;
            
            if&#40;&#40;new_pad & PAD_TRIANGLE&#41; && &#40;menuNumber > 2&#41;&#41; &#123;
               mainMenuS&#40;&#41;;
               
	            
	            
	            
            &#125;
            
            if&#40;new_pad & PAD_R1&#41; &#123;
            &#125;
            
            if&#40;new_pad & PAD_L1&#41; &#123;
            &#125;
            
            if&#40;new_pad & PAD_R2&#41; &#123;
            &#125;
            
            if&#40;new_pad & PAD_L2&#41; &#123;
            &#125;
            
        

            // Test the press mode
            /* Calling SetActAlign repetedly will kill the iop &#58;P
             * &#40;guess the EE is too fast for IOP to handle..&#41;
             * So I'd recommend to change the actuator values only once per
             * vblank or so..
             */
            if&#40;buttons.triangle_p&#41; &#123;
#if 0
                actAlign&#91;1&#93; = &#40;i >> 3&#41;; buttons.triangle_p;  // Big engine
                padSetActDirect&#40;port, slot, actAlign&#41;;
#else
#endif
            &#125;
            // Start little engine if we move right analog stick right
            if&#40;buttons.rjoy_h > 0xf0&#41;
            &#123;
                // Stupid check to see if engine is already running,
                // just to prevent overloading the IOP with requests
                if &#40;actAlign&#91;0&#93; == 0&#41; &#123;
                    actAlign&#91;0&#93; = 1;
                    padSetActDirect&#40;port, slot, actAlign&#41;;
                &#125;
                
             
                
            &#125;
        &#125; 
    &#125;

    SleepThread&#40;&#41;;

    return 0;
&#125;
It compiles fine, runs, and everything works fine, except that, when there are three items, and a top item is selected, and DOWN is pressed, the middle item is skipped over, and the bottom item is selected. The strange thing is that this does not occur when a bottom item is selected, and there are three items, and the UP button is pressed. No, that works just as planned, selecting the middle item, after which another UP press will select the top item.

Could someone please point out where I've erred, if that's obvious? I'm guessing it's just some simple lack of proper logic...

Posted: Sat Jan 17, 2009 6:14 pm
by ps2devman
Pads are tricky on the PS2...

Too lazy to study/debug your method, but here is a last resort sample, if you need to compare with a working small menu (method nearly identical to the one used in SMS, if I remember correctly, since I learn most of PS2 stuff by studying SMS source) :

http://home.tele2.fr/~fr-51785/ps2_pong.zip

Posted: Sat Jan 17, 2009 8:39 pm
by Lukasz
I think your problem could be related to the fact that your source probably will read the pads more than once pr. frame. Padlib works in such a way that it only updates the pad status after a vsync (new frame), so if you don't wait until the next frame to read the pad status, you might be reading the same status twice or more. This would explain why the results you are getting are inconsistent.

The two pad samples I wrote (for padx and mtap) both wait for vsync before reading the pad status, you might want to check them out.

http://svn.ps2dev.org/filedetails.php?r ... rev=0&sc=0
http://svn.ps2dev.org/filedetails.php?r ... rev=0&sc=0

Posted: Mon Jan 19, 2009 5:51 pm
by LBGSHI
Surprisingly, the same thing happened with your example. I'll do some more work tomorrow, and see if I can figure out what's going on here.

Posted: Wed Jan 21, 2009 11:22 am
by LBGSHI
One of the things my mind half-heartedly concocted as a solution worked: I added a continue to each of the if statements controlling menu flow, and the problem is now gone :)