Design help needed (UML overview)

Started by
14 comments, last by swinchen 18 years, 8 months ago
So here are my goals: To create a 2D top view side map that can smoothly scroll. Right now I am simply going for a single layer, textured quads map. Below is my start to a UML diagram for this. If you take a look please be very critical and let me know what I might be doing wrong. I am new to the design process like this. (I know that CView is not complete) Free Image Hosting at www.ImageShack.us My biggest problem is figuring out how everything snaps together. It is the Object Oriented design that is throwing me. Thanks for any comments! Sam
Advertisement
I don't know too much about your overall plans, so for me it looks rather ok.

However, few things spring out to mind:

1. Why CMap is contained in CView, and not the other way round? If I was you, I wouldn't even contain any of them inside the other one, and just pass pointer to CView to CMap::draw (that way you could also get rid of additional arguments in draw), along with additional CRectangle struct (which would tell where is the physical portion on screen where it may render map) - using this method, it would be pretty easy to introduce split screen or Half Life - like camers. But remember that I know very little about your game, so I might be wrong.

2. It's very simple UML class diagram - great, you have achieved KISS :-)

3. Passing GLuint by reference helps in nothing, especially - it doesn't have any effects (positive or negative) on performance. So, you can delete all & in function declarations :-)

4. Maybe try abstracting GLuint to CTexture or sth like that (I'm referring to CMapElement::setTexture)? After some time you may discover that you need other features or attributes (not only simple GL texture handler) and then you would need to add more arguments to setTexture. But when you'll be using classess, any additions are kept private. OTOH, I know nothing about your resource loading / sharing methods, so once again, I may be wrong.

HTH :-)
Wow, I have a really really hard time with object oriented design.

Now not including CMap in CView... would they be connected by a one way association?

I wouldnt have thought of leaving them seperate. Are those the only two you would seperate?

Right now I dont really have any resource loading, I am just trying to figure out a simple, robust design for map.

I basically just want to scoll a bunch of quads around (that can have different textures) and figure out which ones to draw on the screen (hence CView)

When I was designing CView I think I was trying to make it a lot like CRectangle.. it has start coordinates and a height and width. This is the actual physical viewport dimensions.

Thanks for the tips.
Quote:Original post by swinchen

Now not including CMap in CView... would they be connected by a one way association?

I wouldnt have thought of leaving them seperate. Are those the only two you would seperate?


In my previous post I meant that they wouldn't be connected by aggregation in any direction (nor CView in CMap, nor CMap in CView), and CMap::draw would get CView in function parameter (but it wouldn't save that ptr to CView anywhere!).

That way, by separating them you would achieve greater flexibility (ie. split screen and cameras) - but if you don't need such features and you're sure that nothing will change, ok - stay with your original design.

And yes, CMap and CView were the only things I would separate.

Quote:Original post by swinchen
Right now I dont really have any resource loading, I am just trying to figure out a simple, robust design for map.


Ok, but you will need one, and it's better to design it, while you're designing systems that will be using it (ugh, sorry for my english :-/ )
Ok, here is revision #2.

Free Image Hosting at www.ImageShack.us

I changed the name of the classes a little, just to make it a little clearer.

Notice that CLevel is aware of CCamera, and CTexture through association, but they are not actually part of eachother.

I think this looks quite a bit better. Thanks for the suggestions so far. And don't worry about your English! I promise that you know a lot more English than I know any other language.

Sam
Quote:
I think this looks quite a bit better. Thanks for the suggestions so far.


Indeed, it looks rather nice.

Few comments:

1. Does italic text in CObject::draw means that this function is virtual? If yes (and IIRC it's true), than it's clear that you are planning also other types to derive from it (ie. CPlayer, CMonster etc.). Out of curiosity - what other classess are you planning?

2. CLevel::m_mapdata is defined as single pointer, which of course can be interpreted as one-dimensional array. Since you can be creating 2D platformer or 2D game with view from top ("2D top view side map that can smoothly scroll"), you should use two dimensional array (CMapElement ** m_mapdata). Ok, that was probably a typo :-) not design flaw.

3. CTexture::setTexID IMHO should be replaced with bool loadFromFile(const std::string & filename) which would be responsible for loading picture and setting private id member.

