Jump to content

  • Log In with Google      Sign In   
  • Create Account


Cloned Texture not displayed with Linked List


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
30 replies to this topic

#1 Dissipate   Members   -  Reputation: 324

Like
0Likes
Like

Posted 21 January 2013 - 05:48 PM

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?



Sponsor:

#2 Mercile55   Members   -  Reputation: 136

Like
0Likes
Like

Posted 21 January 2013 - 06:25 PM

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.



#3 Dissipate   Members   -  Reputation: 324

Like
0Likes
Like

Posted 22 January 2013 - 04:31 AM

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)



#4 KnolanCross   Members   -  Reputation: 1271

Like
0Likes
Like

Posted 22 January 2013 - 09:51 AM

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).


#5 Dissipate   Members   -  Reputation: 324

Like
0Likes
Like

Posted 22 January 2013 - 10:13 AM

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; }


#6 KnolanCross   Members   -  Reputation: 1271

Like
0Likes
Like

Posted 22 January 2013 - 10:24 AM

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


Edited by KnolanCross, 22 January 2013 - 10:28 AM.

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


#7 Dissipate   Members   -  Reputation: 324

Like
0Likes
Like

Posted 22 January 2013 - 10:29 AM

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



#8 KnolanCross   Members   -  Reputation: 1271

Like
0Likes
Like

Posted 22 January 2013 - 10:37 AM

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).


#9 Dissipate   Members   -  Reputation: 324

Like
0Likes
Like

Posted 22 January 2013 - 10:53 AM

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).



#10 KnolanCross   Members   -  Reputation: 1271

Like
0Likes
Like

Posted 22 January 2013 - 11:06 AM

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?


Edited by KnolanCross, 22 January 2013 - 11:06 AM.

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


#11 Dissipate   Members   -  Reputation: 324

Like
0Likes
Like

Posted 22 January 2013 - 11:33 AM

Confirmed: .log shows:

m_pSquare->GetVertexBuffer() = 64896640   // this is the master object
pSprCurrent->GetVertexBuffer() = 64896640 // this is the cloned one

The code for adding to the list is displayed above.

(back at computer at 9:30pm)



#12 KnolanCross   Members   -  Reputation: 1271

Like
0Likes
Like

Posted 22 January 2013 - 01:05 PM

Well, I am out of ideas now, sorry.

The only thing that comes to my mind is that the clone method is losing some information (normals, maybe?) and the drawn is not displaying.


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


#13 Dissipate   Members   -  Reputation: 324

Like
0Likes
Like

Posted 22 January 2013 - 03:49 PM

ok thanks for your help.

Maybe someone else will know...?



#14 Mercile55   Members   -  Reputation: 136

Like
0Likes
Like

Posted 22 January 2013 - 05:29 PM

Just one more question for clarity. How does SetTexture get called and m_Texture set in effect ?

EDIT(2):
I think there's either something wrong with the LinkedList, so that for some reason, things get reset.
EDIT: removed invalid statement.

Other than that, check pointers to m_Texture when calling Draw for every item on the list, and compare to the root one from m_pSquare (I believe).

It maybe easier if you could post complete code of the AddNode, CLinkedList constructor that is being used, and ==/!= overloads, only any code dealing with CNode and head/end objects.

Edited by Mercile55, 25 January 2013 - 09:12 AM.


#15 Dissipate   Members   -  Reputation: 324

Like
0Likes
Like

Posted 23 January 2013 - 10:29 AM

How does SetTexture get called and m_Texture set in effect ?

It is called only within the Render() by the master CSprTex object like this:

 

    // SQUARE
    if (m_pSquare != NULL) // only draw if this has been set
    {    
        m_pSquare->Rotate(m_fRotateX, m_fRotateY, m_fRotateZ);
        m_pSquare->Move(m_fMoveX, m_fMoveY, m_fMoveZ);
        m_pSquare->SetTransformTransByRotXYZ();
        m_pSquare->SelectBuffers();
        m_pSquare->SetTexture();
        m_pSquare->Draw();
    }

 

The clones (m_pSquareCloneArray[20]) get drawn the same way but without the SetTexture() being called and they display and fly around fine.

m_Texture is set as follows:

void CSprTex::SetTexture(void)
{
    g_App.GetDevice()->SetTexture(0, m_Texture); // Device is LPDIRECT3DDEVICE9
}// SetTexture

This is not called by the clones as they do not have thier texture property assigned. Note: that the colour of the squares are brown...! as are all the meshes (box and teapot non-clones) and not 50% grey as they should be. This, I noticed, only happens when I am setting the texture for the master object. If I change only the top left pixel of the graphic file (.png), I get strange results... Purple gives me blank purple square and green gives me a mauve, green gives me a pink square... hmm interesting... what is happening the teh texture...? Also... They are drawn upside down (rotated 180deg on X-axis).

 

 

I think there's either something wrong with the LinkedList, so that for some reason, things get reset. It may not necessarily be noticed, as static_cast will call constructor on CSprTex, so the instance will appear correct, therefore, if all objects in linked list are invalid, then they are all gonna be created anew when statically cast.

Ok so I commented out the NULL in the constructor and that still didnt work...

CSprTex::CSprTex(void)
{
	m_Texture = NULL; // Commenting out makes no differance
	m_iNum    = 0;    // The class keeps this value and logs it during the render for proof
}// CSprTex

Plus I can confirm the constructors get called in the static_cast as I logged them during the Render().

So should I be using dynamic_cast or safe_cast instead? How can I access the object in the linked list. If I dont use VOID* then I will need to have linked lists of every class of object. They need to be cast some how, howelse could I access the members.

 

 

