[PSP] Faster menu loading times

Post tutorials on how to do certain tasks within game or engine code here.
Post Reply
Mexicouger
Posts: 514
Joined: Sat May 01, 2010 10:12 pm
Contact:

[PSP] Faster menu loading times

Post by Mexicouger »

Ok, so as many of you know, if you mess with Kurok at all, the menu lags a bit when you goto access a new menu screen. It is kind of annoying. This tutorial is simple, and will make loading times faster for menu navigation.
First off, Open up Host.c


Scroll down to Host_Init, and find this in the function:

Add in the yellow line of code.
Memory_Init (parms->membase, parms->memsize);
Cbuf_Init ();
Cmd_Init ();
V_Init ();
Chase_Init ();
Host_InitVCR (parms);
COM_Init (parms->basedir);
Host_InitLocal ();
W_LoadWadFile ("gfx.wad");
Key_Init ();
Con_Init ();
M_Init ();
PR_Init ();
Mod_Init ();
NET_Init ();
SV_Init ();

Save and close Host.c, and open up menu.h.

Add the Yellow line of code.
//
// menus
//
void Menu_Init (void);
void M_Init (void);
void M_Keydown (int key);
void M_Draw (void);
void M_ToggleMenu_f (void);
Save and close, And open up menu.c
Scroll down a little bit until you find this:

Code: Select all

//int         track;

qboolean	m_return_onerror;
char		m_return_reason [32];

#define StartingGame	(m_multiplayer_cursor == 1)
#define JoiningGame		(m_multiplayer_cursor == 0)
#define SerialConfig	(m_net_cursor == 0)
#define DirectConfig	(m_net_cursor == 1)
#define	IPXConfig		(m_net_cursor == 2)
#define	TCPIPConfig		(m_net_cursor == 3)

void M_ConfigureNetSubsystem(void);
Add this Directly above it.
//////////////////////////////////////////////////////////////////////
/////// Menu Caches, To make the menu load faster, and Not have a hang.
////////////////////////////////////////////////////////////////////
// Multiplayer Menu
qpic_t *s1; //Single 1
qpic_t *s0; //Single 0
qpic_t *m1; //Multiplayer 1
qpic_t *m0; //Multiplayer 0
qpic_t *o1; //Options 1
qpic_t *o0; //Options 0
qpic_t *h1; //Help 1
qpic_t *h0; //Help 0
qpic_t *q1; //Quit 1
qpic_t *q0; //Quit 0
// Single Player menu
qpic_t *nw1; //New 1
qpic_t *nw0; //New 0
qpic_t *sv1; //Save 1
qpic_t *sv0; //Save 0
qpic_t *ld1; //Load 1
qpic_t *ld0; //Load 0
// Multiplayer 2 Menu
qpic_t *jn1; //Join 1
qpic_t *jn0; //Join 0
qpic_t *ct1; //Create 1
qpic_t *ct0; //Create 0
qpic_t *st1; //Setup 1
qpic_t *st0; //Setup 0
qpic_t *inf1; //Infranstructure 1
qpic_t *inf0; //Infranstructure 0
qpic_t *ad1; //Adhoc 1
qpic_t *ad0; //Adhoc 0



//int track;

qboolean m_return_onerror;
char m_return_reason [32];

#define StartingGame (m_multiplayer_cursor == 1)
#define JoiningGame (m_multiplayer_cursor == 0)
#define SerialConfig (m_net_cursor == 0)
#define DirectConfig (m_net_cursor == 1)
#define IPXConfig (m_net_cursor == 2)
#define TCPIPConfig (m_net_cursor == 3)

void M_ConfigureNetSubsystem(void);
Now directly below that, Add this:

void M_ConfigureNetSubsystem(void);

