Sign in to follow this  
AgentShiva

Vertex structure and vector array

Recommended Posts

AgentShiva    128
I have searched for nearly two days on this topic and can't dig up anything. I have Beginning DirectX 10 Game Programming by Wendy Jones, and in the end of chapter 6 she creates a predefined terrain mesh. What I am trying to do is create a dynamic terrain piece by having the user input the number of rows, the number of columns and cell width and height.
//Terrain Structs
struct VertexStruct
{
	D3DXVECTOR3 pos;
}; 

/* Terrain Class */
class Terrain
{
	public:
		Terrain();
		~Terrain();

		void loadTerrainFile(LPCSTR filename);
		void saveTerrainFile(LPCSTR filename);
		HRESULT createNewTerrain();

	private:
		vector<VertexStruct*> pVertStruct;
		ID3D10Buffer* pVerts;
		ID3D10Buffer* pIndeces;
};

Terrain::Terrain()
{
	pVerts = NULL;
	if(FAILED(createNewTerrain()))
		MessageBox(wndHandle, "Failed to create terrain!", "Error", MB_ICONERROR);
	return;
}

HRESULT Terrain::createNewTerrain()
{
	VertexStruct temp;

	for(UINT z = 0; z < tRows; ++z)
	{
		for(UINT x = 0; x < tColumns; ++x)
		{
			temp.pos.x = (float)x * tCellWidth;
			temp.pos.z = (float)z * tCellHeight;
			temp.pos.y = 1.0f;
			pVertStruct.push_back(&temp);
		}
	}

	D3D10_BUFFER_DESC bufDesc;
	bufDesc.Usage = D3D10_USAGE_DEFAULT;
	bufDesc.ByteWidth = sizeof(VertexStruct) * (tRows * tColumns);
	bufDesc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
	bufDesc.CPUAccessFlags = 0;
	bufDesc.MiscFlags = 0;

	D3D10_SUBRESOURCE_DATA initData;
	initData.pSysMem = &pVertStruct[0];
	
	HRESULT hr = pd3dDevice->CreateBuffer(&bufDesc, &initData, &pVerts);
	if(FAILED(hr))
		return hr;

	return hr;
}


I have tried many many different options. I have tried pVertStruct.resize(tRows*tColumns) and everything turns up memory errors. I have very limited knowledge of vectors and am learning DirectX in the process of making this. I really dont know what I am doing wrong. Every vector tutorial says what I have is correct, but memory errors always pop up. With this build it shows up when the windows API calls up the New Terrain dialog box, which has not turned up memory errors in the past. Any information or help is greatly appreciated.

Share this post


Link to post
Share on other sites
jyk    2094
For starters, you need to change this:
vector<VertexStruct*> pVertStruct;
To this:
vector<VertexStruct> pVertStruct;
And this:
pVertStruct.push_back(&temp);
To this:
pVertStruct.push_back(temp);
In order to understand why your code is wrong, you'll need to have a basic understanding of pointers, and of what it means to store data by reference as opposed to by value. (If you're not entirely up to speed on these topics, the forum archives here on GDNet might be a good place to start - there have been a number of threads in the past on the subject of pointers, what they're for, and how to use them.)