Other than that, check pointers to m_Texture when calling Draw for every item on the list, and compare to the root one from m_pSquare (I believe).

Aha here is the .log called in the Render() for 3 nodes:

*** Start Drawing Nodes ********************************
iNum = 1
m_pSquare->GetTexture() =39384576
pSprCurrent->GetTexture() =135168096

iNum = 2
m_pSquare->GetTexture() =39384576
pSprCurrent->GetTexture() =135170848

iNum = 3
m_pSquare->GetTexture() =39384576
pSprCurrent->GetTexture() =140321984

 

Here is the AddNode 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;

	//m_pTempNode = m_pEndNode->pPrev;  // Save Prev
	//m_pTempNode->pNext = pNewNode;    // Prev ==> New
	//m_pEndNode->pPrev  = pNewNode;    //          New <== End
	//pNewNode->pNext    = m_pEndNode;  //          New ==> End
	//pNewNode->pPrev    = m_pTempNode; // Prev <== New 

	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
	
	m_iNumberOfNodes++;  // Keep track of how many nodes there are
	g_FileDebug->WriteEx("Number of nodes = ", m_iNumberOfNodes);
}// AddNode

Called like this:

if(KEY_DOWN(VK_SPACE))	
	if (bToggleSpace) 
	{
		bToggleSpace = false; // run once
		
		// Create a sprite within a linked list and 
		// display it randomly on the screen
		CSprTex* SprHappyFace = new CSprTex;
		SprHappyFace->m_iNum = iNumIncrementor;
		m_pSpriteManager->Clone(m_pSquare, SprHappyFace);
		SprHappyFace->Move(0.0f, 0.0f, 1.0);
		SprHappyFace->SetFilename(FILE_TEX2);

		m_LLFaces.AddNode(SprHappyFace);
		iNumIncrementor++;
	}

Please dont laugh at the SprHappyFace variable I thought it would cheer me up (highly unprofessional though)

Here is the LL constructor:

CLinkedList::CLinkedList(void)
{
	//g_FileDebug->Write("CLinkedList Constructor\n");

	m_iNumberOfNodes = 0;
	
	// Set the non leaf node types
	m_HeadNode.m_uNodeType = CNODE_HEAD;
	m_EndNode.m_uNodeType  = CNODE_END;

	m_HeadNode.pNext = &m_EndNode;  //          Head ==> End
	m_EndNode.pPrev  = &m_HeadNode; //          Head <== End 
	m_HeadNode.pPrev = NULL;        // NULL <== Head
	m_EndNode.pNext  = NULL;        //                   End ==> NULL
	m_HeadNode.pData = NULL;
	m_EndNode.pData  = NULL;
}// Constructor

The following is in the Initialisation part and displays the texture fine:

for (int i = 0; i < 20; i++)
{
	m_pSquareCloneArray[i] = new CSprTex;
	m_pSpriteManager->Clone(m_pSquare, m_pSquareCloneArray[i]);
	m_pSquareCloneArray[i]->Move((rand() % 20) - 10,
				     (rand() % 20) - 10,
				     (rand() % 20) - 10);
	m_pSquareCloneArray[i]->m_iNum = i + 100; // Just to keep an identity for these elements
}

 

So if I am losing the texture then that means that the clone isn't working, or the static_cast isnt working. Hmm what so I do?



#16 rip-off   Moderators   -  Reputation: 8113

Like
0Likes
Like

Posted 23 January 2013 - 11:40 AM

Is there a reason you are not using the standard library for this?



#17 Dissipate   Members   -  Reputation: 324

Like
0Likes
Like

Posted 23 January 2013 - 11:58 AM

Is there a reason you are not using the standard library for this?

Only std::vector is brand new to me, I have no experience of it. It was easier to code the thing myself and I have no idea how much junk it will add in... Will it resolve the problem? Im looking it up now and will create a test (somehow).



#18 Dissipate   Members   -  Reputation: 324

Like
0Likes
Like

Posted 23 January 2013 - 12:33 PM

Can my linked list be described as:

AddNode O(1)

DeleteNode O(1)

DeleteAllNodes O(n)

 

@RipOff: I am reading this for std::vector http://www.cplusplus.com/reference/vector/vector/



#19 rip-off   Moderators   -  Reputation: 8113

Like
0Likes
Like

Posted 23 January 2013 - 12:36 PM

I cannot say that switching to the standard library will necessarily resolve the problem. However, using the standard library would rule out many bugs that would hide in a typical beginner's hand rolled linked list implementation.

 

While I would encourage any beginner to write a linked list implementation to get familiar with the data structure, I would advise them against using this implementation in an actual project.

 

The standard containers will not add in "junk". At most it will contain some functionality that you won't use (yet), but the linker should strip all that out of the final build. Most implementations will add some sanity checks to debug builds, which will catch some bugs where you use the standard library incorrectly.

 

I cannot comment on the algorithmic complexity of code I cannot see. You'd have to post your entire linked list class for us to check the O(?) of those functions.



#20 rip-off   Moderators   -  Reputation: 8113

Like
0Likes
Like

Posted 23 January 2013 - 12:38 PM

It may not necessarily be noticed, as static_cast will call constructor on CSprTex, so the instance will appear correct, therefore, if all objects in linked list are invalid, then they are all gonna be created anew when statically cast.

 

This is incorrect. Using static_cast<> with a pointer type will not call any constructors for the pointed at type.


Edited by rip-off, 23 January 2013 - 12:43 PM.





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS