Out of Memory - Title, Menu, & Character Selection Screens

Bruce

Active member
Hello everyone,

I've posted my question regarding to this issue in another topic, but I think it is better for me to create a topic and post all my code.
I started learning how to add backgrounds and animations with arraylist to the title, menu, and character selection screens.
If I just start the game normally, there is no issue.
If I just loop the title, menu, then character selection screens back and forth for a while (40-50 times),
it would cause out of memory. I know that no one would be crazy enough to loop the screens back and forth like this,
but still it should not be out of memory if it was coded correctly.
Furthermore, if I start the game and then quit the game, and repeat the loop above, it causes out of memory alot quicker.
Also, if I don't comment out these 2 functions in the title screen
Code:
ClearGlobalArrays();  
SetupArrayLists();
and
Code:
ClearGlobalArrays()  in inLevelLoop(),
it causes out of memory alot quicker. It seems like it adds more stuff to the memory instead of removing them when I start looping back and forth , but why?????

Obviously, I didn't code it correctly....
Please any help, advises, comments to help me with better coding/route/understanding, would be greatly appreciated

Video link: Out of memory at the end of the video
Notice: this is just a tryout...

updated.c
Code:
#include "data/scripts/common/constants.h"
#include "data/scripts/story/story_clear.c"
#include "data/scripts/story.c"
#include "data/scripts/gettick.c"
#include "data/scenes/ScreenAnim.c"

#define BG_TITLE1          0
#define BG_TITLE2          1
#define BG_MENU1           2
#define BG_MENU2           3
#define BG_SELECT1         4
#define BG_BLK             5

//       ANIM_TITLE0       0   // NOT USED
#define ANIM_TITLE1        1                        
#define ANIM_TITLE2        2
#define ANIM_TITLE3        3
#define ANIM_TITLE4        4
#define ANIM_SELECT1       5
#define ANIM_SELECT2       6



void oncreate(){  
    InitializeVariables();
}

void ondestroy(){
    log("LOG: ON_DESTROY \n");
    ClearGlobalArrays();
    clearStory();
    clearglobalvar();
    clearlocalvar();
}

void main()
{
    if(openborvariant("current_scene")=="data/levels/scenes/credits/credits.txt")
    {
        clearStory();
        InitializeVariables();
    }
   
    mainLoop();
   
    if(openborvariant("in_selectscreen")){
        int TitleCounter = getlocalvar("TitleCounter");
        if(TitleCounter > 0){
    /*    ClearGlobalArrays();   //these causing the out of memory much quicker!
            SetupArrayLists();  */
            setlocalvar("TitleCounter", 0);
            void TitleAnimList = getglobalvar("List_TitleAnim");
            if(TitleAnimList != NULL())
            {               // GlobalVarIndex, Entity, XYZ
               SpawnScreenAnim(ANIM_SELECT1, "SelectAnim1", 961, 541, -2000);
               SpawnScreenAnim(ANIM_SELECT2, "SelectAnim2", 800, 500, 1);
            }  
        }
        void BG_List = getglobalvar("List_TitleBG");
        void SelectBG = get(BG_List, BG_SELECT1);
        if(SelectBG != NULL()){
            changedrawmethod(NULL(), "alpha", 0);
            drawsprite(SelectBG, 0, 0, 0);
        }
    }
}

