Terrain engine

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Post Reply
maitrelame2
Posts: 26
Joined: Sun Jan 21, 2007 9:11 pm

Terrain engine

Post by maitrelame2 »

Hi,

I have been trying to find an easy to use terrain engine but couldn't find one so i made one.
It works wit 256x256 heightmaps. (You can adapt it to 128x128... by using the ratio 240/256 for the size but we will get to it later).
Basically the engine is going to make a virtual grid :

Image

And is going to get the distance between your camera and the map coordinates. If the distance is shorter than the distance you have defined, it will load the grid, if the distance is bigger it will remove the map. If you go back it will reload the map.
You will only have to rename your heightmaps to gridX.X.png (X.X being the virtual coordinates cf : picture above) and same for the color that you will rename colorX.X.png.

Changelog :

v0.1 : Added physics
v0.2 working : adding PhysX wrapper.

Here is the code :
CTerrain.cpp

Code: Select all

/* Author : Y
Date : 08/12/2008
Copyright Naruto : Tatakai 2008 */

#include "CTerrain.h"


#define DISTANCE 8000 /// Distance from which the terrain will be loaded or removed if bigger
#define SCALEXZ 20
#define SCALEY 2
#define RATIO 240 /// for 256 I think that it would be 120 for 128
#define SIZE 4800 /// multiply SCALEXZ by RATIO


CTerrain::CTerrain()
{
    smgr = Graphic::GetSingleton()->GetSmgrDevice();
    driver = Graphic::GetSingleton()->GetDriverDevice();
    m_count = 16;
    for(int i = 0;i < 4; i++)
    {
        for(int j = 0;j < 4; j++)
        {
            char* tmp = new char[100];
            //sprintf(tmp,"Media2/grid%ld.%ld.png",i,j);
            char* tmp2 = new char[100];
            //sprintf(tmp2,"Media2/color%ld.%ld.png",i,j);
            sprintf(tmp2,"Media2/color0.0.png");
            sprintf(tmp,"Media2/grid0.0.png");
            TerrainInfo* Tmp = new TerrainInfo;
            Tmp->loaded = false;
            Tmp->X = i*SIZE;
            Tmp->Z = j*SIZE;
            Tmp->height = tmp;
            Tmp->color = tmp2;
            m_terrainInfo.push_back(Tmp);
        }
    }
}

CTerrain::~CTerrain()
{
    int i = 0;
    while(i < m_count)
    {
       delete m_terrainInfo.at(i)->height;
       delete m_terrainInfo.at(i)->color;
       delete  m_terrainInfo.at(i);
       i++;
    }
}

void CTerrain::render()
{
    int distance,X,Z = 0;
    int id = 0;
    vector3df camPos = Graphic::GetSingleton()->GetCameraSceneNode()->getAbsolutePosition();
    vector3df nodePos = Graphic::GetSingleton()->GetMainSceneNode()->getPosition();
    while(id < m_count)
    {
        X = camPos.X - m_terrainInfo.at(id)->X;
        Z = camPos.Z - m_terrainInfo.at(id)->Z;
        distance = sqrt(pow(X,2)+pow(Z,2));
        if(distance < DISTANCE && m_terrainInfo.at(id)->loaded == false)
            loadGrid(id);
        if(distance > DISTANCE && m_terrainInfo.at(id)->loaded == true)
            deleteGrid(id);
        if(nodePos.X < m_terrainInfo.at(id)->X+4800 && nodePos.X > m_terrainInfo.at(id)->X &&
        nodePos.Z < m_terrainInfo.at(id)->Z+4800 && nodePos.Z > m_terrainInfo.at(id)->Z)
        {
            setAnimator(id);
        }
        else if(m_terrainInfo.at(id)->anim == true)
            m_terrainInfo.at(id)->anim = false;
        id++;
    }
}