OTOH, that what I have written in previous sentence probably would ruin your performance and would eat huge amount of memory if you was loading multiple times the same texture for all possible tiles.

In this case it would be best to implement another class, CTextureMgr, which would be responsible for texture sharing (ie. not loading the same texture multiple times). If you're planning to load textures also for other things (UI, player and monster sprites, mouse cursor etc.), it's the best advice I can give you - design and implement CTextureMgr before it's too late - you don't want to end up copying n' pasting the same code responsible for loading textures, to N other classess (where probably N > 4 + rand()%3).

4. Why "CLevel is aware of (...) CTexture through association"? There's no CTexture in CLevel public API, so probably you are planning to obtain texture id from each tile texture in CLevel::draw, glBindTexture() it, and render, right? My comment is the same as in 3 - make responsible for rendering CTexture ( fortunately, you can do it without any performancy or memory penalties this time) or introduce another class, CRenderer, which would be responsible for abstracting such operations (ie. void drawTexture(const CTexture * texture). CRenderer could also have functions like drawLine, drawText etc.


But don't treat my comments too seriously - still I know nothing about your game, your plans, your skills and experience in programming, what libraries you are using etc. so my suggestions may help you, or they may hurt you - use them at your own risk ;-) and think carefully will they interfere correctly with your other classess that I don't know about.

Quote:
And don't worry about your English! I promise that you know a lot more English than I know any other language.


Who knows, who knows ;-) My comment was reffering to "Ok, but you will need one, and it's better to design it, while you're designing systems that will be using it" which sounds strange :-/
Wow, thanks for the help... this is great.

#1) Yep, draw() is a pure virtual function (CObject is abstract). I am planning things like CItem, CPlayer, CEnemy, CNPC (maybe) and possibly much more.

#2) I was actually going to implement it like this:

m_mapData = new CTile[m_width*m_height];

Then I could access it like a normal 2D array... m_mapData[2][3]; for example.

It would probably be best for me make a class CArray2D or something like that.

#3) I was just thinking about that. I was going to have CMap::loadFromFile handle loading textures and applying them to each tile. This is probably not a very good way to do this because I can not reuse it. I think your suggestion for CTextureMgr is a very valid one! So a texture manager would need to:

a) Be able to load textures from a file.
b) Store all available textures with some form of unique key. (probably name?)
b.1) This would also allow me to keep track of which textures have already been loaded.
c) Return the desired texture id (not sure how to query it... probably by name?)
d) Free a texture.

Am I missing anything?

So maybe it should be something like:
CTile::m_texID = CTextureMgr::queryTexture("HorribleEnemy.tga");

#4) See #3... you hit the nail right on the head.
Hmm, so if I draw the texture in CTexture... CTile doesnt do much at this point!

It looks like CRenderer might be a good idea.

Thanks again!

Heh, no prob ;-)

Quote:
So a texture manager would need to:

a) Be able to load textures from a file.
b) Store all available textures with some form of unique key. (probably name?)
b.1) This would also allow me to keep track of which textures have already been loaded.
c) Return the desired texture id (not sure how to query it... probably by name?)
d) Free a texture.

Am I missing anything?

So maybe it should be something like:
CTile::m_texID = CTextureMgr::queryTexture("HorribleEnemy.tga");


Yup, you're right. One thing what you might want adding, are groups - each texture should belong to some of them. Ie. group "Player" would be responsible for keeping player sprites, group "Tiles" would keep tiles, group "Monsters" would keep monsters, group "UI" would keep... ok, enough :-)


If you're curious about implementation of CTextureMgr, here's source code of mine. It's very simple - uses std::map with key: string and value: texture, which makes all the texture lookups very fast - O(log n). There's also reference counting used, so that manager knows in how many places each texture is used, and if refCount equals 0, it can safely free this texture. This manager is also very simple to code, debug, and use. So, I would recommend you to write sth like this:

Header:

