[SOLVED]unexpected crash using custom irrlicht method

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
chisser98
Posts: 7
Joined: Thu Mar 31, 2011 11:57 pm
Location: Canada

[SOLVED]unexpected crash using custom irrlicht method

Post by chisser98 »

Hi everyone,

I decided I needed some functionality that would require me to modify the irrlicht source code directly.

What I wanted was an addTerrainSceneNode(..) method that could take in a 'float* data' variable (structured as a 1D row-major ordered array of floats) to use as the terrain data in lieu of a file (i.e. heightmap image, etc).

I made the changes, compiled Irrlicht without errors, called the method from my project, compiled my project without errors, and ran it. However, as soon as I get to the new method call the project crashes with no errors (at least not that I can see).

I would love some help with this :D Here are the changes I made to Irrlicht:

1) added this to ITerrainSceneNode.h

Code: Select all

virtual bool loadHeightMapRAWData(f32* data, s32 size,
			video::SColor vertexColor = video::SColor(255, 255, 255, 255), s32 smoothFactor = 0) = 0;
2) added this to CTerrainSceneNode.h

Code: Select all

virtual bool loadHeightMapRAWData(f32* data, s32 size, video::SColor vertexColor,
			s32 smoothFactor);
3) added this to CTerrainSceneNode.cpp

Code: Select all

bool CTerrainSceneNode::loadHeightMapRAWData(f32* data, s32 size, video::SColor vertexColor,
		s32 smoothFactor) {
	if (data == 0)
		return false;

	// start reading
	const u32 startTime = os::Timer::getTime();

	Mesh->MeshBuffers.clear();

	TerrainData.Size = size;

	switch (TerrainData.PatchSize) {
		case ETPS_9:
			if (TerrainData.MaxLOD > 3) {
				TerrainData.MaxLOD = 3;
			}
			break;
		case ETPS_17:
			if (TerrainData.MaxLOD > 4) {
				TerrainData.MaxLOD = 4;
			}
			break;
		case ETPS_33:
			if (TerrainData.MaxLOD > 5) {
				TerrainData.MaxLOD = 5;
			}
			break;
		case ETPS_65:
			if (TerrainData.MaxLOD > 6) {
				TerrainData.MaxLOD = 6;
			}
			break;
		case ETPS_129:
			if (TerrainData.MaxLOD > 7) {
				TerrainData.MaxLOD = 7;
			}
			break;
	}

	// --- Generate vertex data from heightmap data ----
	// resize the vertex array for the mesh buffer one time (makes loading faster)
	scene::CDynamicMeshBuffer *mb = 0;
	const u32 numVertices = TerrainData.Size * TerrainData.Size;
	if (numVertices <= 65536) {
		//small enough for 16bit buffers
		mb = new scene::CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_16BIT);
		RenderBuffer->getIndexBuffer().setType(video::EIT_16BIT);
	} else {
		//we need 32bit buffers
		mb = new scene::CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_32BIT);
		RenderBuffer->getIndexBuffer().setType(video::EIT_32BIT);
	}

	mb->getVertexBuffer().reallocate(numVertices);

	video::S3DVertex2TCoords vertex;
	vertex.Normal.set(0.0f, 1.0f, 0.0f);
	vertex.Color = vertexColor;

	// Read the heightmap to get the vertex data
	// Apply positions changes, scaling changes
	const f32 tdSize = 1.0f / (f32)(TerrainData.Size - 1);
	s32 index = 0;
	float fx = 0.f;
	float fx2 = 0.f;
	for (s32 x = 0; x < TerrainData.Size; ++x) {
		float fz = 0.f;
		float fz2 = 0.f;
		for (s32 z = 0; z < TerrainData.Size; ++z) {
			video::S3DVertex2TCoords & vertex
					= static_cast<video::S3DVertex2TCoords*> (mb->getVertexBuffer().pointer())[index++];
			vertex.Normal.set(0.0f, 1.0f, 0.0f);
			vertex.Color = vertexColor;
			vertex.Pos.X = fx;
			vertex.Pos.Y = data[(TerrainData.Size - x - 1) * TerrainData.Size + z];
			//vertex.Pos.Y = (f32) heightMap->getPixel(TerrainData.Size - x - 1, z).getLightness();
			vertex.Pos.Z = fz;

			vertex.TCoords.X = vertex.TCoords2.X = 1.f - fx2;
			vertex.TCoords.Y = vertex.TCoords2.Y = fz2;

			++fz;
			fz2 += tdSize;
		}
		++fx;
		fx2 += tdSize;
	}

	smoothTerrain(mb, smoothFactor);

	// calculate smooth normals for the vertices
	calculateNormals(mb);

	// add the MeshBuffer to the mesh
	Mesh->addMeshBuffer(mb);

	// We copy the data to the renderBuffer, after the normals have been calculated.
	RenderBuffer->getVertexBuffer().set_used(numVertices);

	for (u32 i = 0; i < numVertices; ++i) {
		RenderBuffer->getVertexBuffer()[i] = mb->getVertexBuffer()[i];
		RenderBuffer->getVertexBuffer()[i].Pos *= TerrainData.Scale;
		RenderBuffer->getVertexBuffer()[i].Pos += TerrainData.Position;
	}

	// We no longer need the mb
	mb->drop();

	// calculate all the necessary data for the patches and the terrain
	calculateDistanceThresholds();
	createPatches();
	calculatePatchData();

	// set the default rotation pivot point to the terrain nodes center
	TerrainData.RotationPivot = TerrainData.Center;

	// Rotate the vertices of the terrain by the rotation
	// specified. Must be done after calculating the terrain data,
	// so we know what the current center of the terrain is.
	setRotation(TerrainData.Rotation);

	// Pre-allocate memory for indices

	RenderBuffer->getIndexBuffer().set_used(
			TerrainData.PatchCount * TerrainData.PatchCount * TerrainData.CalcPatchSize
					* TerrainData.CalcPatchSize * 6);

	RenderBuffer->setDirty();

	const u32 endTime = os::Timer::getRealTime();

	c8 tmp[255];
	snprintf(tmp, 255, "Generated terrain data (%dx%d) in %.4f seconds", TerrainData.Size,
			TerrainData.Size, (endTime - startTime) / 1000.0f);
	os::Printer::log(tmp);

	return true;

}
4) added this to ISceneManager.h

