Cloned Texture not displayed with Linked List

Started by
29 comments, last by Dissipate 11 years, 3 months ago

I have a clone function that succesfully clones the vertex and index buffers of a square with a texture. It displays it correctly. The linked list uses nodes with pData of type VOID that is statically cast to a CSprTex. The CSprTexdisplays and updates correctly but the texture is not displayed and I dont know why.


class CNode
{
public:
    CNode(void);
    ~CNode(void);

    UINT m_uNodeType; // Leaf or non leaf-(head or end)

    VOID* pData;      // Can be cast to any class type eg CSprite*
    
    CNode* pNext;     // Pointer to the next object
    CNode* pPrev;     // Pointer to the previous object
private:

};// CNode

CLinked list's Add Node function:


void CLinkedList::AddNode(VOID* pData)
{
    g_FileDebug->Write("Add a Node\n");

    CNode* pNewNode = new CNode;      // Create the Node
    pNewNode->pData = pData;          // Assign the Sprite data
    pNewNode->m_uNodeType = CNODE_NODE;

    ...// insert behind Node End
    
    m_iNumberOfNodes++;  // Keep track of how many nodes there are
    g_FileDebug->WriteEx("Number of nodes = ", m_iNumberOfNodes);
}// AddNode

And this is how I draw it. with a loop that accesses the nodes.


        CNode* pCurrentNode = m_LLFaces.m_HeadNode.pNext;     // Point to first in list
        while (pCurrentNode != &m_LLFaces.m_EndNode)
        {
            CSprTex* pSprCurrent = static_cast<CSprTex*>(pCurrentNode->pData); // Void to CSprite
            if (pSprCurrent != NULL)
            {
                pSprCurrent->Orbit(index, 0.0f, index);
                pSprCurrent->Rotate(m_fRotateXClone, m_fRotateY, m_fRotateZ);
                pSprCurrent->SetTransformTransByRotXYZ();
                pSprCurrent->SelectBuffers();
                pSprCurrent->Draw();
            }
            pCurrentNode = pCurrentNode->pNext;                 // Go to next in the list
        }// end while*>

This is the cloning function:


int CSpriteManager::Clone(CSprTex* pSource, CSprTex* pDest)
{
    // vertex and index buffers
    pDest->SetVertexBuffer(pSource->GetVertexBuffer());
    pDest->SetIndexBuffer(pSource->GetIndexBuffer());

    //pDest->m_pVertexBuffer = pSource->m_pVertexBuffer;
    //pDest->m_pIndexBuffer  = pSource->m_pIndexBuffer;

    // number of verticies and indicies and primitive count
    pDest->m_iNumOfVertices  = pSource->m_iNumOfVertices;
    pDest->m_iNumOfIndicies  = pSource->m_iNumOfIndicies;
    pDest->m_iPrimCount      = pSource->m_iPrimCount;
    
    // rotational and translational matricies
    pDest->m_matRotateX      = pSource->m_matRotateX;
    pDest->m_matRotateY      = pSource->m_matRotateY;
    pDest->m_matRotateZ      = pSource->m_matRotateZ;
    pDest->m_matTranslate    = pSource->m_matTranslate;
    
    return (1);
}// Clone (overloaded)

So why doesn't the texture display? The square does display though and I can move (any number of them) independantly of the master. Cloning an object outside of the Linked list structure displays the texture fine. What am I missing?

Advertisement

1. You didn't specify what data you're passing when calling CLinkedList::AddNode(VOID*...).

2. With static_cast, you need to be sure that target type is compatible in all terms, i.e. you should not cast statically from base class to an object that derives from it, unless you're absolutely sure of its content. Remember that it will always return something that may not be valid. The null check will only protect you if source pData is null.

3. You also didn't write, how and where Clone is being used, and whether is works, when you Clone more than once.

4. Do you actually set CNode's pNext to the next node's pointer ?

If the m_LLFaces.m_HeadNode points to the first CNode, then m_LLFaces.m_HeadNode.pNext will most likely be the second. That's how LL works, pNext is always the second or "this" is the last if it's NULL.

More details please.

Thanks for the reply. Sorry I have become one of those people who dont give enough pertinent information.

1. You didn't specify what data you're passing when calling CLinkedList::AddNode(VOID*...).

I am passing my CSprTex class which is inherited from CShape:


class CSprTex: public CShape 
{
public:
	CSprTex(void);
	~CSprTex(void);

	int SetFilename(char* cFilename);
	void SetTexture(void);

	inline LPDIRECT3DTEXTURE9 GetTexture(void) { return m_Texture; }

	void ReleaseTexture(void);

	LPDIRECT3DTEXTURE9 m_Texture;

private:

	char* m_cFilename;

};// CSprTex

2. With static_cast, you need to be sure that target type is compatible in all terms, i.e. you should not cast statically from base class to an object that derives from it, unless you're absolutely sure of its content. Remember that it will always return something that may not be valid. The null check will only protect you if source pData is null.