#ifndef TEXTUREMGR_H#define TEXTUREMGR_H/*! \file textureMgr.h     \brief File tha contains interface of texture loading system.*/// ------------------------------------------------- #include "../../Others/Misc/basicTypes.h"#include "../../Others/Misc/singleton.h"#include <gl/gl.h>#include <map>// ------------------------------------------------- //! Use this macro to get access to texture manager.#define getTextureMgr SC::TextureMgr::get()namespace SC  {// -------------------------------------------------         //! Handle for texture, filled by GetTextureID or UseTexture.  struct TextureHandle   {     GLuint id;     slint width, height; //!< Sizes that this bmp has in memory (it may be physicalWidth rounded to next power of 2).     slint physicalWidth, physicalHeight; //!< Sizes that this bmp has when on disk.     usint refCount;        };        //! Class that is responsible for loading and managing textures.  //! It allows loading only textures from files that are: .png, .jpg, .gif, .bmp, with all standard color depths.  class TextureMgr : public Singleton<TextureMgr>   {    public:        bool Init();     void Shutdown();    // -------------------------------------------------      //! Loads textures into memory (_textureList is string of texture names separated with spaces)     //! SkinSystem prefix is added before each directory and texture name, however, you don't need to     //! manually add anything if you for example use GetTextureID (nor skin prefix or _directory).     //! \param _directory Should end with /     //! \return Number of not-loaded textures.     ssint LoadTextures(const char * _groupName, const char * _textureList, const char * _directory = "");          //! Similiar to LoadTextures but loads only one texture at a time.     //! \return True if texture was succesfully loaded.     bool LoadTexture(const char * _groupName,  const char * _textureName, const char * _directory = "");     //! Fills _out with data of appropriate texture.     void GetTextureID(TextureHandle & _out, const char * _groupName, const char * _textureName);          //! Texture will be finally released when it's reference count will be equal to 0.     void ReleaseTexture(const char * _groupName, const char * _textureName);          //! Texture will be finally released when it's reference count will be equal to 0.     //! Updates passed _handle with new reference count - when it hits 0, texture is truly released     //! and can't be used anymore.     void ReleaseTexture(const char * _groupName, TextureHandle & _handle);          //! Forces release of one group with all of its textures (reference counts etc. are ignored).     void ReleaseTextureGroup(const char * _groupName);          //! Forces release of all textures from all groups (reference counts etc. are ignored).     void ReleaseAllGroups();       private:                       // -------------------------------------------------          	 struct string_less 	  {	  		bool operator() (const char * left, const char * right) const		 { 	    		  return strcmp(left,right) < 0;	     		 }	  };  // -------------------------------------------------           // single texture group     typedef std :: map < std :: string , TextureHandle > TextureGroup;     typedef TextureGroup :: iterator TextureGroupItor;          typedef std :: pair < std :: string, TextureHandle> TextureGroupPair;                        // map of textures     typedef std :: map <const char*, TextureGroup*, string_less > Textures;     typedef Textures :: iterator TexturesItor;     typedef std :: pair <const char*, TextureGroup* > TexturesPair;     // -------------------------------------------------                bool LoadTexture(const TexturesItor & _itor, const char * _directory, const char * _textureName);          Textures textures;                };   // -------------------------------------------------          }#endif


Implementation:

