diff options
author | David Walter Seikel | 2016-03-28 22:28:34 +1000 |
---|---|---|
committer | David Walter Seikel | 2016-03-28 22:28:34 +1000 |
commit | 7028cbe09c688437910a25623098762bf0fa592d (patch) | |
tree | 10b5af58277d9880380c2251f109325542c4e6eb /src/others/irrlicht-1.8.1/examples/23.SMeshHandling/main.cpp | |
parent | Move lemon to the src/others directory. (diff) | |
download | SledjHamr-7028cbe09c688437910a25623098762bf0fa592d.zip SledjHamr-7028cbe09c688437910a25623098762bf0fa592d.tar.gz SledjHamr-7028cbe09c688437910a25623098762bf0fa592d.tar.bz2 SledjHamr-7028cbe09c688437910a25623098762bf0fa592d.tar.xz |
Move Irrlicht to src/others.
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.cpp | 426 |
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 | |||
3 | A tutorial by geoff. | ||
4 | |||
5 | In this tutorial we'll learn how to create custom meshes and deal with them | ||
6 | with Irrlicht. We'll create an interesting heightmap with some lighting effects. | ||
7 | With keys 1,2,3 you can choose a different mesh layout, which is put into the | ||
8 | mesh buffers as desired. All positions, normals, etc. are updated accordingly. | ||
9 | |||
10 | Ok, 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 | ||
21 | using namespace irr; | ||
22 | using namespace video; | ||
23 | using namespace core; | ||
24 | using namespace scene; | ||
25 | using namespace io; | ||
26 | using namespace gui; | ||
27 | |||
28 | /* This is the type of the functions which work out the colour. */ | ||
29 | typedef 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 | ||
32 | creating the mesh. */ | ||
33 | |||
34 | // Greyscale, based on the height. | ||
35 | SColor 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. | ||
43 | SColor 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. | ||
49 | SColor white(f32, f32, f32) { return SColor(255, 255, 255, 255); } | ||
50 | |||
51 | /* The type of the functions which generate the heightmap. x and y | ||
52 | range between -0.5 and 0.5, and s is the scale of the heightmap. */ | ||
53 | |||
54 | typedef f32 generate_func(s16 x, s16 y, f32 s); | ||
55 | |||
56 | // An interesting sample function :-) | ||
57 | f32 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 :-/ | ||
65 | f32 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 | ||
74 | f32 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 | |||
84 | class HeightMap | ||
85 | { | ||
86 | private: | ||
87 | const u16 Width; | ||
88 | const u16 Height; | ||
89 | f32 s; | ||
90 | core::array<f32> data; | ||
91 | public: | ||
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. */ | ||
174 | class TMesh | ||
175 | { | ||
176 | private: | ||
177 | u16 Width; | ||
178 | u16 Height; | ||
179 | f32 Scale; | ||
180 | public: | ||
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 | /* | ||
291 | Our event receiver implementation, taken from tutorial 4. | ||
292 | */ | ||
293 | class MyEventReceiver : public IEventReceiver | ||
294 | { | ||
295 | public: | ||
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 | |||
318 | private: | ||
319 | // We use this array to store the current state of each key | ||
320 | bool KeyIsDown[KEY_KEY_CODES_COUNT]; | ||
321 | }; | ||
322 | |||
323 | /* | ||
324 | Much of this is code taken from some of the examples. We merely set | ||
325 | up a mesh from a heightmap, light it with a moving light, and allow | ||
326 | the user to navigate around it. | ||
327 | */ | ||
328 | |||
329 | int 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 | /* | ||
425 | That's it! Just compile and play around with the program. | ||
426 | **/ | ||