void mainLoop()
{
    if(openborvariant("in_level")){
        inLevelLoop();
    }
    else
    {
        if(openborvariant("current_scene") == "data/scenes/intro.txt"){
            int TitleCounter = getlocalvar("TitleCounter");
            if(TitleCounter == NULL() || TitleCounter > 0){
                setlocalvar("TitleCounter", 0);
            }
        }

        else if(openborvariant("in_titlescreen")){
            int TitleCounter = getlocalvar("TitleCounter");
            if(TitleCounter != 1){
                clearStory();
                // InitializeVariables();
                playwebm("data/scenes/Press_Start_Screen.webm", 0);  // 0 = skippable
               
                void TitleAnimList = getglobalvar("List_TitleAnim");
                if(TitleAnimList != NULL())
                {
                    void SelectAnim1 = get(TitleAnimList, ANIM_SELECT1);
                    if(SelectAnim1 != NULL()){
                        killentity(SelectAnim1);
                    }
                    void SelectAnim2 = get(TitleAnimList, ANIM_SELECT2);
                    if(SelectAnim2 != NULL()){
                        killentity(SelectAnim2);
                    }
                }
                   
                if(TitleAnimList != NULL())
                {               // GlobalVarIndex, Entity, XYZ
                   SpawnScreenAnim(ANIM_TITLE1, "TitleAnim1", 500, 500, -1);
                   SpawnScreenAnim(ANIM_TITLE2, "TitleAnim2", 800, 500, -1);
                }              
               
                setlocalvar("TitleCounter", 1);
                playmusic("data/music/Title.ogg", 1);
            }
           
            drawstring(20,20,0, "TITLE");
            void BG_List = getglobalvar("List_TitleBG");
            void TitleBG = get(BG_List, BG_TITLE1); // see SetupArrayLists() for details
            if(TitleBG != NULL()){
                changedrawmethod(NULL(), "alpha", 0);
                drawsprite(TitleBG, 0, 0, -2);
            }
            void BlackMask = get(BG_List, BG_BLK);
            if(BlackMask != NULL()){
                changedrawmethod(NULL(), "alpha", 6);  // 50% transparency
                drawsprite(BlackMask, 0, 0, -1);
            }          
        }
       
        else if(openborvariant("in_menuscreen")){
            drawstring(20,20,0, "MENU");
            int TitleCounter = getlocalvar("TitleCounter");
             if(TitleCounter != 2)
            {
                setlocalvar("TitleCounter", 2);
                playmusic("data/music/Menu.ogg", 1);

                void TitleAnimList = getglobalvar("List_TitleAnim");
                if(TitleAnimList != NULL())
                {
                    void TitleAnim1 = get(TitleAnimList, ANIM_TITLE1);
                    if(TitleAnim1 != NULL()){
                        killentity(TitleAnim1);
                    }
                    void TitleAnim2 = get(TitleAnimList, ANIM_TITLE2);
                    if(TitleAnim2 != NULL()){
                        killentity(TitleAnim2);
                    }
                }
             }    
   
            void BG_List = getglobalvar("List_TitleBG");
            void MenuBG = get(BG_List, BG_MENU1);
            if(MenuBG != NULL()){
                changedrawmethod(NULL(), "alpha", 0);
                drawsprite(MenuBG, 0, 0, -1);
            }
            void BlackMask = get(BG_List, BG_BLK);
            if(BlackMask != NULL()){
                changedrawmethod(NULL(), "alpha", 6);  // 50% transparency
                drawsprite(BlackMask, 0, 0, -1);
            }
        }
    }
}

void InitializeVariables()
{
    setglobalvar("LevelFirstStart", 1);
    SetupArrayLists();
}

void inLevelLoop()
{
    turnWhite();
    storySystem();
    int LevelFirstStart = getglobalvar("LevelFirstStart");
    if(LevelFirstStart > 0)
    {
        setglobalvar("LevelFirstStart", 0);
        // ClearGlobalArrays();
    }
}
   
void SetupArrayLists()
{
    void TitleBG_List = getglobalvar("List_TitleBG");
    if(!TitleBG_List || TitleBG_List == NULL())
    {
        TitleBG_List = array(2);  //array(2) means total of 3 items
        set(TitleBG_List, BG_TITLE1, loadsprite("data/scenes/TitleScreen.png"));
        set(TitleBG_List, BG_TITLE2, NULL());
        set(TitleBG_List, BG_MENU1, loadsprite("data/scenes/MenuScreen.png"));
        set(TitleBG_List, BG_MENU2, NULL());
        set(TitleBG_List, BG_SELECT1, loadsprite("data/bgs/select.png"));
        set(TitleBG_List, BG_BLK, loadsprite("data/scenes/black.gif"));
        setglobalvar("List_TitleBG", TitleBG_List);
    }

    void AnimList = getglobalvar("List_TitleAnim");
    if(!AnimList || AnimList == NULL())
    {
        AnimList = array(3);  //array(3) means total of 4 items
        set(AnimList, 0, NULL());  //  NOT USED
        set(AnimList, ANIM_TITLE1, NULL());  // Title Animation 1
        set(AnimList, ANIM_TITLE2, NULL());
        set(AnimList, ANIM_TITLE3, NULL());
        set(AnimList, ANIM_TITLE4, NULL());
        set(AnimList, ANIM_SELECT1, NULL());
        set(AnimList, ANIM_SELECT2, NULL());
        setglobalvar("List_TitleAnim", AnimList);
    }
}  
   