#include "textureMgr.h"using namespace std;typedef basic_string <char> :: size_type StrPos;// cast prevents from unnecessary warning about assigning to unsigned int negative numberconst StrPos npos = (static_cast<StrPos> (-1));const char * gfxLogFile = "gfxLog.txt";// ------------------------------------------------- start Initbool SC :: TextureMgr :: Init() {  log2("TextureMgr","Succesfully created.")      logAttachTo(gfxLogFile)  logDumpStdHeader;  logAttatchToPrevious;  textures.clear();  return true; }   // ------------------------------------------------- end Init// ------------------------------------------------- start Shutdown   void SC :: TextureMgr :: Shutdown() {  bool wasError = false;    if (!textures.empty())   {    wasError = true;        // assums it is called when log.txt is active    logError2("TextureMgr","There are unreleased resources still existing, see gfxLog.txt for details.")	logAttachTo(gfxLogFile)	    TexturesItor groupItor;    TextureGroupItor textureItor;      log("This file contains list of unreleased texture objects, that were found alive while trying to close the engine.")	log("Please contact with author of application and send him this file, as well as main log.txt file.")        for (groupItor = textures.begin(); groupItor != textures.end(); ++groupItor)     {      log2("From group", (groupItor->first));                  for (textureItor = (groupItor->second)->begin(); textureItor != (groupItor->second)->end(); ++ textureItor)       {        log2("Texture", (textureItor->first))            glDeleteTextures(1, &textureItor->second.id);                   }               delete (groupItor->second);     }                     textures.clear();        }   // -------------------------------------------------     if (textures.empty() && (!wasError))   {    logAttachTo(gfxLogFile)   }  logDumpStdFooter;  logClose;                          log2("TextureMgr", "Succesfully destroyed.")  }   // ------------------------------------------------- end Shutdown// ------------------------------------------------- start LoadTexturesSC :: ssint SC :: TextureMgr :: LoadTextures(const char * _groupName, const char * _textureList,                                             const char * _directory) {  if (!getRenderer.IsEnabled())   {    logError2("TextureMgr", "Must be in graphic mode in order to load textures.")    return 0;   }      TexturesItor groupItor = textures.find(_groupName);        if (groupItor == textures.end())   {	// no such group, create new	TextureGroup * ptr = new TextureGroup();    	if (!ptr) 	 {	  logError2("TextureMgr", "Not enough memory to create new texture group.")	  return (-1);	 }     	groupItor = ( textures.insert( TexturesPair(_groupName, ptr)) ).first;         }     // -------------------------------------------------     // follow mod architecture design    string directory(getSkinSystem.GetDirectoryPrefix());  directory += _directory;       // first delete whitespaces at the end of texture list  string tmp(_textureList);        reverse( tmp.begin(), tmp.end() );      StrPos firstNotSpaceValue = tmp.find_first_not_of(" ");       // no spaces means it's directly glued to left margin(after reverse) , but npos == -1...  if (firstNotSpaceValue == npos)      firstNotSpaceValue = 0;                      string textureList( tmp.substr(firstNotSpaceValue) );         reverse( textureList.begin(), textureList.end() );              string singleTexture;  StrPos endOfName = 0;  StrPos startOfName = 0;  bool end = false;      usint failures = 0;  // -------------------------------------------------     logAttachTo(gfxLogFile)  beginG("Loading textures")  log2("Group", _groupName);    do    {       endOfName = textureList.find(" ", endOfName);        if (endOfName == npos)      {      endOfName = textureList.size();      end = true;     }                  string textureName ( textureList.substr(startOfName, endOfName - startOfName));                        if (!LoadTexture(groupItor, directory.c_str(), textureName.c_str()))     {      string tmp("Couldn't load texture: ");      tmp += textureName;      logError2("TextureMgr", tmp.c_str());      ++failures;           }        ++endOfName;    startOfName = endOfName;                                      } while (!end);     endG;   logAttatchToPrevious;   // -------------------------------------------------         return failures; }// ------------------------------------------------- end LoadTextures// ------------------------------------------------- start LoadTexture publicbool SC :: TextureMgr :: LoadTexture(const char * _groupName,  const char * _textureName, const char * _directory) {  if (!getRenderer.IsEnabled())   {    logError2("TextureMgr", "Must be in graphic mode in order to load texture.")    return 0;   }      TexturesItor groupItor = textures.find(_groupName);        if (groupItor == textures.end())   {	// no such group, create new	TextureGroup * ptr = new TextureGroup();    	if (!ptr) 	 {	  logError2("TextureMgr", "Not enough memory to create new texture group.")	  return (-1);	 }     	groupItor = ( textures.insert( TexturesPair(_groupName, ptr)) ).first;         }     // -------------------------------------------------     // follow mod architecture design    string directory(getSkinSystem.GetDirectoryPrefix());  directory += _directory;       logAttachTo(gfxLogFile)  if (!LoadTexture(groupItor, directory.c_str(), _textureName))     {      string tmp("Couldn't load texture: ");      tmp += directory;      tmp += _textureName;      tmp += " for group: ";      tmp += _groupName;      logError2("TextureMgr", tmp.c_str());      logAttatchToPrevious;      return false;           }  #ifdef __SC_LOG_TEXTURE_SINGLE_GROUP__  log2("From group", _groupName);  #endif       logAttatchToPrevious;  return true;    }    // ------------------------------------------------- end LoadTexture public// ------------------------------------------------- start LoadTexture helperbool SC :: TextureMgr :: LoadTexture(const TexturesItor & _itor, const char * _directory, const char * _textureName) {  string filename(_directory);  filename += _textureName;      TextureGroupItor textureItor = _itor->second->find(_textureName);       if (textureItor != _itor->second->end())   {    ++(textureItor->second.refCount);            #ifdef __SC_LOG_TEXTURE_REUSE__     log2("Reusing", filename);    #endif    return true;   }          #ifdef __SC_LOG_TEXTURE_NEW__   log2("New", filename)  #endif    if (!fileExists(filename.c_str())) return false;// -------------------------------------------------   SDL_Surface * tmp = IMG_Load(filename.c_str());     if (tmp == 0) return false;    // first check whether it is needed to expand texture size to powers of 2    usint w = tmp->w;    usint h = tmp->h;  usint physicalW = tmp->w;  usint physicalH = tmp->h;    SDL_Surface * image = tmp; // create alias    bool IsWidth = IsPowerOfTwo(w);  bool IsHeight = IsPowerOfTwo(h);   // -------------------------------------------------        if ((!IsWidth) || (!IsHeight) || (tmp->format->BitsPerPixel != 32))   {    #ifdef __SC_LOG_TEXTURE_STARTUP__      if ((!IsWidth) || (!IsHeight)) debug("This texture needs to be resized during startup.")      if (tmp->format->BitsPerPixel != 32) debug("This texture needs to have altered color depth.")      debug("In release versions, please remember to fix it so startups will be much shorter.")    #endif          if (!IsWidth) w = PowerOfTwo(w);	if (!IsHeight) h = PowerOfTwo(h);// -------------------------------------------------		Uint32 rmask, gmask, bmask, amask;    /*	 SDL interprets each pixel as a 32-bit number, so our masks must depend on the endianness	 (byte order) of the machine	*/    #if SDL_BYTEORDER == SDL_BIG_ENDIAN      rmask = 0xff000000;      gmask = 0x00ff0000;      bmask = 0x0000ff00;      amask = 0x000000ff;    #else      rmask = 0x000000ff;      gmask = 0x0000ff00;      bmask = 0x00ff0000;      amask = 0xff000000;    #endif// -------------------------------------------------	// now image is no longer alias to tmp, rather that new surface	image = SDL_CreateRGBSurface(SDL_SWSURFACE /*| SDL_SRCALPHA*/, w, h, 32, rmask, gmask, bmask, amask);		if ( image == 0 ) 	 {      logError2("TextureMgr", "Couldn't allocate memory for expanding texture to power of 2")      SDL_FreeSurface(tmp);	  SC_ASSERT(!"Couldn't allocate memory for expanding texture to power of 2")	  return false;	 }      SDL_Rect area;	area.x = 0;	area.y = 0;	area.w = tmp->w;	area.h = tmp->h;	// it was fucking stupid bug with 32 bpp textures that needed to be resized	if ( tmp->format->BitsPerPixel == 32)     SDL_SetAlpha(tmp, 0, 0);	// copy the tmp into the new GL texture image	SDL_BlitSurface(tmp, &area, image, &area);		SDL_FreeSurface(tmp);	tmp = 0;   }// -------------------------------------------------       TextureHandle textureHwnd;     glGenTextures(1, &textureHwnd.id);    glBindTexture(GL_TEXTURE_2D, textureHwnd.id);            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);           glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);       textureHwnd.width = w;  textureHwnd.height = h;  textureHwnd.physicalWidth = physicalW;  textureHwnd.physicalHeight = physicalH;  textureHwnd.refCount = 1;    if (tmp) SDL_FreeSurface(tmp);   else SDL_FreeSurface(image);    // now add it to map 					     (_itor->second)->insert(TextureGroupPair(_textureName, textureHwnd));  return true; }// ------------------------------------------------- end LoadTexture helper        // ------------------------------------------------- start GetTextureID        void SC :: TextureMgr :: GetTextureID(TextureHandle & _out, const char * _groupName, const char * _textureName) {  TexturesItor groupItor = textures.find(_groupName);      if (groupItor == textures.end())   {    _out.id = 0;    #ifdef __SC_LOG_GROUP_NOT_FOUND__    logError2("TextureMgr", "Not found specified group.")    #endif    return;   }    else    {    TextureGroupItor textureItor = (groupItor->second)->find(_textureName);        if (textureItor == (groupItor->second)->end())     {      _out.id = 0;      #ifdef __SC_DEBUG__      logError2("TextureMgr", "Not found specified texture.")      #endif      return;      }       else      {       _out = textureItor->second;       return;      }           }      }// ------------------------------------------------- end GetTextureID// ------------------------------------------------- start ReleaseTexture    void SC :: TextureMgr :: ReleaseTexture(const char * _groupName, const char * _textureName) {  TexturesItor groupItor = textures.find(_groupName);        if (groupItor == textures.end())   {    #ifdef __SC_LOG_GROUP_NOT_FOUND__    logError("ReleaseTexture, couldn't find group.")    logError2(_groupName, _textureName);    SC_ASSERT(0)    #endif    return;   }  TextureGroupItor textureItor = (groupItor->second)->find(_textureName);    if (textureItor == (groupItor->second)->end())   {    #ifdef __SC_DEBUG__    logError("ReleaseTexture, couldn't find texture.")    logError2(_groupName, _textureName);    SC_ASSERT(0)    #endif    return;   }// -------------------------------------------------//  printVal(textureItor->second.refCount)  --(textureItor->second.refCount);    if (textureItor->second.refCount == 0)   {    glDeleteTextures(1, &textureItor->second.id);    //    logAttachTo(gfxLogFile) <--- here's bug//    log2("Released individual texture", _textureName); // it should be redirected to gfxLog, but here's stupid bug        (groupItor->second)->erase(textureItor);// -------------------------------------------------     // try to release whole group     if (groupItor->second->size() == 0)      {//       log2("Group is now empty, so can be released", _groupName);       delete (groupItor->second);       textures.erase(groupItor);      }      //    logAttatchToPrevious; <--- here's bug   }       }// ------------------------------------------------- end ReleaseTexture// ------------------------------------------------- start ReleaseTexturevoid SC :: TextureMgr :: ReleaseTexture(const char * _groupName, TextureHandle & _handle) {  TexturesItor groupItor = textures.find(_groupName);  if (groupItor == textures.end())   {    #ifdef __SC_LOG_GROUP_NOT_FOUND__    logError2("ReleaseTexture, couldn't find group", _groupName)    SC_ASSERT(0)    #endif    return;   }     for (TextureGroupItor textureItor = (groupItor->second)->begin(); textureItor != (groupItor->second)->end();      ++textureItor)   {    if (textureItor->second.id == _handle.id)     {      // we've found texture that should be released      --(textureItor->second.refCount);            _handle.id = textureItor->second.refCount;// -------------------------------------------------     if (textureItor->second.refCount == 0)      {       glDeleteTextures(1, &textureItor->second.id);       //    logAttachTo(gfxLogFile) <--- here's bug//    log2("Released individual texture", _textureName); // it should be redirected to gfxLog, but here's stupid bug      (groupItor->second)->erase(textureItor);// -------------------------------------------------      // try to release whole group      if (groupItor->second->size() == 0)      {//       log2("Group is now empty, so can be released", _groupName);       delete (groupItor->second);       textures.erase(groupItor);      }     }         return;   }     }    #ifdef __SC_DEBUG__  logError2("ReleaseTexture, couldn't find texture by handle, from group", _groupName)  SC_ASSERT(0)  #endif }// ------------------------------------------------- end ReleaseTexture// ------------------------------------------------- start ReleaseTextureGroupvoid SC :: TextureMgr :: ReleaseTextureGroup(const char * _groupName) {  TexturesItor groupItor = textures.find(_groupName);      if (groupItor == textures.end())    {    /*    #ifdef __SC_DEBUG__    logError2("ReleaseTextureGroup, couldn't find group", _groupName)    SC_ASSERT(0)    #endif    */    return;   }        if (groupItor->second->size() != 0)   {        logAttachTo(gfxLogFile)                log2("TextureMgr", "Releasing group of textures:")    beginG("Releasing textures")      for (TextureGroupItor textureItor = (groupItor->second)->begin(); textureItor != (groupItor->second)->end();         ++textureItor)     {      log((textureItor->first))      glDeleteTextures(1, &textureItor->second.id);             }      endG;    logAttatchToPrevious;   }           delete (groupItor->second);    textures.erase(groupItor);       }// ------------------------------------------------- end ReleaseTextureGroup// ------------------------------------------------- start ReleaseAllGroupsvoid SC :: TextureMgr :: ReleaseAllGroups() {  TexturesItor groupItor;  TextureGroupItor textureItor;    logAttachTo(gfxLogFile)  log2("TextureMgr", "Releasing all groups of textures:")  beginG("Releasing textures")      for (groupItor = textures.begin(); groupItor != textures.end(); ++groupItor)   {    log2("From group", (groupItor->first));              for (textureItor = (groupItor->second)->begin(); textureItor != (groupItor->second)->end(); ++ textureItor)     {      log((textureItor->first))      glDeleteTextures(1, &textureItor->second.id);                 }             delete (groupItor->second);      textures.erase(groupItor);           }                  endG;     textures.clear();  logAttatchToPrevious; } // ------------------------------------------------- end ReleaseAllGroups


