Magazine Storage v.0.9

M@gg!

26-09-2006 10:50:38

Finaly I found the time to complete the Magazine Storage.

It can be used to store nearly each object you like in it. The key feature is, that you can easily preload a huge amount of identicaly objects and can access them when ever you like (it's an Ogre::Singleton).

The Magazine Storage is a framelistener, that updates your objects (if you like) each framend with the elapsed time since the last frame.

I'd be grateful if you report bugs, because it is still not well testet (the reason why it's not v.1.0).

If you think it should have feature x,y,z or notices that there is something missing, please say so, too. I'll try to implement it, if it's making sence.

\REMARK
It is documented for Doxygen use.

M@gg!

26-09-2006 10:51:35

magazine.h

/*!
* HowTo use this class:
*
* Example:
* You are programming a game and want to preload 100 bullets. That's faster than generating
* a new one each time you want to shoot. In addition you want to return the bullets when their
* livetime expires.
*
* ToDo for this task:

* <Build a new class of type StoreItem>
* <Redefine its methods>

class Bullet: public StoreItem
{
public:
virtual ~StoreItem()
{
//You'll have to care about the destruction of your object
}

//Is called from "void MagazineShell::setActive(bool _true)" or "void StoreItem::setActive(bool _true)"
virtual void custimizedActive (bool _true)
{
if (true)
{
makeTheBulletVisible();
enablePhysicalInteraction();
mLiveTime = 15;
}
else
{
makeTheBulletInvisible();
disablePhysicalInteraction();
mLiveTime = 0;
}
}

//Is called on end of each frame from the MagazineStorage if the Magazine::update flag is set true
virtual void update (Ogre::Real _elapsed_time)
{
mLiveTime -= _elapsed_time;

if (mLiveTime <= 0)
{
if(mShell)
{
mShell->returnShell(); //Automatically calls "setActive(false)" it is the only way to return the item to the magazine
}
else
{
Ogre::LogManager::getSingleton().logMessage("StoreItem can't be returned, because it is not part of a Magazine.");
}
}
}


//A possible method of yours
void shotBullet(Ogre::Vector _position, Ogre::Quaternion _direction, Ogre::Real speed)
{
//Your code
}


private:
Ogre::Real mLiveTime;
}

* <Create a MagazineStorage>

new MagazineStorage(mRoot, 10);

* <Create a Magazine>

mMagazine = new Magazine(100);

* <Initialise the Magazine "fill the Magazine with your bullets">

MagazineShell *shell;

while (shell = magazine->getUninitialisedShell())
{
shell->initializeShell(new Bullet());
}

* <Setting the Magazine update flag>

magazine->setUpdateFlag();

* <At last, put the Magazine in the MagazineStorage>
* <Don't forget to save the id, you'll need it for acces to the Magazine>

unsigned int id = MagazineStorage::getSingleton().addMagazine(magazine);


* <Now you can use it in your program at any place like this>
Magazine *magazine = MagazineStorage::getSingleton().getMagazine(id);

Bullet *bullet = (bullet*) magazine->getInactiveStoreItem();

bullet->setActive();
bullet->shot(...);

* You can repeat this as long as there are unused bullets in the magazine. Remember, they are returned automatically.
*
* Copyright (c) 2006 by < M@gg! >
*/
#ifndef __MAGAZINE_H
#define __MAGAZINE_H

#include <Ogre.h>
#include <vector>

class Magazine;
class MagazineShell;
class StoreItem;