/*
///////////////////////
MenuInit
//////////////////////
*/
void Menu_Init (void)
{
//Main menu section
s1 = Draw_CachePic ("gfx/menu/single_1.lmp");
s0 = Draw_CachePic ("gfx/menu/single_0.lmp");
m1 = Draw_CachePic ("gfx/menu/multi_1.lmp");
m0 = Draw_CachePic ("gfx/menu/multi_0.lmp");
o1 = Draw_CachePic ("gfx/menu/option_1.lmp");
o0 = Draw_CachePic ("gfx/menu/option_0.lmp");
h1 = Draw_CachePic ("gfx/menu/help_1.lmp");
h0 = Draw_CachePic ("gfx/menu/help_0.lmp");
q1 = Draw_CachePic ("gfx/menu/quit_1.lmp");
q0 = Draw_CachePic ("gfx/menu/quit_0.lmp");
//Single player
nw1 = Draw_CachePic ("gfx/menu/sp/new_1.lmp");
nw0 = Draw_CachePic ("gfx/menu/sp/new_0.lmp");
sv1 = Draw_CachePic ("gfx/menu/sp/save_1.lmp");
sv0 = Draw_CachePic ("gfx/menu/sp/save_0.lmp");
ld1 = Draw_CachePic ("gfx/menu/sp/load_1.lmp");
ld0 = Draw_CachePic ("gfx/menu/sp/load_0.lmp");
//Multiplayer 2 Menu
jn1 = Draw_CachePic ("gfx/menu/mp/join_1.lmp");
jn0 = Draw_CachePic ("gfx/menu/mp/join_0.lmp");
ct1 = Draw_CachePic ("gfx/menu/mp/create_1.lmp");
ct0 = Draw_CachePic ("gfx/menu/mp/create_0.lmp");
st1 = Draw_CachePic ("gfx/menu/mp/setup_1.lmp");
st0 = Draw_CachePic ("gfx/menu/mp/setup_0.lmp");
inf1 = Draw_CachePic ("gfx/menu/mp/inf_1.lmp");
inf0 = Draw_CachePic ("gfx/menu/mp/inf_0.lmp");
ad1 = Draw_CachePic ("gfx/menu/mp/adhoc_1.lmp");
ad0 = Draw_CachePic ("gfx/menu/mp/adhoc_0.lmp");

}
Scroll down to

Code: Select all

void M_Main_Draw (void)
Replace this:

Code: Select all