Sample usage:

// ... {  // loading  TextureHandle picture;  if ( !getTextureMgr.LoadTexture("Player", "player_sprite_1.png") )   {    logError2("Player", "Couldn't load player sprite")    return false;   }  getTextureMgr.GetTextureID(picture, "Player", "player_sprite_1.png"); } // rendering  getRenderer.UseTexture(picture);  getRenderer.RenderTexture(/* where to render etc. */ );


HTH :-)
phew! Ok, so I am playing catch up a little bit. This is really my first C++ project of any size (I am used to C)

My plan was to use a hash table... is that basically what the structure of a map is?


Quote:typedef std :: map < std :: string , TextureHandle > TextureGroup;

So this looks like where you are actually storing each texture (with it's name being the key)

Quote:typedef TextureGroup :: iterator TextureGroupItor;

The iterator... :)

Quote:typedef std :: pair < std :: string, TextureHandle> TextureGroupPair;

I don't know what this is.


Quote:typedef std :: map <const char*, TextureGroup*, string_less > Textures;

Ok, storing an pointer to each group. Doing this because storing the actual group would be slow? In this case would const char* be the texture group name?

Quote:typedef Textures :: iterator TexturesItor;

:)

Quote:typedef std :: pair <const char*, TextureGroup* > TexturesPair;