/*!
* \brief
* Holds Magazines.
*
* This class can be generated once and then holds a predifined number of magazines. It is an Ogre::Singleton and an Ogre::Framlistener.
* It is automaticaly registered as framelistener to the passed Ogre::Root reference. You can force it not do this and register it by your own.
*
* \remarks
* Do not try to create it several times.
*/
class MagazineStorage: public Ogre::Singleton<MagazineStorage>,
public Ogre::FrameListener{

public:
MagazineStorage(Ogre::Root *_root, unsigned int _size, bool _start_framelistener = true);
~MagazineStorage();

virtual bool frameStarted (const Ogre::FrameEvent& evt);
virtual bool frameEnded (const Ogre::FrameEvent& evt);

static MagazineStorage& getSingleton(void);
static MagazineStorage* getSingletonPtr(void);


unsigned int addMagazine (Magazine* _magazine); //0 = Error
Magazine *getMagazine (unsigned int _id);
void setUpdateFlagMagazines (bool _true = true)
{
mUpdateAll = !_true;
}
void setUpdateAllMagazines (bool _true = true)
{
mUpdateAll = _true;
}
void manuallyUpdateFlagMagazines(Ogre::Real _elapsed_time);
void manuallyUpdateAllMagazines (Ogre::Real _elapsed_time);
Magazine *removeMagazine (unsigned int _id);
/*!
* \brief
* Returns the MagazineStorage size.
*
* \returns
* Returns the MagazineStorage size.
*/
unsigned int getStorageSize()
{
return mSize;
}

private:

bool mUpdateAll;

unsigned int mSize;

std::vector<Magazine*> vMagazines;


};




class Magazine{
public:

Magazine (unsigned int _size);
~Magazine ();

MagazineShell *getUninitialisedShell ();
StoreItem *getInactiveStoreItem ();

//Very slow
unsigned int getNumberShellsTotal ();
unsigned int getNumberShellsUnused ();
unsigned int getNumberShellsUninitialised ();

void updateShells (Ogre::Real _elapsed_time);
void setUpdateFlag (bool _true=true);
bool getUpdateFlag ();

private:

unsigned int mSize;
bool mUpdateFlag;
std::vector<MagazineShell*> vShells;
};





class MagazineShell{
friend class Magazine;

public:
MagazineShell(unsigned int _number);
~MagazineShell();


void initializeShell(StoreItem* _store_item);
void setActive (bool _true=true);
void updateShell (Ogre::Real _elapsed_time);
void returnShell ();

StoreItem *getStoreItem();

bool getInitialised ();
bool getActive ();

void lockShell (bool _true = true);
bool shellLocked ();

unsigned int getNumber ();
private:


bool mActive;
bool mInitialised;
bool mLocked;

StoreItem *mStoreItem;
unsigned int mNumber;

};





class StoreItem
{
friend class MagazineShell;

public:
StoreItem(): mShell(NULL), mName(""){
}

/*!
* \brief
* Has to be redefined by user.
*
* \see
* Example code
*/
virtual ~StoreItem(){}

/*!
* \brief
* Has to be redefined by user.
*
* \see
* Example code
*/
virtual void update (Ogre::Real _elapsed_time){ /* Do nothing */ }

void setName (const Ogre::String &_name)
{

mName = _name;
}

Ogre::String getName()
{
return mName;
}

/*!
* \brief
* Sets the StoreItem active.
*
* \param[in] _true
* Active = true
*
* setActive calls the MagazineShells setActive method, when it is attached to it.
* The MagazineShell then calls the custimizedActive method of the StoreItem.
*
* When it is not attached to the Shell, it calls custimizedActive directly. So you may use it
* even if it's not attached.
*
* \see
* MagazineShell::setActive
*/
void setActive (bool _true = true)
{
if(mShell)
{
mShell->setActive(_true);
}
else
{
custimizedActive(_true);
}
}



protected:
/*!
* \brief
* Has to be redefined by user.
*
* \see
* Example code
*/
virtual void custimizedActive (bool _true = true)
{
}

MagazineShell *mShell;
Ogre::String mName;

private:
void setMagazineShell (MagazineShell* _shell)
{
mShell = _shell;
}


};



#endif

M@gg!

26-09-2006 10:52:10

magazine.cpp

#include "magazine.h"

///////MagazineStorage


template<> MagazineStorage* Ogre::Singleton<MagazineStorage>::ms_Singleton = 0;