void M_Main_Draw (void)
{
	int		f;
	qpic_t	*p,*b, *s, *m, *o, *h, *q, *t;

	if (kurok)
	{
        t = Draw_CachePic ("gfx/menu/title.lmp");
    	M_DrawPic ((320-t->width)/2, 16, t);

        if (m_main_cursor == 0)
            s = Draw_CachePic ("gfx/menu/single_1.lmp");
        else
            s = Draw_CachePic ("gfx/menu/single_0.lmp");
    	M_DrawPic ((320-s->width)/2, 160, s);

        if (m_main_cursor == 1)
            m = Draw_CachePic ("gfx/menu/multi_1.lmp");
        else
            m = Draw_CachePic ("gfx/menu/multi_0.lmp");
    	M_DrawPic ((320-m->width)/2, 176, m);

        if (m_main_cursor == 2)
            o = Draw_CachePic ("gfx/menu/option_1.lmp");
        else
            o = Draw_CachePic ("gfx/menu/option_0.lmp");
    	M_DrawPic ((320-o->width)/2, 192, o);

        if (m_main_cursor == 3)
            h = Draw_CachePic ("gfx/menu/help_1.lmp");
        else
            h = Draw_CachePic ("gfx/menu/help_0.lmp");
    	M_DrawPic ((320-h->width)/2, 208, h);

        if (m_main_cursor == 4)
            q = Draw_CachePic ("gfx/menu/quit_1.lmp");
        else
            q = Draw_CachePic ("gfx/menu/quit_0.lmp");
    	M_DrawPic ((320-q->width)/2, 224, q);

    }
With...

Code: Select all

void M_Main_Draw (void)
{
	int		f;
	qpic_t	*p,*b,*t;

	if (kurok)
	{
        t = Draw_CachePic ("gfx/menu/title.lmp");
    	M_DrawPic ((320-t->width)/2, 16, t);

        if (m_main_cursor == 0)
           M_DrawPic ((320-s1->width)/2, 160, s1);
        else
    	M_DrawPic ((320-s0->width)/2, 160, s0);

        if (m_main_cursor == 1)
            M_DrawPic ((320-m1->width)/2, 176, m1);
        else
            M_DrawPic ((320-m0->width)/2, 176, m0);

        if (m_main_cursor == 2)
           M_DrawPic ((320-o1->width)/2, 192, o1);
        else
          M_DrawPic ((320-o0->width)/2, 192, o0);

        if (m_main_cursor == 3)
            M_DrawPic ((320-h1->width)/2, 208, h1);
        else
            M_DrawPic ((320-h0->width)/2, 208, h0);

        if (m_main_cursor == 4)
            M_DrawPic ((320-q1->width)/2, 224, q1);
        else
           M_DrawPic ((320-q0->width)/2, 224, q0);

    }
Now scroll down to

Code: Select all

void M_SinglePlayer_Draw (void)
Replace:

Code: Select all

void M_SinglePlayer_Draw (void)
{
	int		f;
	qpic_t	*p,*b, *n, *l, *s, *t;

	b = Draw_CachePic ("gfx/m_bttns.lmp");
	M_DrawPic ( (320-b->width)/2, 248, b );

	if (kurok)
	{
        t = Draw_CachePic ("gfx/menu/title.lmp");
    	M_DrawPic ((320-t->width)/2, 16, t);

        if (m_singleplayer_cursor == 0)
            n = Draw_CachePic ("gfx/menu/sp/new_1.lmp");
        else
            n = Draw_CachePic ("gfx/menu/sp/new_0.lmp");
    	M_DrawPic ((320-n->width)/2, 160, n);

        if (m_singleplayer_cursor == 1)
            l = Draw_CachePic ("gfx/menu/sp/load_1.lmp");
        else
            l = Draw_CachePic ("gfx/menu/sp/load_0.lmp");
    	M_DrawPic ((320-l->width)/2, 176, l);

        if (m_singleplayer_cursor == 2)
            s = Draw_CachePic ("gfx/menu/sp/save_1.lmp");
        else
            s = Draw_CachePic ("gfx/menu/sp/save_0.lmp");
    	M_DrawPic ((320-s->width)/2, 192, s);
    }
With...

Code: Select all

void M_SinglePlayer_Draw (void)
{
	int		f;
	qpic_t	*p,*b,*t;

	b = Draw_CachePic ("gfx/m_bttns.lmp");
	M_DrawPic ( (320-b->width)/2, 248, b );

	if (kurok)
	{
        t = Draw_CachePic ("gfx/menu/title.lmp");
    	M_DrawPic ((320-t->width)/2, 16, t);

        if (m_singleplayer_cursor == 0)
           M_DrawPic ((320-nw1->width)/2, 160, nw1);
        else
            M_DrawPic ((320-nw0->width)/2, 160, nw0);

        if (m_singleplayer_cursor == 1)
           M_DrawPic ((320-ld1->width)/2, 176, ld1);
        else
           M_DrawPic ((320-ld0->width)/2, 176, ld0);

        if (m_singleplayer_cursor == 2)
            M_DrawPic ((320-sv1->width)/2, 192, sv1);
        else
            M_DrawPic ((320-sv0->width)/2, 192, sv0);
    }
Alright! We are almost done, Just 1 more thing.
Scroll down to:

Code: Select all

void M_MultiPlayer_Draw (void)
Replace:

Code: Select all

void M_MultiPlayer_Draw (void)
{
	int		f;

	qpic_t	*p,*b, *j, *c, *t, *i, *a;

    b = Draw_CachePic ("gfx/m_bttns.lmp");
	M_DrawPic ( (320-b->width)/2, 248, b );

	if (kurok)
	{
//        M_DrawTransPic (72, 32, Draw_CachePic ("gfx/menu/multi_0.lmp") );

        if (m_multiplayer_cursor == 0)
            j = Draw_CachePic ("gfx/menu/mp/join_1.lmp");
        else
            j = Draw_CachePic ("gfx/menu/mp/join_0.lmp");
    	M_DrawPic ((320-j->width)/2, 72, j);

        if (m_multiplayer_cursor == 1)
            c = Draw_CachePic ("gfx/menu/mp/create_1.lmp");
        else
            c = Draw_CachePic ("gfx/menu/mp/create_0.lmp");
    	M_DrawPic ((320-c->width)/2, 88, c);

        if (m_multiplayer_cursor == 2)
            t = Draw_CachePic ("gfx/menu/mp/setup_1.lmp");
        else
            t = Draw_CachePic ("gfx/menu/mp/setup_0.lmp");
    	M_DrawPic ((320-t->width)/2, 104, t);

        if (m_multiplayer_cursor == 3)
            i = Draw_CachePic ("gfx/menu/mp/inf_1.lmp");
        else
            i = Draw_CachePic ("gfx/menu/mp/inf_0.lmp");
    	M_DrawPic ((320-i->width)/2, 128, i);

	    M_DrawCheckbox ((320/2) - ((3*8)/2), 144, tcpipAvailable && !tcpipAdhoc);

        if (m_multiplayer_cursor == 4)
            a = Draw_CachePic ("gfx/menu/mp/adhoc_1.lmp");
        else
            a = Draw_CachePic ("gfx/menu/mp/adhoc_0.lmp");
    	M_DrawPic ((320-a->width)/2, 152, a);
with...

Code: Select all

void M_MultiPlayer_Draw (void)
{
	int		f;

	qpic_t	*p,*b;

    b = Draw_CachePic ("gfx/m_bttns.lmp");
	M_DrawPic ( (320-b->width)/2, 248, b );

	if (kurok)
	{
//        M_DrawTransPic (72, 32, Draw_CachePic ("gfx/menu/multi_0.lmp") );

        if (m_multiplayer_cursor == 0)
            M_DrawPic ((320-jn1->width)/2, 72, jn1);
        else
          M_DrawPic ((320-jn0->width)/2, 72, jn0);

        if (m_multiplayer_cursor == 1)
           M_DrawPic ((320-ct1->width)/2, 88, ct1);
        else
            M_DrawPic ((320-ct0->width)/2, 88, ct0);

        if (m_multiplayer_cursor == 2)
            M_DrawPic ((320-st1->width)/2, 104, st1);
        else
            M_DrawPic ((320-st0->width)/2, 104, st0);

        if (m_multiplayer_cursor == 3)
            M_DrawPic ((320-inf1->width)/2, 128, inf1);
        else
            M_DrawPic ((320-inf0->width)/2, 128, inf0);

	    M_DrawCheckbox ((320/2) - ((3*8)/2), 144, tcpipAvailable && !tcpipAdhoc);

        if (m_multiplayer_cursor == 4)
            M_DrawPic ((320-ad1->width)/2, 152, ad1);
        else
            M_DrawPic ((320-ad0->width)/2, 152, ad0);
And you are done! Compile and test it. You should be able to cruise through the menu with no hang times.

-Mexicouger
Last edited by Mexicouger on Fri Oct 08, 2010 10:23 pm, edited 1 time in total.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Post by Baker »

Kind of like the touch model code in Quake.

Although I'm not too sure the menu being slightly slow the first time is something to worry about.
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Mexicouger
Posts: 514
Joined: Sat May 01, 2010 10:12 pm
Contact:

Post by Mexicouger »

Well I personally get annoyed with the small hangups when accessing each menu. Now I can fly through the menus the first time around. I just need to add 1 more piece of code, and that is cacheing the bars that go around the console and other various things.
Tomaz
Posts: 67
Joined: Fri Nov 05, 2004 8:21 pm

Post by Tomaz »

It was probably done the way it was to save memory since the PSP only got 22 or was it 24Mb of ram...
Ranger366
Posts: 203
Joined: Thu Mar 18, 2010 5:51 pm

Post by Ranger366 »

and well you can see it was made on kurok.
sounds interesting thought, making loading faster on psp would be better. (i use HalfByteLoader, no cfw) and have to use the latest built of DQuake. i dont like DQuake much, but its the only way.
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Post by Spike »

if the code given works, then those images are persistant.
if those images are persistant then its going to sit in memory the whole time if the menus are ever used anyway.

On PC its okay as the images are not loaded from a cheapo flash drive. When your cheap flash requires you to read large chunks at a time, and is over a slow bus and stuff, then its going to be slow.
On the other hand, stream-loading rocks.
mankrip
Posts: 924
Joined: Fri Jul 04, 2008 3:02 am

Post by mankrip »

Makaqu precaches all menu images, except for the Help menu; this keeps memory usage low, and speeds up menu usage a lot in the Dreamcast.
Ph'nglui mglw'nafh mankrip Hell's end wgah'nagl fhtagn.
==-=-=-=-=-=-=-=-=-=-==
Dev blog / Twitter / YouTube
Mexicouger
Posts: 514
Joined: Sat May 01, 2010 10:12 pm
Contact:

Post by Mexicouger »

I am not too sure about all the technical points of this, But It speeds up menu navigation immensely. However, when loading the actual game, the loading times have slightly increased.

I will finish the tutorial soon.
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Post by mh »

This is definitely one of those areas where there is a trade-off involved. In a memory constrained situation it makes sense to cache-on-demand; you could probably even remove the textures from the cache whenever the player exits the menus if you really wanted to be extreme about it.

GLQuake was written to 1996 specs and did need to run on a 4MB 1st gen Voodoo, after all, and a lot of the things it did to save memory are not really valid anymore (and can even cause more problems than they solve these days). On any hardware from 2000 or so you could almost certainly use this technique without any problems.
It speeds up menu navigation immensely. However, when loading the actual game, the loading times have slightly increased.
I'd expect that behaviour for sure. The overhead of loading menu textures has now been transferred to startup time; some people might find that a little unacceptable though - fast start-up vs fast in-game stuff is another trade-off. DirectQ does something similar with it's maps menu, caching all the data on startup rather than while the menu is being navigated, and it has been pointed out to me that startup is slow.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
Mexicouger
Posts: 514
Joined: Sat May 01, 2010 10:12 pm
Contact:

Post by Mexicouger »

It's not much slower though. Give or take a second or 2. As I go on, I may try to learn more memory shortcuts and workarounds that save memory.

Thanks for the feedback. It is my first tutorial anyways, and I am getting familiar with the engine still. My C programming book helps alot, and you are guys are geniuses when help is needed.
Tomaz
Posts: 67
Joined: Fri Nov 05, 2004 8:21 pm

Post by Tomaz »

Also I have a feeling the PSPQuake engines doesnt really have the most optimized file loading functions. SImply doing a fopen isnt always the best method which is something I learned while making a few PSP games at work.
Post Reply