void ClearGlobalArrays()
{
    int i;
    void BG_List = getglobalvar("List_TitleBG");

    if(BG_List)
    {
        for(i=0; i<size(BG_List); i++)
        {
            set(BG_List, i, NULL());
        }
        free(BG_List);
        setglobalvar("List_TitleBG", NULL());
    }
    void Anim_List = getglobalvar("List_TitleAnim");
    if(Anim_List)
    {
        for(i=0; i<size(Anim_List); i++)
        {
            set(Anim_List, i, NULL());
        }
        free(Anim_List);
        setglobalvar("List_TitleAnim", NULL());
    }
}

ScreenAnim.c:
Code:
void SpawnScreenAnim(int ArrayIndex, void AnimatedEntity, int X, int Y, int Z)
{
        void vSpawn;
        void subent;

        void AnimList = getglobalvar("List_TitleAnim");
        if(AnimList != NULL())
        {
            void TitleAnim = get(AnimList, ArrayIndex);
            if(TitleAnim != NULL()){
               killentity(TitleAnim); //Kill previous spawned enity to avoid duplicated entities
            }
        }
       
        loadmodel(AnimatedEntity); // name of the entity to be loaded
        clearspawnentry(); // clean the spawn entry
        setspawnentry("name", AnimatedEntity); // define the entity to be spawn
        setspawnentry("coords", X, Y, Z); // set the position of the entity
        subent=spawn();  //  spawn the entity
        if(AnimList != NULL())
        {
            set(AnimList, ArrayIndex, subent);
            setglobalvar("List_TitleAnim", AnimList);
        }
        changeentityproperty(subent, "position", X, Y, Z);//for safe, set again the position

}

SelectAnim1.txt
Code:
name         SelectAnim1
health         1
type         panel
speed         10
shadow     0
setlayer     -2000
facing         1

anim idle
    loop 1 1
    offset    961 541
    delay    15
    @cmd changeentityproperty getlocalvar("self") "direction" 1
    frame    data/scenes/SelectAnim/SelectAnim01.png
    @cmd changeentityproperty getlocalvar("self") "setlayer" -2000
    frame    data/scenes/SelectAnim/SelectAnim02.png
    frame    data/scenes/SelectAnim/SelectAnim03.png
    frame    data/scenes/SelectAnim/SelectAnim04.png
    frame    data/scenes/SelectAnim/SelectAnim05.png
    frame    data/scenes/SelectAnim/SelectAnim06.png
    frame    data/scenes/SelectAnim/SelectAnim07.png
    frame    data/scenes/SelectAnim/SelectAnim08.png
    frame    data/scenes/SelectAnim/SelectAnim09.png
    frame    data/scenes/SelectAnim/SelectAnim10.png
    frame    data/scenes/SelectAnim/SelectAnim11.png
    frame    data/scenes/SelectAnim/SelectAnim12.png
    frame    data/scenes/SelectAnim/SelectAnim13.png
    frame    data/scenes/SelectAnim/SelectAnim14.png
    frame    data/scenes/SelectAnim/SelectAnim15.png
    frame    data/scenes/SelectAnim/SelectAnim16.png
    frame    data/scenes/SelectAnim/SelectAnim17.png
    frame    data/scenes/SelectAnim/SelectAnim18.png
    frame    data/scenes/SelectAnim/SelectAnim19.png
    frame    data/scenes/SelectAnim/SelectAnim20.png
    frame    data/scenes/SelectAnim/SelectAnim21.png
    frame    data/scenes/SelectAnim/SelectAnim22.png
    frame    data/scenes/SelectAnim/SelectAnim23.png
    frame    data/scenes/SelectAnim/SelectAnim24.png
    frame    data/scenes/SelectAnim/SelectAnim25.png
    frame    data/scenes/SelectAnim/SelectAnim26.png
    frame    data/scenes/SelectAnim/SelectAnim27.png
    frame    data/scenes/SelectAnim/SelectAnim28.png
    frame    data/scenes/SelectAnim/SelectAnim29.png
    frame    data/scenes/SelectAnim/SelectAnim30.png

Thank you very much
 
I have one game at 1080, i tested 4k, 1080 and inbetweens, settled for 720p now , try sequence with 2 frames.
Transparency will eat ton of CPU processing.