/*!
* \brief
* MagazineStorage constructor.
*
* \param[in/out] _root
* The Ogre::Root object, where the MagazineStorage framelistener is registered to.
*
* \param[in] _size
* The number of magazines that can be hold.
*
* \param[in] _start_framelistener
* Defines if the framelistener is registered to the given Root object or not.
*
* If you set _start_framelistener = false, you can register MagazineStorage as framelistener by your own,
* or you may update it manually.
*
*
* \see
* manuallyUpdateFlagMagazines
* manuallyUpdateAllMagazines
*
*/
MagazineStorage::MagazineStorage(Ogre::Root *_root, unsigned int _size, bool _start_framelistener)
{
mSize = _size;
mUpdateAll = false;

if (_start_framelistener){
_root->addFrameListener(this);
}

for (unsigned int i = 0; i < mSize; i++)
{
vMagazines.push_back(NULL);
}
}


/*!
* \brief
* MagazineStorage destructor.
*
* The destructor deletes only the MagazineStorage, not the Magazines in it. So you'll have to delete them by your own.
*/
MagazineStorage::~MagazineStorage()
{
}


MagazineStorage &MagazineStorage::getSingleton()
{
return *ms_Singleton;
}

MagazineStorage *MagazineStorage::getSingletonPtr()
{
return ms_Singleton;
}


bool MagazineStorage::frameStarted (const Ogre::FrameEvent& evt)
{
return 1;
}

bool MagazineStorage::frameEnded (const Ogre::FrameEvent& evt)
{

if (mUpdateAll)
{
manuallyUpdateAllMagazines(evt.timeSinceLastFrame);
}
else
{
manuallyUpdateFlagMagazines(evt.timeSinceLastFrame);
}

return 1;
}


/*!
* \brief
* Adds a Magazine to the MagazineStorage.
*
* \param[in] _magazine
* The Magazine to add.
*
* \returns
* Returns the Magazine ID. 0 indicates, that the MagazineStorage is full and that the magazine can't be added.
*
*/
unsigned int MagazineStorage::addMagazine (Magazine* _magazine) //0 = Error
{
std::vector<Magazine*>::iterator iter;

unsigned int i = 1;

for( iter = vMagazines.begin(); iter != vMagazines.end(); iter++, i++)
{
if ((*iter) == NULL)
{
(*iter) = _magazine;
return i;
}
}

return 0;
}

/*!
* \brief
* If exists, it returns the Magazine with the ID _id.
*
* \param[in] _id
* The Magazines ID.
*
* \returns
* The Magazine, or if it does not exist NULL.
*
*/
Magazine *MagazineStorage::getMagazine (unsigned int _id)
{
if(_id <= mSize && vMagazines[_id - 1])
{
return vMagazines[_id - 1];
}

return NULL;
}

/*!
* \brief
* Updates all Magazines with an update flag by the given time.
*
* \param[in] _elapsed_time
* Time elapsed since last update.
*
* Updates all Magazines with an update flag by the given time.
*
* \see
* manuallyUpdateFlagMagazines
* Magazine::updateShells
* StoreItem::update
*/
void MagazineStorage::manuallyUpdateFlagMagazines(Ogre::Real _elapsed_time)
{
std::vector<Magazine*>::iterator iter;

for (iter = vMagazines.begin(); iter != vMagazines.end(); iter++)
{
if((*iter) && (*iter)->getUpdateFlag())
{
(*iter)->updateShells(_elapsed_time);
}
}
}

/*!
* \brief
* Updates all Magazines by the given time.
*
* \param[in] _elapsed_time
* Time elapsed since last update.
*
* Updates all Magazine by the given time.
*
* \see
* manuallyUpdateAllMagazines
* Magazine::updateShells
* StoreItem::update
*/
void MagazineStorage::manuallyUpdateAllMagazines(Ogre::Real _elapsed_time)
{
std::vector<Magazine*>::iterator iter;

for (iter = vMagazines.begin(); iter != vMagazines.end(); iter++)
{
if((*iter))
{
(*iter)->updateShells(_elapsed_time);
}
}
}