The NULL check was just for safety. I am casting from a derived class to a derived class. That's ok isn't it? They both will have the same functions.

3. You also didn't write, how and where Clone is being used, and whether is works, when you Clone more than once.

Used like this from the CSpriteManager class:


int Clone(CSprTex* pSource, CSprTex* pDest);

See above for CSpriteManager::Clone(...) function. The function is being called when the space bar is pressed (key repeat is handled) and is called like this:


CSprTex* SprTest = new CSprTex;              // Allocate space 
m_pSpriteManager->Clone(m_pSquare, SprTest); // Clone master CSprTex to CSprTest
SprTest->Move(0.0f, 0.0f, 0.0f);             // Initialise to start at this position

m_LLFaces.AddNode(SprTest);                  // Linked List add node

See above for how it is drawn. Note: that the clone function works and I can draw from it and the texture is displayed if I do not use the linked list(LL) but I create only 1. Using the LL I can display maybe 150 squares all moving independantly around the screen in 3D.

4. Do you actually set CNode's pNext to the next node's pointer ?

Ok heres the code I cut out of ::AddNode to abbreviate it for you :P


m_EndNode.pPrev->pNext = pNewNode;  // Last ==> New
pNewNode->pNext  = &m_EndNode;      //          New ==> End
pNewNode->pPrev  = m_EndNode.pPrev; // Last <== New
m_EndNode.pPrev  = pNewNode;        //          New <== End

I have stepped through the creation and deletion of the nodes within a separate solution and am confident that all the nodes point to the right addresses and that Add, DeleteNode and DelAllNodes work impeccabley.

If the m_LLFaces.m_HeadNode points to the first CNode, then m_LLFaces.m_HeadNode.pNext will most likely be the second. That's how LL works, pNext is always the second or "this" is the last if it's NULL.

No sorry what I have done I is to create separate Head and End nodes that exist on their own. The m_HeadNode.pNext points to the first CNode. That way I can delete all the CNodes and have a structure to place nodes back into... hmmm maybe its not the lightest of lightweight solutions but anyway.

Please don't hesitate to ask for any further clarification. (Thanks in advance)

I am wondering about this part:


    // vertex and index buffers
    pDest->SetVertexBuffer(pSource->GetVertexBuffer());
    pDest->SetIndexBuffer(pSource->GetIndexBuffer());

I don't know what those buffers are, but mostly they are an area of memory. If that is the case, depending on your implementation it is possible that you are not creating a copy here, but assigning the same pointer to the two objects (this is also know as aliasing and is can be dangereous).

Currently working on a scene editor for ORX (http://orx-project.org), using kivy (http://kivy.org).

I am trying to use a Master Object then create another object that just points to the data that the master holds. Re-using its data. The clones are not deleted but the Master is.

Here is the header:


inline LPDIRECT3DVERTEXBUFFER9 GetVertexBuffer(void)    { return m_pVertexBuffer; }
inline LPDIRECT3DINDEXBUFFER9  GetIndexBuffer(void)     { return m_pIndexBuffer; }
inline void SetVertexBuffer(LPDIRECT3DVERTEXBUFFER9 pV) { m_pVertexBuffer = pV; }
inline void SetIndexBuffer(LPDIRECT3DINDEXBUFFER9 pI)   { m_pIndexBuffer = pI; }

Are LPDIRECT3DVERTEXBUFFER9 and LPDIRECT3DINDEXBUFFER9 pointers, structs or classes? If they are a class, do they overload the "=" operator?

Currently working on a scene editor for ORX (http://orx-project.org), using kivy (http://kivy.org).

It is a pointer to a structure of an IDirect3DVertexBuffer9 Interface within directX9.0c.

Well, then you are not cloning the object, if the buffer on the source is deleted or changed it will affect all its clones (and the clones of the clone). I wouldn't really recommend this at all.

You said the master is deleted, are you sure you are not removing the buffer when doing this? If you do it will affect all the clones, if you don't you will have a hard time to determine when to free this buffer (assuming this is dynamically allocated memory).

Currently working on a scene editor for ORX (http://orx-project.org), using kivy (http://kivy.org).

No you dont understand. The master holds the information for, lets say the texture. The clones all point to the master so that there need only be 1 copy of a texture in memory. Then all the clones get their own properties set to what ever independant of the master as only the texture is pointed at!

The Master is deleted at program end.

But this isnt the problem the problem (I think) something to do with the static_cast. Maybe its not pointing to the memory. But it works if I dont use the Linked list. I tried re-cloning the object after it is cast - but that didn't work. (I'm blind on this).

Hm, ok. I pointed that because it is a bad pratice and could be the error, seems I was wrong, sorry.

Have you tried loging the pointer by using %p to check if the memory addresses are correct (or using the debugger to check them)?

Can you post the code where you add to the list?

Currently working on a scene editor for ORX (http://orx-project.org), using kivy (http://kivy.org).

This topic is closed to new replies.

Advertisement