Openbor "can" handle even over 9000p , so DC was right in theory - in practice the game will run until you start adding effects - it will start losing fps even on GPU from the future.
So you will get like 15fps and what kind of experience is that - which is why idisagree with DC on this.
Runs ? Yes , but is it managable to build a game with that resolution ?

Not really , maybe if you have only 1 bg/fglayer, not many effects, then maybe. 1080p isnt that demanding.But "thousands of high resolutions" is just a theory.

There arent many people who did hires games with openbor, im one of them and i dont know anyone else who did 1080 besides you.

Openbor is not using GPU, im on RTX3090 but still get frame drops with a couple fglayers .

Always test ahead before diving and spending time creating big assets.

Id say try to test your sequences in game, on stage to see if youll get performance drops.Try with 10 frames, try with 2 frames.
You will get to the core of the problem fast if You will test like this.
I've been busy and have not worked on my game much lately...
I don't have problems with FRS even with 50 frames animation, but I do have so much issues with memory overloading at 1080p. I have about 1,200 png sprites, and it is overloading the memory. I started to think that this Openbor engine can not handle 1080P :-( I love high resolution games...
DC said 70 of 200k sprites is only 1% of what the engine can handle. However, I have 1,200 of 300kb~400kb sprites and the memory is already overloaded, especially whenever I play webm video which does not make any sense why playing webm video causes memory overloaded?????

How many sprites do you have in your 720P game? Do you have overloading memory problems?
Thank you
 
I've been busy and have not worked on my game much lately...
I don't have problems with FRS even with 50 frames animation, but I do have so much issues with memory overloading at 1080p. I have about 1,200 png sprites, and it is overloading the memory. I started to think that this Openbor engine can not handle 1080P :-( I love high resolution games...
DC said 70 of 200k sprites is only 1% of what the engine can handle. However, I have 1,200 of 300kb~400kb sprites and the memory is already overloaded, especially whenever I play webm video which does not make any sense why playing webm video causes memory overloaded?????

How many sprites do you have in your 720P game? Do you have overloading memory problems?
Thank you


1% is hyperbole, however your problem is not the sprite load. It just isn't. Simple math tells us this

Rounding up your sprite size to 500KB each, that means 1,200 sprites comes out to ~586MB uncompressed. Except the engine does trim and compress them, but let's assume it doesn't.

OpenBOR is a 32bit application, meaning it can address ~2GB of RAM. The internal sprite database is likewise indexed with a 32bit signed integer, meaning the hard code limit for sprites is just over 2 billion. So obviously the practical limit is RAM.

At the rate you're going, there's still room for 2,500 more and plenty to spare, and that's assuming absolutely zero memory management and loading everything all at once.

That doesn't account for framerate, hardware RAM limitations, or other issues with your design and workflow, and there are several things that might trigger an OOM error. It isn't your sprite count.

DC
 
1% is hyperbole, however your problem is not the sprite load. It just isn't. Simple math tells us this

Rounding up your sprite size to 500KB each, that means 1,200 sprites comes out to ~586MB uncompressed. Except the engine does trim and compress them, but let's assume it doesn't.

OpenBOR is a 32bit application, meaning it can address ~2GB of RAM. The internal sprite database is likewise indexed with a 32bit signed integer, meaning the hard code limit for sprites is just over 2 billion. So obviously the practical limit is RAM.

At the rate you're going, there's still room for 2,500 more and plenty to spare, and that's assuming absolutely zero memory management and loading everything all at once.

That doesn't account for framerate, hardware RAM limitations, or other issues with your design and workflow, and there are several things that might trigger an OOM error. It isn't your sprite count.

DC
I know my computer is not a gamer computer, but I believe it should be more than enough to run the 1080p games. It is running the official Capcom UMVC3 game no problem at all, no slow down nothing. When you said "framerate", does this mean how many sprites I have per animation or it is the game running framerate?
Can you take a look at my computer and see if it could be the system requirement not met?

1732809638934.png

Updated:

I just created a new project with only a few scripts and very simple basic stuff in OpenBOR Build 6.3.9.1, but sadly it is still OOM whenever I play Webm.
I do not think this OpenBOR Build 6.3.9.1 works well for 1080P resolution when there are over 1200 png files?
Maybe it requires a gamer computer?

I started Dante with 15 animations, and it worked no problems, but as I added more animations to it, it went OOM. Basically, adding more png files causes the OOM.
 
Last edited:
Back
Top Bottom