Code: Select all

virtual ITerrainSceneNode* addTerrainSceneNode(f32* data, s32 size, ISceneNode* parent = 0,
			s32 id = -1, const core::vector3df& position = core::vector3df(0.0f, 0.0f, 0.0f),
			const core::vector3df& rotation = core::vector3df(0.0f, 0.0f, 0.0f),
			const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f),
			video::SColor vertexColor = video::SColor(255, 255, 255, 255), s32 maxLOD = 5,
			E_TERRAIN_PATCH_SIZE patchSize = ETPS_17, s32 smoothFactor = 0,
			bool addAlsoIfHeightmapEmpty = false) = 0;
5) added this to CSceneManager.h

Code: Select all

virtual ITerrainSceneNode* addTerrainSceneNode(f32* data, s32 size, ISceneNode* parent = 0,
			s32 id = -1, const core::vector3df& position = core::vector3df(0.0f, 0.0f, 0.0f),
			const core::vector3df& rotation = core::vector3df(0.0f, 0.0f, 0.0f),
			const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f),
			video::SColor vertexColor = video::SColor(255, 255, 255, 255), s32 maxLOD = 5,
			E_TERRAIN_PATCH_SIZE patchSize = ETPS_17, s32 smoothFactor = 0,
			bool addAlsoIfHeightmapEmpty = false);
6) added this to CSceneManager.cpp

Code: Select all