/*!
* \brief
* Deletes the pointer of the Magazine with the ID _id.
*
* \param[in] _id
* Description of parameter _id.
*
* \returns
* Returns the pointer of the removed Magazine. If no Magazine with the given ID exists, it returns NULL.
*
*
* Possible usage, deleting the storage and all magazines in it:
*
* unsigned int size = MagazineStorage::getSingleton().getStorageSize();
* Magazine *tmp = NULL;
*
* for (unsinged int i = 0; i < size; i++)
* {
* if (tmp = MagazineStorage::getSingleton().removeMagazine(i + 1))
* {
* delete tmp;
* }
* }
*
*/
Magazine *MagazineStorage::removeMagazine (unsigned int _id)
{
Magazine* mag = NULL;

if(_id <= mSize && vMagazines[_id - 1])
{
mag = vMagazines[_id - 1];
vMagazines[_id - 1] = NULL;
}

return mag;
}

/////Magazine

/*!
* \brief
* Magazine constructor.
*
* \param[in] _size
* Description of parameter _size.
*
* \throws <exception class>
* Description of criteria for throwing this exception.
*
* Creates a Magazine with the given size.
*
* \remarks
* The UpdateFlag is per default set "false".
*
* \see
* Magazine::setUpdateFlag
*/
Magazine::Magazine (unsigned int _size)
{
mSize = _size;

vShells.clear();

for (unsigned int i = 1; i <= mSize; i++)
{
vShells.push_back(new MagazineShell(i));
}

mUpdateFlag = false;
}



/*!
* \brief
* Magazine destructor.
*
* Deletes all MagazineShells in the Magazine.
*
* \remarks
* If you delete a shell, the StoreItem in it is deleted, too.
*
* \see
* MagazineShell::~MagazineShell
*/
Magazine::~Magazine()
{
std::vector<MagazineShell*>::iterator iter;

for( iter = vShells.begin(); iter != vShells.end(); iter++)
{
if ((*iter))
{
delete (*iter);

}
}
}


/*!
* \brief
* Returns an uninitialised Shell.
*
* \returns
* Returns an uninitialised Shell. If there is no uninitialised shell left, it returns NULL.
*
* Searches for an uninitialised shell and returns it. Use this method to fill the Magazine.
*
* \see
* MagazineShell::initializeShell
*/
MagazineShell *Magazine::getUninitialisedShell ()
{

std::vector<MagazineShell*>::iterator iter;

for (iter = vShells.begin(); iter != vShells.end(); iter++)
{
if (!(*iter)->getInitialised())
{
return (*iter);
}
}

return NULL;
}

/*!
* \brief
* Returns an inactive StoreItem.
*
* \returns
* Returns an inactive StoreItem. If all items are active or uninitialised it returns NULL.
*
* Searches for an inactive shell and returns it. Uninitialised shells are not returned.
*/
StoreItem *Magazine::getInactiveStoreItem ()
{
std::vector<MagazineShell*>::iterator iter;

for (iter = vShells.begin(); iter != vShells.end(); iter++)
{
if (!(*iter)->shellLocked() && !(*iter)->getActive())
{
(*iter)->lockShell();
return ((*iter)->getStoreItem());
}
}

return NULL;
}

/*!
* \brief
* Returns the size of the Magazine.
*
* \returns
* Returns the size of the Magazine
*/
unsigned int Magazine::getNumberShellsTotal ()
{
return mSize;
}

/*!
* \brief
* Returns the number of unused Shells.
*
* \returns
* Returns the number of unused Shells.
*
* Returns the number of unused Shells, uninitialised shells included.
*
* \see
* getNumberShellsUnused
*/
unsigned int Magazine::getNumberShellsUnused ()
{
unsigned int result = 0;
std::vector<MagazineShell*>::iterator iter;

for (iter = vShells.begin(); iter != vShells.end(); iter++)
{
if (!(*iter)->shellLocked())
{
result++;
}
}
return result;
}

/*!
* \brief
* Returns the number of uninitialised shells.
*
* \returns
* Returns the number of uninitialised shells.
*
* Returns the number of uninitialised shells.
*
* \see
* getNumberShellsUnused
*/
unsigned int Magazine::getNumberShellsUninitialised ()
{
unsigned int result = 0;
std::vector<MagazineShell*>::iterator iter;

for (iter = vShells.begin(); iter != vShells.end(); iter++)
{
if (!(*iter)->getInitialised())
{
result++;
}
}
return result;

}

