~baltix/+junk/irrlicht-test

« back to all changes in this revision

Viewing changes to examples/12.TerrainRendering/main.cpp

  • Committer: Mantas Kriaučiūnas
  • Date: 2011-07-18 13:06:25 UTC
  • Revision ID: mantas@akl.lt-20110718130625-c5pvifp61e7kj1ol
Included whole irrlicht SVN libraries to work around launchpad recipe issue with quilt, see https://answers.launchpad.net/launchpad/+question/165193

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/** Example 012 Terrain Rendering
 
2
 
 
3
This tutorial will briefly show how to use the terrain renderer of Irrlicht. It
 
4
will also show the terrain renderer triangle selector to be able to do
 
5
collision detection with terrain.
 
6
 
 
7
Note that the Terrain Renderer in Irrlicht is based on Spintz'
 
8
GeoMipMapSceneNode, lots of thanks go to him. DeusXL provided a new elegant
 
9
simple solution for building larger area on small heightmaps -> terrain
 
10
smoothing.
 
11
 
 
12
In the beginning there is nothing special. We include the needed header files
 
13
and create an event listener to listen if the user presses a key: The 'W' key
 
14
switches to wireframe mode, the 'P' key to pointcloud mode, and the 'D' key
 
15
toggles between solid and detail mapped material.
 
16
*/
 
17
#include <irrlicht.h>
 
18
#include "driverChoice.h"
 
19
 
 
20
using namespace irr;
 
21
 
 
22
#ifdef _MSC_VER
 
23
#pragma comment(lib, "Irrlicht.lib")
 
24
#endif
 
25
 
 
26
 
 
27
class MyEventReceiver : public IEventReceiver
 
28
{
 
29
public:
 
30
 
 
31
        MyEventReceiver(scene::ISceneNode* terrain, scene::ISceneNode* skybox, scene::ISceneNode* skydome) :
 
32
                Terrain(terrain), Skybox(skybox), Skydome(skydome), showBox(true), showDebug(false)
 
33
        {
 
34
                Skybox->setVisible(showBox);
 
35
                Skydome->setVisible(!showBox);
 
36
        }
 
37
 
 
38
        bool OnEvent(const SEvent& event)
 
39
        {
 
40
                // check if user presses the key 'W' or 'D'
 
41
                if (event.EventType == irr::EET_KEY_INPUT_EVENT && !event.KeyInput.PressedDown)
 
42
                {
 
43
                        switch (event.KeyInput.Key)
 
44
                        {
 
45
                        case irr::KEY_KEY_W: // switch wire frame mode
 
46
                                Terrain->setMaterialFlag(video::EMF_WIREFRAME,
 
47
                                                !Terrain->getMaterial(0).Wireframe);
 
48
                                Terrain->setMaterialFlag(video::EMF_POINTCLOUD, false);
 
49
                                return true;
 
50
                        case irr::KEY_KEY_P: // switch wire frame mode
 
51
                                Terrain->setMaterialFlag(video::EMF_POINTCLOUD,
 
52
                                                !Terrain->getMaterial(0).PointCloud);
 
53
                                Terrain->setMaterialFlag(video::EMF_WIREFRAME, false);
 
54
                                return true;
 
55
                        case irr::KEY_KEY_D: // toggle detail map
 
56
                                Terrain->setMaterialType(
 
57
                                        Terrain->getMaterial(0).MaterialType == video::EMT_SOLID ?
 
58
                                        video::EMT_DETAIL_MAP : video::EMT_SOLID);
 
59
                                return true;
 
60
                        case irr::KEY_KEY_S: // toggle skies
 
61
                                showBox=!showBox;
 
62
                                Skybox->setVisible(showBox);
 
63
                                Skydome->setVisible(!showBox);
 
64
                                return true;
 
65
                        case irr::KEY_KEY_X: // toggle debug information
 
66
                                showDebug=!showDebug;
 
67
                                Terrain->setDebugDataVisible(showDebug?scene::EDS_BBOX_ALL:scene::EDS_OFF);
 
68
                                return true;
 
69
                        default:
 
70
                                break;
 
71
                        }
 
72
                }
 
73
 
 
74
                return false;
 
75
        }
 
76
 
 
77
private:
 
78
        scene::ISceneNode* Terrain;
 
79
        scene::ISceneNode* Skybox;
 
80
        scene::ISceneNode* Skydome;
 
81
        bool showBox;
 
82
        bool showDebug;
 
83
};
 
84
 
 
85
 
 
86
/*
 
87
The start of the main function starts like in most other example. We ask the
 
88
user for the desired renderer and start it up. This time with the advanced
 
89
parameter handling.
 
90
*/
 
