Thread: deleting objects, textures, and materials

  1. #1
    Registered User
    Join Date
    Jul 2006
    Posts
    15

    deleting objects, textures, and materials

    Full code in a wordpad file here:
    http://www.kryolinth.com/gamecodeV1_...estroyMesh.rtf

    Real simple. InitGeometry(); is called when you press the C key. "C" for "Create stuff" you can think of it as. Upon pressing the D key, it calls DestroyGeometry(); which is supposed to delete meshes, tetxures, and materials.

    The problem? Everything compiles fine, however I get an error when I press D to call DestroyGeometry.
    Code:
    VOID DestroyGeometry(int NUMOFOBJECTS)
    {
    	int w;
    	for(w=0;w<NUMOFOBJECTS;w++)
    	{
    		if( m_pMeshMaterials[w] )
    			delete[] m_pMeshMaterials[w];
    		if( m_pMeshTextures[w] )
    		{
    			for( DWORD i = 0; i < m_dwNumMaterials[w]; i++ )
    			{
    				if( m_pMeshTextures[w][i] )
    					m_pMeshTextures[w][i]->Release();
    			}
    			delete[] m_pMeshTextures[w];
    		}
    		if( m_pMesh[w] )
    			m_pMesh[w]->Release();
    	}
    }

    I load in two meshes with InitGeometry(2); The "2" tells the InitGeometry loop how many times to loop so it loads in 2 objects. So I use the same method with DestroyGeometry. DestroyGeometry(2); so it loops through the FOR loop twice for both objects.

    I did read that you have to be careful when deleting things, so I guess it's good that I'm asking about this before my computer blows up.

    I've messed around with this a bit.

    It likes this line: delete[] m_pMeshMaterials[w];

    But it doesn't like this one: m_pMeshTextures[w][i]->Release();
    That's where it messes up. The debugger doesn't seem to yield any useful information.

  2. #2
    The Right Honourable psychopath's Avatar
    Join Date
    Mar 2004
    Location
    Where circles begin.
    Posts
    1,071
    But it doesn't like this one: m_pMeshTextures[w][i]->Release();
    Because you haven't declared m_pMeshTextures as a multi-dimentional array.

    Try
    Code:
    if(m_pMeshTextures[i]){
         m_pMeshTextures[i]->Release();
    }
    Last edited by psychopath; 07-18-2006 at 12:42 PM.
    M.Eng Computer Engineering Candidate
    B.Sc Computer Science

    Robotics and graphics enthusiast.

  3. #3
    Registered User
    Join Date
    Jul 2006
    Posts
    15
    I tried your way, but it didn't work.

    The first time I use m_pMeshTextures, I have [g] on the end
    m_pMeshTextures[g] = new LPDIRECT3DTEXTURE9[m_dwNumMaterials[g]];

    Then a few lines down, I have
    m_pMeshTextures[g][i] = NULL;

    yet it was not declared as a multi-dimentional array
    LPDIRECT3DTEXTURE9* m_pMeshTextures[2];

    but when I use it as a multi-d array when loading the .x mesh and etc, it seems to work properly. I learned most of this code from a book, so if I'm doing something wrong with the arrays, the book must be teaching me wrong. I appologize for that.

  4. #4
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Code:
    LPDIRECT3DTEXTURE9* m_pMeshTextures[2];

    Looks suspicious.

    LPDIRECT3DTEXTURE9 is the declaration you use to declare a pointer to the interface.
    IDirect3DTexture9 is the declaration you use to declare the actual interface. - NOTE I said declaration. You cannot create an IDirect3DTexture9 object on the stack.

    From the SDK:
    The LPDIRECT3DTEXTURE9 and PDIRECT3DTEXTURE9 types are defined as pointers to the IDirect3DTexture9 interface.

    typedef struct IDirect3DTexture9 *LPDIRECT3DTEXTURE9, *PDIRECT3DTEXTURE9;
    Code:
    LPDIRECT3DTEXTURE9 m_pTexture;
    IDirect3DTexture9 *m_pTexture;
    These two lines accomplish the same thing.


    Code:
    class CTextureMgr;
    
    class CTexture
    {
      friend class CTextureMgr;
      IDirect3DTexture9 *m_pTexture;
      IDirect3DDevice9 *m_pDevice;
      ...
      void CreateFromFile(std::string File,IDirect3DDevice9 *pDevice)
      {
        D3DXCreateTextureFromFile(File.c_str(),pDevice,m_pTexture);
      }
    
      void CreateFromResource(std::string File);
      void CreateFromMemory(DWORD *pBuffer,DWORD dwSize);
    
      public:
        virtual ~CTexture()
        {
          if (m_pTexture)
          {
             m_pTexture->Release();
             m_pTexture=NULL;
          }
    
    };
    
    class CTextureMgr
    {
      std::vector<CTexture *> m_vTextures;
    
      public:
        virtual ~CTextureMgr()
        {
          for (DWORD i=0;i<static_cast<DWORD>m_vTextures.size();i++)
          {
             if (m_vTextures[i]) delete m_vTextures[i];
          }
          m_vTextures.clear();
       }
             
        DWORD AddFromFile(std::string File,IDirect3DDevice9 *pDevice)
        {
           CTexture *pTex=new CTexture;
           pTex->CreateFromFile(File,pDevice);          
           m_vTextures.push_back(pTex);
           return static_cast<DWORD>(m_vTextures.size()-1);
        }
        ...
    };
    Last edited by VirtualAce; 07-18-2006 at 01:06 PM.

  5. #5
    Registered User
    Join Date
    Jul 2006
    Posts
    15
    Why do I get the feeling all that code I've written is all for nothing and that my DirectX book is completely useless?

  6. #6
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Books show you examples on how to do A or B. What most of them fail to do is show you how to incorporate said function into a class. Either this is because it is their intent to teach DirectX and not class design, or it's because they feel that the added class overhead may complicate a simple explanation. I also feel it's because they are teaching you the fundamentals, they are NOT telling you how to design a class heirarchy around the DX API. They provide the building blocks and you put them all together.

    But here is the simple truth:

    If you cannot take the information in the book and assimilate it into your own design patterns using C++ design principles, you have no business messing with it as of yet.

    An engine will be a complex beast and you first must wrap the DX API in your core framework code. Then you can begin to build classes that use this framework.

    Note that in my own design, CTextureMgr inherits from CSingleton to inherit singleton functionality. As I said, things can get extremely complex. However, efficient and correct use of resources is vital to any code base. If your code does not do it correctly, no amount of flashy graphics, shaders, or sounds is going to cover up it's insistence on crashing at the drop of a hat.
    Last edited by VirtualAce; 07-18-2006 at 01:15 PM.

  7. #7
    The Right Honourable psychopath's Avatar
    Join Date
    Mar 2004
    Location
    Where circles begin.
    Posts
    1,071
    I'm still trying to figure out how it's possible to treat an array as multi-dimentional when it hasn't been declared that way.

    I certainly can't get it to work.

    [EDIT]Nevermind. I'm a moron.[/EDIT]
    Last edited by psychopath; 07-18-2006 at 09:43 PM.
    M.Eng Computer Engineering Candidate
    B.Sc Computer Science

    Robotics and graphics enthusiast.

  8. #8
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Well the code he gave is sort of a mess and I have no idea why one would declare LPDIRECT3DTEXTURE9 *pArray[2]. That would be 2 levels of indirections which is 1 more than is needed in this instance.

    The way I've shown which encapsulates the IDirect3DTexture9 interface and then uses a separate class to manage a collection of those classes IMO is a much better approach. Interfaces can be used as is but given they expose more functions and possible interfaces, encapsulating a COM object lends itself well to C++ classes.

    I'm still trying to figure out how it's possible to treat an array as multi-dimentional when it hasn't been declared that way.

    I certainly can't get it to work.

    [EDIT]Nevermind. I'm a moron.[/EDIT]
    No worries. I sat here for some time trying to sift through it myself. Some of the constructs and code practices I see in these questions stump me not because they are hard, but because they are using some arcane complex approach to a very simple problem. But some of them stump me because um....they are hard.
    Last edited by VirtualAce; 07-18-2006 at 11:18 PM.

  9. #9
    Registered User
    Join Date
    Jul 2006
    Posts
    15
    Well, this was my logic... I learned how to load in one .x from the DirectX documentation tutorial. It's really simple and straight forward. The code for all that is here: http://www.kryolinth.com/gamecodeV1_3.rtf But it carries with it a problem.. it can only load in one mesh. If I want to load in two meshes, I have to write a whole second function that does the same thing, only the file name for the .x file is different. (and the variables for the textures etc are dif. as well)

    As a solution, I decided to write a for loop to handle an infinite number of meshes. The code of the function would basically stay the same, only I would impliment a way to change the variable names each time the for loop loops. For instance, the .x file name would be FILEN1 then FILEN2. Those are = to the real file names, which are square.x and myball.x. The same applies to the other variables.

    HOWEVER, you cannot make C++ generate "FILEN1" and "FILEN2" in a for loop. It cannot combine a string - "FILEN" - with the increasing 'i' of a FOR loop to make FILEN1 and FILEN2. I tried various ways to make it, but it's impossible. In FLash Actionscript, it is possible. ["FILEN" + i] which comes out to FILEN1 and FILEN2. The only way around this problem was to make FILEN an array, which was recommended by another programmer. So that's where I got FILEN[2] and then used FILEN[i] in the FOR loop. Naturally, I applied this method to each item in InitGeometry, including LPDIRECT3DTEXTURE9* m_pMeshTextures[2];

    So although my code may be messy, hopefully you can see how I would reason to do what I have.

  10. #10
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Let me address some issues with your post:

    Well, this was my logic... I learned how to load in one .x from the DirectX documentation tutorial. It's really simple and straight forward. The code for all that is here: http://www.kryolinth.com/gamecodeV1_3.rtf But it carries with it a problem.. it can only load in one mesh. If I want to load in two meshes, I have to write a whole second function that does the same thing, only the file name for the .x file is different. (and the variables for the textures etc are dif. as well)
    In other words each mesh is its own separate object - as it should be. So you write 1 C++ class to encapsulate the mesh object and then create multiple instances of that object. Done.

    HOWEVER, you cannot make C++ generate "FILEN1" and "FILEN2" in a for loop. It cannot combine a string - "FILEN" - with the increasing 'i' of a FOR loop to make FILEN1 and FILEN2. I tried various ways to make it, but it's impossible. In FLash Actionscript, it is possible. ["FILEN" + i] which comes out to FILEN1 and FILEN2. The only way around this problem was to make FILEN an array, which was recommended by another programmer. So that's where I got FILEN[2] and then used FILEN[i] in the FOR loop. Naturally, I applied this method to each item in InitGeometry, including LPDIRECT3DTEXTURE9* m_pMeshTextures[2];
    Let's get something straight here. You cannot change variable names that you would normally type in on the compiler-side from code. That much is true.

    However, you can create 'strings' that can be concatenated (combined) to create different file names. For C you would use strcat(). I will show you using the MFC string class because it's simple.

    This code assumes m_vMeshes is a vector of CMesh pointers.
    Code:
    CString strFilename;
    for (int i=0;i<iNumFiles;i++)
    {
      CMesh *pMesh=new CMesh;
      strFilename.Format(L"Mesh%d.dat");
      pMesh->CreateFromFile(strFilename);
      m_vMeshes.push_back(pMesh);
    }
    This will be strFilename for the first 5 iterations:

    Mesh1.dat
    Mesh2.dat
    Mesh3.dat
    Mesh4.dat
    Mesh5.dat

    This function acts as a small object factory. First it figures out the filename of the mesh to load. Second, it creates an object of type CMesh. Third, it passes the filename as a parameter to CMesh::CreateFromFile() which would then be responsible for actually creating the DirectX mesh interface and object. Lastly, the code then adds the new mesh to a vector.

    This can just as easily be done with arrays and should be in a game engine. Simply create a header for your mesh file. Something like this may do:


    Code:
    struct MeshHeader
    {
      DWORD dwNumMeshes;
      BYTE uVersionMinor;
      BYTE uVersionMajor;
      DWORD dwReserved[255];   //For later expansion if needed
      BYTE uCompressionType;
    };
    
    struct MeshBlockHeader
    {
      DWORD dwBlockSize;
      DWORD dwMeshID;
      BYTE      MeshName[64];
      BYTE      dwVertexFormatType;
      DWORD dwNumVerts;
      DWORD dwNumTris;
      DWORD dwNumFaces;
      DWORD dwShaderID;
      DWORD dwReserved[64];   //For later expansion
    };
    So to read in the meshes from your own file format you would do the following.

    • Open the mesh resource file
    • Read in the mesh resource file header (MeshHeader)
    • Check if mesh version is compatible with current engine version
    • Note compression type
    • Create an object array, size determined by MeshHeader::dwNumMeshes
    • Loop from 0 to dwNumMeshes
    • Create mesh object on heap
    • Read in mesh resource file block header
    • Initialize mesh object based on data in header
    • Read in raw data - size determined by MeshBlockHeader::dwBlockSize
    • Clean up


    I fail to see the problem here.

  11. #11
    Registered User
    Join Date
    Jul 2006
    Posts
    15
    There's no "problem" with that method. I was just hoping that my code for loading one mesh wouldn't be that different from the code to load in two. I suppose I will grab my book to learn about structs, classes, compression, heaps, file block headers, and raw data so I can understand what you just said.

  12. #12
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    That's just a sample of what a header and block header may look like. The general idea is:

    Main file header
    .
    .
    Block header 1
    .
    Data for block 1
    .
    Block header 2
    .
    Data for block 2
    .
    . etc, etc, etc

    Compression is normally the type of compression used on the file or block data.

    If you were going to compress the entire file, you would use the compression type to first decompress the file into a buffer and then read from the buffer to get to the data. This all is to allow you to squeeze all of your meshes into one huge file, instead of having ten thousand different mesh files to mess with. This can be done with any resource and really simplifies the folder structure for your game.

    It does, however, make your game a bit harder to modify by third party users.
    Last edited by VirtualAce; 07-19-2006 at 05:21 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. openGL: textures, gluLookAt, and undefined behavior
    By MK27 in forum Game Programming
    Replies: 7
    Last Post: 04-28-2009, 10:12 AM
  2. Resource management...again
    By VirtualAce in forum Game Programming
    Replies: 3
    Last Post: 11-29-2006, 04:50 AM