/*!
* \brief
* Updates the shells by the given time.
*
* \param[in] _elapsed_time
* The time since last update.
*
* Updates the shells by the given time.
*
* \see
* manuallyUpdateAllMagazines
* manuallyUpdateFlagMagazines
* StoreItem::update
*/
void Magazine::updateShells (Ogre::Real _elapsed_time)
{

std::vector<MagazineShell*>::iterator iter;

for (iter = vShells.begin(); iter != vShells.end(); iter++)
{
if (!(*iter)->getActive())
{
(*iter)->updateShell(_elapsed_time);
}
}
}

/*!
* \brief
* Chose if the magazine shall be updated.
*
* \param[in] _true
* Chose if the magazine shall be updated.
*
* Chose if the magazine shall be updated by the expired time at frame end.
*
*/
void Magazine::setUpdateFlag (bool _true)
{
mUpdateFlag = _true;
}

bool Magazine::getUpdateFlag ()
{
return mUpdateFlag;
}



////MagazineShell


/*!
* \brief
* MagazineShell constructor.
*
* \param[in] _number
* The shells number. For future use.
*
* MagazineShell constructor.
*
*/
MagazineShell::MagazineShell(unsigned int _number) :mActive(false), mInitialised(false), mLocked(true), mNumber(_number){
}

/*!
* \brief
* MagazineShell destructor.
*
* MagazineShell constructor. It deletes the object stored in it.
*/
MagazineShell::~MagazineShell (){
if(mStoreItem)
{
delete mStoreItem;
}
}




/*!
* \brief
* Use this method to store an object of the type or subtype StoreItem in the shell.
*
* \param[in] _store_item
* The item beeing stored.
*
* Use this method to store an object of the type or subtype StoreItem in the shell.
*/
void MagazineShell::initializeShell(StoreItem *_store_item)
{
mStoreItem = _store_item;
mStoreItem->setMagazineShell(this);
mInitialised = true;
mLocked = false;
}

/*!
* \brief
* Sets the Shell and Object active. Simply calls the set active method of the StoreItem.
*
* \param[in] _true
* Description of parameter _elapsed_time.
*
* Sets the Shell and Object active. Simply calls the set custom method of the object.
*
* \see
* StoreItem::setActive
* StoreItem::custimizedActive
*/
void MagazineShell::setActive(bool _true)
{
mActive = _true;

mStoreItem->custimizedActive(_true);
}


/*!
* \brief
* Updates the shell by the given time.
*
* \param[in] _elapsed_time
* The time since last update.
*
* Updates the shell by the given time.
*
* \see
* manuallyUpdateAllMagazines
* manuallyUpdateFlagMagazines
* Magazine::updateShells
*/
void MagazineShell::updateShell(Ogre::Real _elapsed_time)
{

mStoreItem->update(_elapsed_time);
}

/*!
* \brief
* Returns the Shell to the Magazine.
*
*
* Use this method to return the Shell to the Magazine. It is the only clean way to do this.
*
* \see
* StoreItem::returnStoreItem
*/
void MagazineShell::returnShell()
{
mActive = false;
mLocked = false;

mStoreItem->setActive(false);
}

bool MagazineShell::getInitialised()
{
return mInitialised;
}

bool MagazineShell::getActive()
{
return mActive;
}

unsigned int MagazineShell::getNumber()
{
return mNumber;
}

void MagazineShell::lockShell(bool _true)
{
mLocked = _true;
}

bool MagazineShell::shellLocked()
{
return mLocked;
}

/*!
* \brief
* Returns the stored StoreItem.
*
* \returns
* Returns the stored StoreItem.
*
* Returns the stored StoreItem. You'll have to cast it to your class type.
*
* \see
* Example code at the begin of the file.
*/
StoreItem *MagazineShell::getStoreItem()
{
return mStoreItem;
}



//StoreItem

betajaen

26-09-2006 11:01:24

Excellent, I certainly shall be using this in Eos.

