aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/others/irrlicht-1.8.1/examples/23.SMeshHandling/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/others/irrlicht-1.8.1/examples/23.SMeshHandling/main.cpp')
-rw-r--r--src/others/irrlicht-1.8.1/examples/23.SMeshHandling/main.cpp426
1 files changed, 426 insertions, 0 deletions
diff --git a/src/others/irrlicht-1.8.1/examples/23.SMeshHandling/main.cpp b/src/others/irrlicht-1.8.1/examples/23.SMeshHandling/main.cpp
new file mode 100644
index 0000000..c3c2ccf
--- /dev/null
+++ b/src/others/irrlicht-1.8.1/examples/23.SMeshHandling/main.cpp
@@ -0,0 +1,426 @@
1/** Example 023 SMeshBufferHandling
2
3A tutorial by geoff.
4
5In this tutorial we'll learn how to create custom meshes and deal with them
6with Irrlicht. We'll create an interesting heightmap with some lighting effects.
7With keys 1,2,3 you can choose a different mesh layout, which is put into the
8mesh buffers as desired. All positions, normals, etc. are updated accordingly.
9
10Ok, let's start with the headers (I think there's nothing to say about it)
11*/
12
13#include <irrlicht.h>
14#include "driverChoice.h"
15
16#ifdef _MSC_VER
17#pragma comment(lib, "Irrlicht.lib")
18#endif
19
20//Namespaces for the engine
21using namespace irr;
22using namespace video;
23using namespace core;
24using namespace scene;
25using namespace io;
26using namespace gui;
27
28/* This is the type of the functions which work out the colour. */
29typedef SColor colour_func(f32 x, f32 y, f32 z);
30
31/* Here comes a set of functions which can be used for coloring the nodes while
32creating the mesh. */
33
34// Greyscale, based on the height.
35SColor grey(f32, f32, f32 z)
36{
37 u32 n = (u32)(255.f * z);
38 return SColor(255, n, n, n);
39}
40
41// Interpolation between blue and white, with red added in one
42// direction and green in the other.
43SColor yellow(f32 x, f32 y, f32)
44{
45 return SColor(255, 128 + (u32)(127.f * x), 128 + (u32)(127.f * y), 255);
46}
47
48// Pure white.
49SColor white(f32, f32, f32) { return SColor(255, 255, 255, 255); }
50
51/* The type of the functions which generate the heightmap. x and y
52range between -0.5 and 0.5, and s is the scale of the heightmap. */
53
54typedef f32 generate_func(s16 x, s16 y, f32 s);
55
56// An interesting sample function :-)
57f32 eggbox(s16 x, s16 y, f32 s)
58{
59 const f32 r = 4.f*sqrtf((f32)(x*x + y*y))/s;
60 const f32 z = expf(-r * 2) * (cosf(0.2f * x) + cosf(0.2f * y));
61 return 0.25f+0.25f*z;
62}
63
64// A rather dumb sine function :-/
65f32 moresine(s16 x, s16 y, f32 s)
66{
67 const f32 xx=0.3f*(f32)x/s;
68 const f32 yy=12*y/s;
69 const f32 z = sinf(xx*xx+yy)*sinf(xx+yy*yy);
70 return 0.25f + 0.25f * z;
71}
72
73// A simple function
74f32 justexp(s16 x, s16 y, f32 s)
75{
76 const f32 xx=6*x/s;
77 const f32 yy=6*y/s;
78 const f32 z = (xx*xx+yy*yy);
79 return 0.3f*z*cosf(xx*yy);
80}
81
82/* A simple class for representing heightmaps. Most of this should be obvious. */
83
84class HeightMap
85{
86private:
87 const u16 Width;
88 const u16 Height;
89 f32 s;
90 core::array<f32> data;
91public:
92 HeightMap(u16 _w, u16 _h) : Width(_w), Height(_h), s(0.f), data(0)
93 {
94 s = sqrtf((f32)(Width * Width + Height * Height));
95 data.set_used(Width * Height);
96 }
97
98 // Fill the heightmap with values generated from f.
99 void generate(generate_func f)
100 {
101 u32 i=0;
102 for(u16 y = 0; y < Height; ++y)
103 for(u16 x = 0; x < Width; ++x)
104 set(i++, calc(f, x, y));
105 }
106
107 u16 height() const { return Height; }
108 u16 width() const { return Width; }
109
110 f32 calc(generate_func f, u16 x, u16 y) const
111 {
112 const f32 xx = (f32)x - Width*0.5f;
113 const f32 yy = (f32)y - Height*0.5f;
114 return f((u16)xx, (u16)yy, s);
115 }
116
117 // The height at (x, y) is at position y * Width + x.
118
119 void set(u16 x, u16 y, f32 z) { data[y * Width + x] = z; }
120 void set(u32 i, f32 z) { data[i] = z; }
121 f32 get(u16 x, u16 y) const { return data[y * Width + x]; }
122
123 /* The only difficult part. This considers the normal at (x, y) to
124 be the cross product of the vectors between the adjacent points
125 in the horizontal and vertical directions.
126
127 s is a scaling factor, which is necessary if the height units are
128 different from the coordinate units; for example, if your map has
129 heights in metres and the coordinates are in units of a
130 kilometer. */
131
132 vector3df getnormal(u16 x, u16 y, f32 s) const
133 {
134 const f32 zc = get(x, y);
135 f32 zl, zr, zu, zd;
136
137 if (x == 0)
138 {
139 zr = get(x + 1, y);
140 zl = zc + zc - zr;
141 }
142 else if (x == Width - 1)
143 {
144 zl = get(x - 1, y);
145 zr = zc + zc - zl;
146 }
147 else
148 {
149 zr = get(x + 1, y);
150 zl = get(x - 1, y);
151 }
152
153 if (y == 0)
154 {
155 zd = get(x, y + 1);
156 zu = zc + zc - zd;
157 }
158 else if (y == Height - 1)
159 {
160 zu = get(x, y - 1);
161 zd = zc + zc - zu;
162 }
163 else
164 {
165 zd = get(x, y + 1);
166 zu = get(x, y - 1);
167 }
168
169 return vector3df(s * 2 * (zl - zr), 4, s * 2 * (zd - zu)).normalize();
170 }
171};
172
173/* A class which generates a mesh from a heightmap. */
174class TMesh
175{
176private:
177 u16 Width;
178 u16 Height;
179 f32 Scale;
180public:
181 SMesh* Mesh;
182
183 TMesh() : Mesh(0), Width(0), Height(0), Scale(1.f)
184 {
185 Mesh = new SMesh();
186 }
187
188 ~TMesh()
189 {
190 Mesh->drop();
191 }
192
193 // Unless the heightmap is small, it won't all fit into a single
194 // SMeshBuffer. This function chops it into pieces and generates a
195 // buffer from each one.
196
197 void init(const HeightMap &hm, f32 scale, colour_func cf, IVideoDriver *driver)
198 {
199 Scale = scale;
200
201 const u32 mp = driver -> getMaximalPrimitiveCount();
202 Width = hm.width();
203 Height = hm.height();
204
205 const u32 sw = mp / (6 * Height); // the width of each piece
206
207 u32 i=0;
208 for(u32 y0 = 0; y0 < Height; y0 += sw)
209 {
210 u16 y1 = y0 + sw;
211 if (y1 >= Height)
212 y1 = Height - 1; // the last one might be narrower
213 addstrip(hm, cf, y0, y1, i);
214 ++i;
215 }
216 if (i<Mesh->getMeshBufferCount())
217 {
218 // clear the rest
219 for (u32 j=i; j<Mesh->getMeshBufferCount(); ++j)
220 {
221 Mesh->getMeshBuffer(j)->drop();
222 }
223 Mesh->MeshBuffers.erase(i,Mesh->getMeshBufferCount()-i);
224 }
225 // set dirty flag to make sure that hardware copies of this
226 // buffer are also updated, see IMesh::setHardwareMappingHint
227 Mesh->setDirty();
228 Mesh->recalculateBoundingBox();
229 }
230
231 // Generate a SMeshBuffer which represents all the vertices and
232 // indices for values of y between y0 and y1, and add it to the
233 // mesh.
234
235 void addstrip(const HeightMap &hm, colour_func cf, u16 y0, u16 y1, u32 bufNum)
236 {
237 SMeshBuffer *buf = 0;
238 if (bufNum<Mesh->getMeshBufferCount())
239 {
240 buf = (SMeshBuffer*)Mesh->getMeshBuffer(bufNum);
241 }
242 else
243 {
244 // create new buffer
245 buf = new SMeshBuffer();
246 Mesh->addMeshBuffer(buf);
247 // to simplify things we drop here but continue using buf
248 buf->drop();
249 }
250 buf->Vertices.set_used((1 + y1 - y0) * Width);
251
252 u32 i=0;
253 for (u16 y = y0; y <= y1; ++y)
254 {
255 for (u16 x = 0; x < Width; ++x)
256 {
257 const f32 z = hm.get(x, y);
258 const f32 xx = (f32)x/(f32)Width;
259 const f32 yy = (f32)y/(f32)Height;
260
261 S3DVertex& v = buf->Vertices[i++];
262 v.Pos.set(x, Scale * z, y);
263 v.Normal.set(hm.getnormal(x, y, Scale));
264 v.Color=cf(xx, yy, z);
265 v.TCoords.set(xx, yy);
266 }
267 }
268
269 buf->Indices.set_used(6 * (Width - 1) * (y1 - y0));
270 i=0;
271 for(u16 y = y0; y < y1; ++y)
272 {
273 for(u16 x = 0; x < Width - 1; ++x)
274 {
275 const u16 n = (y-y0) * Width + x;
276 buf->Indices[i]=n;
277 buf->Indices[++i]=n + Width;
278 buf->Indices[++i]=n + Width + 1;
279 buf->Indices[++i]=n + Width + 1;
280 buf->Indices[++i]=n + 1;
281 buf->Indices[++i]=n;
282 ++i;
283 }
284 }
285
286 buf->recalculateBoundingBox();
287 }
288};
289
290/*
291Our event receiver implementation, taken from tutorial 4.
292*/
293class MyEventReceiver : public IEventReceiver
294{
295public:
296 // This is the one method that we have to implement
297 virtual bool OnEvent(const SEvent& event)
298 {
299 // Remember whether each key is down or up
300 if (event.EventType == irr::EET_KEY_INPUT_EVENT)
301 KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;
302
303 return false;
304 }
305
306 // This is used to check whether a key is being held down
307 virtual bool IsKeyDown(EKEY_CODE keyCode) const
308 {
309 return KeyIsDown[keyCode];
310 }
311
312 MyEventReceiver()
313 {
314 for (u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)
315 KeyIsDown[i] = false;
316 }
317
318private:
319 // We use this array to store the current state of each key
320 bool KeyIsDown[KEY_KEY_CODES_COUNT];
321};
322
323/*
324Much of this is code taken from some of the examples. We merely set
325up a mesh from a heightmap, light it with a moving light, and allow
326the user to navigate around it.
327*/
328
329int main(int argc, char* argv[])
330{
331 // ask user for driver
332 video::E_DRIVER_TYPE driverType=driverChoiceConsole();
333 if (driverType==video::EDT_COUNT)
334 return 1;
335
336 MyEventReceiver receiver;
337 IrrlichtDevice* device = createDevice(driverType,
338 core::dimension2du(800, 600), 32, false, false, false,
339 &receiver);
340
341 if(device == 0)
342 return 1;
343
344 IVideoDriver *driver = device->getVideoDriver();
345 ISceneManager *smgr = device->getSceneManager();
346 device->setWindowCaption(L"Irrlicht Example for SMesh usage.");
347
348 /*
349 Create the custom mesh and initialize with a heightmap
350 */
351 TMesh mesh;
352 HeightMap hm = HeightMap(255, 255);
353 hm.generate(eggbox);
354 mesh.init(hm, 50.f, grey, driver);
355
356 // Add the mesh to the scene graph
357 IMeshSceneNode* meshnode = smgr -> addMeshSceneNode(mesh.Mesh);
358 meshnode->setMaterialFlag(video::EMF_BACK_FACE_CULLING, false);
359
360 // light is just for nice effects
361 ILightSceneNode *node = smgr->addLightSceneNode(0, vector3df(0,100,0),
362 SColorf(1.0f, 0.6f, 0.7f, 1.0f), 500.0f);
363 if (node)
364 {
365 node->getLightData().Attenuation.set(0.f, 1.f/500.f, 0.f);
366 ISceneNodeAnimator* anim = smgr->createFlyCircleAnimator(vector3df(0,150,0),250.0f);
367 if (anim)
368 {
369 node->addAnimator(anim);
370 anim->drop();
371 }
372 }
373
374 ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS();
375 if (camera)
376 {
377 camera->setPosition(vector3df(-20.f, 150.f, -20.f));
378 camera->setTarget(vector3df(200.f, -80.f, 150.f));
379 camera->setFarValue(20000.0f);
380 }
381
382 /*
383 Just a usual render loop with event handling. The custom mesh is
384 a usual part of the scene graph which gets rendered by drawAll.
385 */
386 while(device->run())
387 {
388 if(!device->isWindowActive())
389 {
390 device->sleep(100);
391 continue;
392 }
393
394 if(receiver.IsKeyDown(irr::KEY_KEY_W))
395 {
396 meshnode->setMaterialFlag(video::EMF_WIREFRAME, !meshnode->getMaterial(0).Wireframe);
397 }
398 else if(receiver.IsKeyDown(irr::KEY_KEY_1))
399 {
400 hm.generate(eggbox);
401 mesh.init(hm, 50.f, grey, driver);
402 }
403 else if(receiver.IsKeyDown(irr::KEY_KEY_2))
404 {
405 hm.generate(moresine);
406 mesh.init(hm, 50.f, yellow, driver);
407 }
408 else if(receiver.IsKeyDown(irr::KEY_KEY_3))
409 {
410 hm.generate(justexp);
411 mesh.init(hm, 50.f, yellow, driver);
412 }
413
414 driver->beginScene(true, true, SColor(0xff000000));
415 smgr->drawAll();
416 driver->endScene();
417 }
418
419 device->drop();
420
421 return 0;
422}
423
424/*
425That's it! Just compile and play around with the program.
426**/