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 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;
Code: Select all
virtual bool loadHeightMapRAWData(f32* data, s32 size, video::SColor vertexColor,
s32 smoothFactor);
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;
}
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;
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);
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;
}
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
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!
Thanks all,
Jarrett