Skip to main content
GameDev.net gamedev.net
🔒 Locked

Vertex structure and vector array

Started by AgentShiva Oct 20, 2008 at 4:46 PM 10 replies 1.4k views
Original Post
AgentShiva
AgentShiva
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.
Zakwayda
Zakwayda
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.
AgentShiva
AgentShiva
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!
rip-off
rip-off
Quote:

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


What for? [grin] (unless that was a joke - your smiley is ambiguous)
AgentShiva
AgentShiva
Writing vertex information to a XML file.

Such as


//32x32 terrain(small but a test)


//more data to be added such as Texture coords, normal etc




Custom 3D file format for terrain only.
Zakwayda
Zakwayda
Quote:
Original post by AgentShiva
Writing vertex information to a XML file.

Such as


//32x32 terrain(small but a test)


//more data to be added such as Texture coords, normal etc




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

AgentShiva
AgentShiva
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.
rip-off
rip-off
#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 *}
Zahlman
Zahlman
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. :)
AgentShiva
AgentShiva
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.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.
Zahlman
Zahlman
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. :) )
AgentShiva
AgentShiva
haha, thank you very much. I never really meant to get an answer as to how to do the XML part. I was initially joking. But thank you to all that have helped! =D

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.