What you're doing currently is repeatedly adding the address of a temporary local variable to your vertex array, which I'm sure is not what you intend. The changes proposed above will have the effect of storing the individual vertices by value rather than by reference, which (I'm fairly certain) is what DirectX expects to see in the data you send it (of course your current data is useless anyway, seeing as how it consists entirely of pointers to a single object that has most likely expired).

Please post back if any of this is unclear.

Share this post


Link to post
Share on other sites
AgentShiva    128
Actually that pretty much all made sense. I have taken computer science classes before but have only been taught java. Trying to learn all of C++'s intricacies is proving to be a tough challenge.

Thank you for the help, I was going crazy trying to figure this out. It's funny how much comprehensive learning programming takes.

Now to turn a floating point number into a char array =P.

Again thank you!

Share this post


Link to post
Share on other sites
AgentShiva    128
Writing vertex information to a XML file.

Such as
<Terrain>
<Mesh>
<Verticies count="1024"> //32x32 terrain(small but a test)
<Vertex>
<Position x="float value" y="float value" z="float value"/>
</Vertex> //more data to be added such as Texture coords, normal etc
</Verticies>
</Mesh>
</Terrain>

Custom 3D file format for terrain only.

Share this post


Link to post
Share on other sites
jyk    2094
Quote:
Original post by AgentShiva
Writing vertex information to a XML file.

Such as
<Terrain>
<Mesh>
<Verticies count="1024"> //32x32 terrain(small but a test)
<Vertex>
<Position x="float value" y="float value" z="float value"/>
</Vertex> //more data to be added such as Texture coords, normal etc
</Verticies>
</Mesh>
</Terrain>

Custom 3D file format for terrain only.
For converting numbers to text in C++, you'll most likely want to look into the SC++L 'stream' classes (e.g. stringstream, fstream, etc.). Here's a quick example of how you might write out the 'position' line of the above file:
std::ofstream file("my_file.xml");
// ...
file << "<Position x=" << x << " y=" << y << " z=" << z << "/>\n";

Share this post


Link to post
Share on other sites
AgentShiva    128
I am actually using a XML parser I found online. It looked fairly easy to use, and comes with a good bit of documentation, but no detailed examples.

It has a function that adds an attribute to a node and it keeps getting memory errors. I am using sprintf() at the moment.

I didn't really expect help with this part of the program though haha.

Share this post


Link to post
Share on other sites
rip-off    10976

#include <sstream>
#include "XML_Thing.h"

void foo(XML::Thing &xml, float f)
{
std::stringstream stream;
stream << f;

// prototype: XML::Thing::write( const char * )
xml.write(stream.str().c_str());
// std::stringstream::str() returns std::string instance
// std::string::c_str() returns const char *
}

Share this post


Link to post
Share on other sites
Zahlman    1682
Quote:
Original post by AgentShiva
Writing vertex information to a XML file.


Why would you convert it into "a char array" when you could instead create an instance of the standard library string class, just as in Java?

But wait, don't answer that - in C++, we don't convert things to text first in order to output them. Instead, we define the operation of outputting them. :) And we can do it with operator overloading, too, which lets us conform to the same interface that is provided for primitive types. (Of course, the overload already exists for double, so you just can output it as jyk shows.)

Of course, if you're working with another library, you might *have to* convert to a string, because it's what the other library is expecting. In which case, you just use a special sort of stream which uses a string as its "output device", and then pass the string along, as rip-off shows. :)

Share this post


Link to post
Share on other sites
AgentShiva    128
I tried implementing what rip-off said:


for(UINT i = 0; i < (tRows * tColumns); i++) //Print Vertex info
{
vertexNode.addChild("Vertex", NULL, NULL).addChild("Position", NULL, NULL);
tempNode = vertexNode.getChildNode("Position", NULL);

stream<<pVertStruct[i].pos.x;
tempNode.addAttribute("x", stream.str().c_str());
stream.flush();
}



But with that when I save the file my program stops responding and its memory usage continually goes up.

addAttribute() takes 2 const char * variables so I thought that stream.str().c_str() would work because .c_str() returns a const char pointer.

I also dont know much about streams, I thought flush cleared the stream but I am most likely wrong. I know I dont want to just keep the stream open and continually write to it because then I would be printing every float sequentially. That is to say the output from c_str() would be "value1" then "value1value2" etc.

Share this post


Link to post
Share on other sites
Zahlman    1682
Quote:
Original post by AgentShiva
I also dont know much about streams, I thought flush cleared the stream


.flush() synchronizes a stream's buffer with its output device. For a std::stringstream, the buffer IS the output device, so the call is meaningless.

Quote:
but I am most likely wrong. I know I dont want to just keep the stream open and continually write to it because then I would be printing every float sequentially. That is to say the output from c_str() would be "value1" then "value1value2" etc.


Indeed. Have you checked your output file? ;)

To set the contents of the underlying string of a stringstream, use the .str() member function with an argument: thus 'stream.str("")' to empty it.

But you don't really want to do that. The neat, organized way to do this is to declare the std::stringstream instance inside the loop: that way, it will be re-constructed each time through, with a new, initially-empty string. This also follows the standard advice to scope your variables as tightly as possible, and declare them near first use.

You should actually be able to do it all with temporaries, if I'm not mistaken. Also, there are neater ways to iterate in C++.


for (std::vector<VertexStruct>::iterator it = vertices.begin(), end = vertices.end(); it != end; ++it) {
vertexNode.addChild("Vertex", NULL, NULL).addChild("Position", NULL, NULL);
vertexNode.getChildNode("Position", NULL).addAttribute("x", (std::stringstream() << it->pos.x).str().c_str());
}



(You might want to consider looking up some documentation for this stuff instead of coming back here for every tiny question, BTW. :) )

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this