Any chance you can repost the code in the Tips post for me, until the new Wiki is up? (I tried doing a split/merge but couldn't find any merge option).

BlasterN

26-09-2006 11:27:08

* <Build a new class of type StoreItem>
Why not use a template class? maybe it's enought for some people.
And who want more control, derive the class and add more features.

btw: license?

M@gg!

26-09-2006 12:46:33

* <Build a new class of type StoreItem>
Why not use a template class? maybe it's enought for some people.


Yes, my original intention was to use templates and I realy tried, but the problem is as following.

If StoreItem is a template class, then you'll have to make MagazineShell a template to. When MagazineShell is a template, Magazine has to be one too. And so on. In the end the whole System doesn't work, because you have to create a System Store for each type of Magazine.

But use templates rarely, so it may be a cause of my nescience. Have you got an idea how to realize it?


btw: license?


First test it, if it's usefull. After this I'll start thinking about licenses. When Betajean in the end realy wants to integrate it in NxOgre, I think it'd be the same license.

betajaen

26-09-2006 17:06:28

It's jaen people.

LGPL would be the license then, depending if it goes into NxOgre or may reside in the prefabs, or even a separate prefab download.

[Edit]

What I mean is. I had the idea of "prototype" bodies and models; More of an intelligent blueprint system where (also shown better in the Karma thread). I could do this:

mScene->fromModel("cake")->create("myCake", Vector3(0,10,0));

As far as I understand it your system does this too (in a very different way of course!)

M@gg!

20-11-2006 19:07:43

Hi Betajaen,

hope you are fine! I'm happy to see, that you are still working on NxOgre. Sadly :cry: I haven't got the time to keep on track, but some day I'll be back on PhysX.

What's about your plans to integrate the MagazineStorage? Are you still planing to do so?

CaseyB

20-11-2006 19:09:01

It's jaen people.Why is it jaen? What does betajean mean?

betajaen

20-11-2006 19:10:40

Oh that's a story and a half.

Game_Ender

20-11-2006 23:35:38

I believe these are commonly called memory pools. If you are not afraid of boost check out the already templated Boost.Pool.

M@gg!

21-11-2006 14:55:55

I believe these are commonly called memory pools. If you are not afraid of boost check out the already templated Boost.Pool.

Take a closer look to the feature description. It is not a memory manager, you'll have to handle this still by your own, but perhaps, it might be a funny new feature *hm...*.


Betajaen:
Have you overlooked my post?

betajaen

21-11-2006 16:51:25

Betajaen:
Have you overlooked my post?


Your post is 2 months old. Did you want me to reply to it?

M@gg!

22-11-2006 00:28:07

Hi Betajaen,

hope you are fine! I'm happy to see, that you are still working on NxOgre. Sadly :cry: I haven't got the time to keep on track, but some day I'll be back on PhysX.

What's about your plans to integrate the MagazineStorage? Are you still planing to do so?


;-) 2 months! You are getting old ;-)

Wretched_Wyx

22-11-2006 06:26:57

Oh my... that's funny. I wish I could see and hear him when he reads that.

betajaen

22-11-2006 09:54:02

What? I am old, I'm 52.

dudeabot

27-06-2007 22:17:39

how to use this?

(i know theres doxygen , but it is more class viewer thing?)

M@gg!

14-12-2007 09:20:02

Hi Betajaen,

hope you are fine! I see you are lively like before :D and still developing this fine piece of wrapper.

I think in 3 or 4 month I'll use the PhysX stuff again, so I'll be more frequently a guest here.

how to use this?

(i know theres doxygen , but it is more class viewer thing?)


Sadly was having realy rarely a look in this forum in the last year, so my answer is a litle outdate, but maybe others are interested in it.

The use of the MagazineStorage needs a litle work to make yourselfe comfortable with it. To do so read the tutorial at the beginning of the source code. You don't need Doxygen for it.

The functions are commented for Doxygen but Visual Studio can show the comments too and you don't need knowledge about Doxygen comments.

Anyhow some small hints for reading:
\brief - means short description
\param - describes for what the parameter is used
\see - is kind of a link
\return - is the decription of the return value

Best regards
M@gg!