ITerrainSceneNode* CSceneManager::addTerrainSceneNode(f32* data, s32 size, ISceneNode* parent,
		s32 id, const core::vector3df& position, const core::vector3df& rotation,
		const core::vector3df& scale, video::SColor vertexColor, s32 maxLOD,
		E_TERRAIN_PATCH_SIZE patchSize, s32 smoothFactor, bool addAlsoIfHeightmapEmpty) {
        std::cout << "ZERO" << std::endl;
	os::Printer::log("ZERO", ELL_NONE); // testing - this does not output
	if (!parent)
		parent = this;

	std::cout << "ONE" << std::endl;

	if (data == 0 && !addAlsoIfHeightmapEmpty) {
		os::Printer::log("Could not load terrain, because the data was empty.", ELL_ERROR);
		return 0;
	}
	std::cout << "TWO" << std::endl;

	CTerrainSceneNode* node = new CTerrainSceneNode(parent, this, FileSystem, id, maxLOD,
			patchSize, position, rotation, scale);
	std::cout << "THREE" << std::endl;

	if (!node->loadHeightMapRAWData(data, size, vertexColor, smoothFactor)) {
		if (!addAlsoIfHeightmapEmpty) {
			node->remove();
			node->drop();
			return 0;
		}
	}
	std::cout << "FOUR" << std::endl;

	node->drop();
	return node;
}
In the above bit of code (#6), you can see a bunch of 'std::cout....' calls being made. None of this gets outputted to the console, so it seems this function isn't even executing..


And finally, here is the code I use in my program that calls the new method:

Code: Select all

//...some code

f32* data = new f32[257 * 257];
	for (int i = 0; i < 257; i++) {
		for (int j = 0; j < 257; j++) {
			data[i * 257 + j] = 10.0f;
		}
	}
	std::cout << "TESTING" << std::endl;
	// add terrain scene node
	scene::ITerrainSceneNode* terrain = smgr_->addTerrainSceneNode(data, 256, // size
			0, // parent node
			-1, // node id
			core::vector3df(0.f, 0.f, 0.f), // position
			core::vector3df(0.f, 0.f, 0.f), // rotation
			core::vector3df(40.f, 4.4f, 40.f), // scale
			video::SColor(255, 255, 255, 255), // vertexColor
			5, // maxLOD
			scene::ETPS_17, // patchSize
			4 // smoothFactor
			);

//...some more code
Unfortunately, the program crashes after the call to smgr_->addTerrainSceneNode(..).

If I comment out the code above, it runs just fine. Alternatively, if I call one of the original addTerrainSceneNode(..) methods it also runs fine.

I think maybe there is something going on within the Irrlicht engine that I'm not catching??

I would really appreciate any help I can get with this! :D

Thanks all,

Jarrett
Last edited by chisser98 on Tue Apr 19, 2011 12:11 am, edited 1 time in total.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Hi Jarrett, the problem is probably due to a not properly recompiled code, which now uses different class sizes for the terrain scene node. However, you should simply remove all those additions again, and simply use the Irrlicht way to achieve the same: Create a memory read file from your data and pass it to the existing raw loader. This does exactly what you want and works with all stable Irrlicht versions.
chisser98
Posts: 7
Joined: Thu Mar 31, 2011 11:57 pm
Location: Canada

Post by chisser98 »

Hi Hybrid,

Thanks for the reply.

I figured I might be able to use that memory read file technique (I think I saw that used somewhere in the forums?), but since I have lots of things I'd like to add to the engine, I figured I might as well start with this :)

I tried recompiling the Irrlicht library and my own project with:

Code: Select all

make clean
make -j2
But it still does not work..

I thought cleaning and recompiling might fix any issues with using different class sizes for the terrain scene node? I'm thinking this is probably my lack of knowledge about the Irrlicht engine that is causing an issue..

Thanks

Jarrett
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Hmm, yeah, recompiling everything from scratch should be enough. Then it might be necessary to ask the debugger where the crash actually happens.
chisser98
Posts: 7
Joined: Thu Mar 31, 2011 11:57 pm
Location: Canada

Post by chisser98 »

Thanks hybrid.

One of the reasons I'm so baffled is that there is a Segmentation Fault that is causing my program to crash, right at the line where I call the new method:

Code: Select all

scene::ITerrainSceneNode* terrain = smgr_->addTerrainSceneNode(data, size, // size
			0, // parent node
			-1, // node id
			core::vector3df(0.f, 0.f, 0.f), // position
			core::vector3df(0.f, 0.f, 0.f), // rotation
			core::vector3df(40.f, 4.4f, 40.f), // scale
			video::SColor(255, 255, 255, 255), // vertexColor
			5, // maxLOD
			scene::ETPS_17, // patchSize
			4 // smoothFactor
			);
I have no idea why..it doesn't look like it's even entering the new method, it's just crashing (seemingly) because I called it..any ideas? :?

Also, not sure if this is relevant, but if I look through the variables in the debugger at the time of the crash I get some warnings about linker symbols for virtual tables for some classes. For instance:

Code: Select all

...
warning: can't find linker symbol for virtual table for `btDefaultMotionState' value
warning: can't find linker symbol for virtual table for `btDefaultMotionState' value
warning: can't find linker symbol for virtual table for `btDefaultMotionState' value
warning: can't find linker symbol for virtual table for `btDefaultMotionState' value
warning: can't find linker symbol for virtual table for `irr::scene::IMeshSceneNode' value
warning: can't find linker symbol for virtual table for `irr::scene::IMeshSceneNode' value
warning: can't find linker symbol for virtual table for `irr::scene::IMeshSceneNode' value
...
Again, not sure if it's relevant, but I thought I'd mention it.

I'd appreciate any insight you might be able to provide hybrid :D (or anyone else who might have any clue what's happening)
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Well, the easiest problem would be that smgr is a null pointer.
chisser98
Posts: 7
Joined: Thu Mar 31, 2011 11:57 pm
Location: Canada

Post by chisser98 »

hybrid wrote:Well, the easiest problem would be that smgr is a null pointer.
OH MY GOD. I am such an idiot.

Thanks hybrid, that was definitely the issue. I had changed my program to have a private member variable called smgr_, but it also had one for testing named smgr, and in this case I was testing functionality with the smgr_ member variable :oops:

Thanks alot hybrid, I appreciate it!

Jarrett
Post Reply