91
int main()
 
92
{
 
93
        // ask user for driver
 
94
        video::E_DRIVER_TYPE driverType=driverChoiceConsole();
 
95
        if (driverType==video::EDT_COUNT)
 
96
                return 1;
 
97
 
 
98
        // create device with full flexibility over creation parameters
 
99
        // you can add more parameters if desired, check irr::SIrrlichtCreationParameters
 
100
        irr::SIrrlichtCreationParameters params;
 
101
        params.DriverType=driverType;
 
102
        params.WindowSize=core::dimension2d<u32>(640, 480);
 
103
        IrrlichtDevice* device = createDeviceEx(params);
 
104
 
 
105
        if (device == 0)
 
106
                return 1; // could not create selected driver.
 
107
 
 
108
        
 
109
        /*
 
110
        First, we add standard stuff to the scene: A nice irrlicht engine
 
111
        logo, a small help text, a user controlled camera, and we disable
 
112
        the mouse cursor.
 
113
        */
 
114
 
 
115
        video::IVideoDriver* driver = device->getVideoDriver();
 
116
        scene::ISceneManager* smgr = device->getSceneManager();
 
117
        gui::IGUIEnvironment* env = device->getGUIEnvironment();
 
118
 
 
119
        driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true);
 
120
 
 
121
        // add irrlicht logo
 
122
        env->addImage(driver->getTexture("../../media/irrlichtlogo2.png"),
 
123
                core::position2d<s32>(10,10));
 
124
 
 
125
        //set other font
 
126
        env->getSkin()->setFont(env->getFont("../../media/fontlucida.png"));
 
127
 
 
128
        // add some help text
 
129
        env->addStaticText(
 
130
                L"Press 'W' to change wireframe mode\nPress 'D' to toggle detail map\nPress 'S' to toggle skybox/skydome",
 
131
                core::rect<s32>(10,421,250,475), true, true, 0, -1, true);
 
132
 
 
133
        // add camera
 
134
        scene::ICameraSceneNode* camera =
 
135
                smgr->addCameraSceneNodeFPS(0,100.0f,1.2f);
 
136
 
 
137
        camera->setPosition(core::vector3df(2700*2,255*2,2600*2));
 
138
        camera->setTarget(core::vector3df(2397*2,343*2,2700*2));
 
139
        camera->setFarValue(42000.0f);
 
140
 
 
141
        // disable mouse cursor
 
142
        device->getCursorControl()->setVisible(false);
 
143
 
 
144
        /*
 
145
        Here comes the terrain renderer scene node: We add it just like any
 
146
        other scene node to the scene using
 
147
        ISceneManager::addTerrainSceneNode(). The only parameter we use is a
 
148
        file name to the heightmap we use. A heightmap is simply a gray scale
 
149
        texture. The terrain renderer loads it and creates the 3D terrain from
 
150
        it.
 
151
 
 
152
        To make the terrain look more big, we change the scale factor of
 
153
        it to (40, 4.4, 40). Because we don't have any dynamic lights in the
 
154
        scene, we switch off the lighting, and we set the file
 
155
        terrain-texture.jpg as texture for the terrain and detailmap3.jpg as
 
156
        second texture, called detail map. At last, we set the scale values for
 
157
        the texture: The first texture will be repeated only one time over the
 
158
        whole terrain, and the second one (detail map) 20 times.
 
159
        */
 
160
 
 
161
        // add terrain scene node
 
162
        scene::ITerrainSceneNode* terrain = smgr->addTerrainSceneNode(
 
163
                "../../media/terrain-heightmap.bmp",
 
164
                0,                                      // parent node
 
165
                -1,                                     // node id
 
166
                core::vector3df(0.f, 0.f, 0.f),         // position
 
167
                core::vector3df(0.f, 0.f, 0.f),         // rotation
 
168
                core::vector3df(40.f, 4.4f, 40.f),      // scale
 
169
                video::SColor ( 255, 255, 255, 255 ),   // vertexColor
 
170
                5,                                      // maxLOD
 
171
                scene::ETPS_17,                         // patchSize
 
172
                4                                       // smoothFactor
 
173
                );
 
174
 
 
175
        terrain->setMaterialFlag(video::EMF_LIGHTING, false);
 
176
 
 
177
        terrain->setMaterialTexture(0,
 
178
                        driver->getTexture("../../media/terrain-texture.jpg"));
 
179
        terrain->setMaterialTexture(1,
 
180
                        driver->getTexture("../../media/detailmap3.jpg"));
 
181
        
 
182
        terrain->setMaterialType(video::EMT_DETAIL_MAP);
 