void CTerrain::loadGrid(int id)
{
    	scene::ITerrainSceneNode* terrain = smgr->addTerrainSceneNode(
		m_terrainInfo.at(id)->height,
		0,
		-1,
		core::vector3df(m_terrainInfo.at(id)->X, 0.f, m_terrainInfo.at(id)->Z),
		core::vector3df(0.f, 0.f, 0.f),
		core::vector3df(SCALEXZ, SCALEY, SCALEXZ),
		video::SColor ( 255, 255, 255, 255 ),
		50,
		scene::ETPS_17,
		4
		);
    if(terrain)
    {
        terrain->setMaterialFlag(video::EMF_FOG_ENABLE, true);

        terrain->setMaterialFlag(video::EMF_LIGHTING, false);

        m_terrainInfo.at(id)->colorTexture = driver->getTexture(m_terrainInfo.at(id)->color);

        terrain->setMaterialTexture(0, m_terrainInfo.at(id)->colorTexture);
        terrain->setMaterialTexture(1, driver->getTexture("Media2/detail.jpg"));

        terrain->setMaterialType(video::EMT_DETAIL_MAP);

        terrain->scaleTexture(1.0f, 20.0f);

        m_terrainInfo.at(id)->loaded = true;
        m_terrain[id] = terrain;
    }
}

void CTerrain::deleteGrid(int id)
{
    m_terrain[id]->remove();
    m_terrainInfo.at(id)->loaded = false;
}

void CTerrain::setAnimator(int id)
{
    vector3df nodePos = YOURNODE>getPosition();
    nodePos.Y = (m_terrain[id]->getHeight(nodePos.X,nodePos.Z) + 25);
    YOURNODE->setPosition(nodePos);
}
CTerrain.h

Code: Select all

#include <irrlicht.h>
#include <iostream>


struct TerrainInfo
{
    int X;
    int Z;
    c8* height;
    c8* color;
    bool loaded;
    bool anim;
    ITexture* colorTexture;
};

class CTerrain {

    public:

        CTerrain();
        ~CTerrain();

        void render();
        void loadGrid(int);
        void deleteGrid(int);
        void setAnimator(int);


    private:

        vector<TerrainInfo*> m_terrainInfo;
        std::map<int,ITerrainSceneNode*> m_terrain;
        IVideoDriver*   driver;
        ISceneManager*  smgr;
        int m_count;


};

How to use ?
Pretty simple :
You just have to find a way to send your node and camera to the class ( I use a singleton so I don't have that problem ) You have to replace YOURCAMERA by your camera's pointer and YOURNODE by your node's pointer.
Then it's easy just add the line :
CTerrain* myTerrain = new CTerrain;
somewhere in your code.
And
myTerrain->render()
in your render loop.
And
delete myTerrain;
after your drop function.
But I repeat that you have to send a pointer to the class you can modify the constructor and make a pointer...

If you want to modify it do as you wish !
If you need help or If you have a suggestion feel free to reply to this post.
PS : The terrain is removed but 5mo of memory is still allocated after removing the terrain. It's not a big deal since those 5mo are deleted when you close your app.
If you want to change region just clean the smgr to free the memory at the same time
Last edited by maitrelame2 on Fri Jan 23, 2009 6:59 am, edited 3 times in total.
Irrlicht 4ever.
JP
Posts: 4526
Joined: Tue Sep 13, 2005 2:56 pm
Location: UK
Contact:

Post by JP »

Sounds good, much like Arras' tiled terrain scene node i imagine.

Those 5mb of unfreed memory is a big deal if you want to load different levels i would imagine, or is it a static amount of memory so it doesn't grow when you load a new level?

Do you know where the 5mb is going or is it an unknown leak? Could be to do with you not removing the heightmap textures from the driver when you're done with them?
Image Image Image
maitrelame2
Posts: 26
Joined: Sun Jan 21, 2007 9:11 pm

Post by maitrelame2 »

When I try to remove the heightmap texture it just crashes, because the memory seems to be freed before.
I don't know where the leak comes from.
I will try to delete the selector maybe it comes from there ?
And it's 5mb per level loaded.

EDIT : I can't get the collisions working correctly...
Is that because I am using 256x256 ?
I get stuck pretty much everywhere.
Irrlicht 4ever.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

The terrain scene node should be used with 129x129 heightmaps.
maitrelame2
Posts: 26
Joined: Sun Jan 21, 2007 9:11 pm

Post by maitrelame2 »

I got it working, made my own collision fonction ^^
Irrlicht 4ever.
Post Reply