Again I am not really sure what this is doing.




Now for a first run through I could just use a single std::map,

std::map<std:string, CTexture, less<string> > m_textures;

And then I could easily query the name. This might not be as well designed with the groups, but I am having a bit of a hard time understanding them.

Thanks man, this is a life saver!

Quote:
I don't know what this is.


That's typedef for the std::pair, which is used for inserting elements into map, like this:

groupItor = ( textures.insert( TexturesPair(_groupName, ptr)) ).first;


If you don't like the extra typedefs, last line could also be rewritten to:

groupItor = ( textures.insert( std::make_pair<const char *, TextureGroup * > (_groupName, ptr)) ).first;


Quote:
Ok, storing an pointer to each group. Doing this because storing the actual group would be slow? In this case would const char* be the texture group name?


Yup, generally it's better to store pointers to objects instead of objects in STL containers, since there won't be called copy constructor and destructor each time you want to do sth with stored value. Also, you're not wasting stack memory if you store pointers to heap. And yes, IIRC const char * is the texture group name.

Quote:
Now for a first run through I could just use a single std::map,

std::map<std:string, CTexture, less<string> > m_textures;

And then I could easily query the name. This might not be as well designed with the groups, but I am having a bit of a hard time understanding them.


If you'd like to learn more about STL, here are good links:

General STL, vectors, lists, deques.

Functors, sets, maps.

Btw, you don't need that less<string> when you're storing std::string, in my group typedef I needed it so that texture name's will be sorted lexicographically, and not by comparing pointers (without dereferencing it). That's why I needed that functor :-)

This topic is closed to new replies.

Advertisement