183
 
 
184
        terrain->scaleTexture(1.0f, 20.0f);
 
185
 
 
186
        /*
 
187
        To be able to do collision with the terrain, we create a triangle selector.
 
188
        If you want to know what triangle selectors do, just take a look into the
 
189
        collision tutorial. The terrain triangle selector works together with the
 
190
        terrain. To demonstrate this, we create a collision response animator
 
191
        and attach it to the camera, so that the camera will not be able to fly
 
192
        through the terrain.
 
193
        */
 
194
 
 
195
        // create triangle selector for the terrain     
 
196
        scene::ITriangleSelector* selector
 
197
                = smgr->createTerrainTriangleSelector(terrain, 0);
 
198
        terrain->setTriangleSelector(selector);
 
199
 
 
200
        // create collision response animator and attach it to the camera
 
201
        scene::ISceneNodeAnimator* anim = smgr->createCollisionResponseAnimator(
 
202
                selector, camera, core::vector3df(60,100,60),
 
203
                core::vector3df(0,0,0),
 
204
                core::vector3df(0,50,0));
 
205
        selector->drop();
 
206
        camera->addAnimator(anim);
 
207
        anim->drop();
 
208
 
 
209
        /* If you need access to the terrain data you can also do this directly via the following code fragment.
 
210
        */
 
211
        scene::CDynamicMeshBuffer* buffer = new scene::CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_16BIT);
 
212
        terrain->getMeshBufferForLOD(*buffer, 0);
 
213
        video::S3DVertex2TCoords* data = (video::S3DVertex2TCoords*)buffer->getVertexBuffer().getData();
 
214
        // Work on data or get the IndexBuffer with a similar call.
 
215
        buffer->drop(); // When done drop the buffer again.
 
216
 
 
217
        /*
 
218
        To make the user be able to switch between normal and wireframe mode,
 
219
        we create an instance of the event reciever from above and let Irrlicht
 
220
        know about it. In addition, we add the skybox which we already used in
 
221
        lots of Irrlicht examples and a skydome, which is shown mutually
 
222
        exclusive with the skybox by pressing 'S'.
 
223
        */
 
224
 
 
225
        // create skybox and skydome
 
226
        driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);
 
227
 
 
228
        scene::ISceneNode* skybox=smgr->addSkyBoxSceneNode(
 
229
                driver->getTexture("../../media/irrlicht2_up.jpg"),
 
230
                driver->getTexture("../../media/irrlicht2_dn.jpg"),
 
231
                driver->getTexture("../../media/irrlicht2_lf.jpg"),
 
232
                driver->getTexture("../../media/irrlicht2_rt.jpg"),
 
233
                driver->getTexture("../../media/irrlicht2_ft.jpg"),
 
234
                driver->getTexture("../../media/irrlicht2_bk.jpg"));
 
235
        scene::ISceneNode* skydome=smgr->addSkyDomeSceneNode(driver->getTexture("../../media/skydome.jpg"),16,8,0.95f,2.0f);
 
236
 
 
237
        driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true);
 
238
 
 
239
        // create event receiver
 
240
        MyEventReceiver receiver(terrain, skybox, skydome);
 
241
        device->setEventReceiver(&receiver);
 
242
 
 
243
        /*
 
244
        That's it, draw everything.
 
245
        */
 
246
 
 
247
        int lastFPS = -1;
 
248
 
 
249
        while(device->run())
 
250
        if (device->isWindowActive())
 
251
        {
 
252
                driver->beginScene(true, true, 0 );
 
253
 
 
254
                smgr->drawAll();
 
255
                env->drawAll();
 
256
 
 
257
                driver->endScene();
 
258
 
 
259
                // display frames per second in window title
 
260
                int fps = driver->getFPS();
 
261
                if (lastFPS != fps)
 
262
                {
 
263
                        core::stringw str = L"Terrain Renderer - Irrlicht Engine [";
 
264
                        str += driver->getName();
 
265
                        str += "] FPS:";
 
266
                        str += fps;
 
267
                        // Also print terrain height of current camera position
 
268
                        // We can use camera position because terrain is located at coordinate origin
 
269
                        str += " Height: ";
 
270
                        str += terrain->getHeight(camera->getAbsolutePosition().X,
 
271
                                        camera->getAbsolutePosition().Z);
 
272
 
 
273
                        device->setWindowCaption(str.c_str());
 
274
                        lastFPS = fps;
 
275
                }
 
276
        }
 
277
 
 
278
        device->drop();
 
279
        
 
280
        return 0;
 
281
}
 
282
 
 
283
/*
 
284
Now you know how to use terrain in Irrlicht.
 
285
**/