diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/irrlicht-1.8.1/source/Irrlicht/CGeometryCreator.cpp | 892 |
1 files changed, 892 insertions, 0 deletions
diff --git a/libraries/irrlicht-1.8.1/source/Irrlicht/CGeometryCreator.cpp b/libraries/irrlicht-1.8.1/source/Irrlicht/CGeometryCreator.cpp new file mode 100644 index 0000000..c592833 --- /dev/null +++ b/libraries/irrlicht-1.8.1/source/Irrlicht/CGeometryCreator.cpp | |||
@@ -0,0 +1,892 @@ | |||
1 | // Copyright (C) 2002-2012 Nikolaus Gebhardt | ||
2 | // This file is part of the "Irrlicht Engine". | ||
3 | // For conditions of distribution and use, see copyright notice in irrlicht.h | ||
4 | |||
5 | #include "CGeometryCreator.h" | ||
6 | #include "SAnimatedMesh.h" | ||
7 | #include "SMeshBuffer.h" | ||
8 | #include "SMesh.h" | ||
9 | #include "IMesh.h" | ||
10 | #include "IVideoDriver.h" | ||
11 | #include "os.h" | ||
12 | |||
13 | namespace irr | ||
14 | { | ||
15 | namespace scene | ||
16 | { | ||
17 | |||
18 | IMesh* CGeometryCreator::createCubeMesh(const core::vector3df& size) const | ||
19 | { | ||
20 | SMeshBuffer* buffer = new SMeshBuffer(); | ||
21 | |||
22 | // Create indices | ||
23 | const u16 u[36] = { 0,2,1, 0,3,2, 1,5,4, 1,2,5, 4,6,7, 4,5,6, | ||
24 | 7,3,0, 7,6,3, 9,5,2, 9,8,5, 0,11,10, 0,10,7}; | ||
25 | |||
26 | buffer->Indices.set_used(36); | ||
27 | |||
28 | for (u32 i=0; i<36; ++i) | ||
29 | buffer->Indices[i] = u[i]; | ||
30 | |||
31 | |||
32 | // Create vertices | ||
33 | video::SColor clr(255,255,255,255); | ||
34 | |||
35 | buffer->Vertices.reallocate(12); | ||
36 | |||
37 | buffer->Vertices.push_back(video::S3DVertex(0,0,0, -1,-1,-1, clr, 0, 1)); | ||
38 | buffer->Vertices.push_back(video::S3DVertex(1,0,0, 1,-1,-1, clr, 1, 1)); | ||
39 | buffer->Vertices.push_back(video::S3DVertex(1,1,0, 1, 1,-1, clr, 1, 0)); | ||
40 | buffer->Vertices.push_back(video::S3DVertex(0,1,0, -1, 1,-1, clr, 0, 0)); | ||
41 | buffer->Vertices.push_back(video::S3DVertex(1,0,1, 1,-1, 1, clr, 0, 1)); | ||
42 | buffer->Vertices.push_back(video::S3DVertex(1,1,1, 1, 1, 1, clr, 0, 0)); | ||
43 | buffer->Vertices.push_back(video::S3DVertex(0,1,1, -1, 1, 1, clr, 1, 0)); | ||
44 | buffer->Vertices.push_back(video::S3DVertex(0,0,1, -1,-1, 1, clr, 1, 1)); | ||
45 | buffer->Vertices.push_back(video::S3DVertex(0,1,1, -1, 1, 1, clr, 0, 1)); | ||
46 | buffer->Vertices.push_back(video::S3DVertex(0,1,0, -1, 1,-1, clr, 1, 1)); | ||
47 | buffer->Vertices.push_back(video::S3DVertex(1,0,1, 1,-1, 1, clr, 1, 0)); | ||
48 | buffer->Vertices.push_back(video::S3DVertex(1,0,0, 1,-1,-1, clr, 0, 0)); | ||
49 | |||
50 | // Recalculate bounding box | ||
51 | buffer->BoundingBox.reset(0,0,0); | ||
52 | |||
53 | for (u32 i=0; i<12; ++i) | ||
54 | { | ||
55 | buffer->Vertices[i].Pos -= core::vector3df(0.5f, 0.5f, 0.5f); | ||
56 | buffer->Vertices[i].Pos *= size; | ||
57 | buffer->BoundingBox.addInternalPoint(buffer->Vertices[i].Pos); | ||
58 | } | ||
59 | |||
60 | SMesh* mesh = new SMesh; | ||
61 | mesh->addMeshBuffer(buffer); | ||
62 | buffer->drop(); | ||
63 | |||
64 | mesh->recalculateBoundingBox(); | ||
65 | return mesh; | ||
66 | } | ||
67 | |||
68 | |||
69 | // creates a hill plane | ||
70 | IMesh* CGeometryCreator::createHillPlaneMesh( | ||
71 | const core::dimension2d<f32>& tileSize, | ||
72 | const core::dimension2d<u32>& tc, video::SMaterial* material, | ||
73 | f32 hillHeight, const core::dimension2d<f32>& ch, | ||
74 | const core::dimension2d<f32>& textureRepeatCount) const | ||
75 | { | ||
76 | core::dimension2d<u32> tileCount = tc; | ||
77 | core::dimension2d<f32> countHills = ch; | ||
78 | |||
79 | if (countHills.Width < 0.01f) | ||
80 | countHills.Width = 1.f; | ||
81 | if (countHills.Height < 0.01f) | ||
82 | countHills.Height = 1.f; | ||
83 | |||
84 | // center | ||
85 | const core::position2d<f32> center((tileSize.Width * tileCount.Width) * 0.5f, (tileSize.Height * tileCount.Height) * 0.5f); | ||
86 | |||
87 | // texture coord step | ||
88 | const core::dimension2d<f32> tx( | ||
89 | textureRepeatCount.Width / tileCount.Width, | ||
90 | textureRepeatCount.Height / tileCount.Height); | ||
91 | |||
92 | // add one more point in each direction for proper tile count | ||
93 | ++tileCount.Height; | ||
94 | ++tileCount.Width; | ||
95 | |||
96 | SMeshBuffer* buffer = new SMeshBuffer(); | ||
97 | video::S3DVertex vtx; | ||
98 | vtx.Color.set(255,255,255,255); | ||
99 | |||
100 | // create vertices from left-front to right-back | ||
101 | u32 x; | ||
102 | |||
103 | f32 sx=0.f, tsx=0.f; | ||
104 | for (x=0; x<tileCount.Width; ++x) | ||
105 | { | ||
106 | f32 sy=0.f, tsy=0.f; | ||
107 | for (u32 y=0; y<tileCount.Height; ++y) | ||
108 | { | ||
109 | vtx.Pos.set(sx - center.X, 0, sy - center.Y); | ||
110 | vtx.TCoords.set(tsx, 1.0f - tsy); | ||
111 | |||
112 | if (core::isnotzero(hillHeight)) | ||
113 | vtx.Pos.Y = sinf(vtx.Pos.X * countHills.Width * core::PI / center.X) * | ||
114 | cosf(vtx.Pos.Z * countHills.Height * core::PI / center.Y) * | ||
115 | hillHeight; | ||
116 | |||
117 | buffer->Vertices.push_back(vtx); | ||
118 | sy += tileSize.Height; | ||
119 | tsy += tx.Height; | ||
120 | } | ||
121 | sx += tileSize.Width; | ||
122 | tsx += tx.Width; | ||
123 | } | ||
124 | |||
125 | // create indices | ||
126 | |||
127 | for (x=0; x<tileCount.Width-1; ++x) | ||
128 | { | ||
129 | for (u32 y=0; y<tileCount.Height-1; ++y) | ||
130 | { | ||
131 | const s32 current = x*tileCount.Height + y; | ||
132 | |||
133 | buffer->Indices.push_back(current); | ||
134 | buffer->Indices.push_back(current + 1); | ||
135 | buffer->Indices.push_back(current + tileCount.Height); | ||
136 | |||
137 | buffer->Indices.push_back(current + 1); | ||
138 | buffer->Indices.push_back(current + 1 + tileCount.Height); | ||
139 | buffer->Indices.push_back(current + tileCount.Height); | ||
140 | } | ||
141 | } | ||
142 | |||
143 | // recalculate normals | ||
144 | for (u32 i=0; i<buffer->Indices.size(); i+=3) | ||
145 | { | ||
146 | const core::vector3df normal = core::plane3d<f32>( | ||
147 | buffer->Vertices[buffer->Indices[i+0]].Pos, | ||
148 | buffer->Vertices[buffer->Indices[i+1]].Pos, | ||
149 | buffer->Vertices[buffer->Indices[i+2]].Pos).Normal; | ||
150 | |||
151 | buffer->Vertices[buffer->Indices[i+0]].Normal = normal; | ||
152 | buffer->Vertices[buffer->Indices[i+1]].Normal = normal; | ||
153 | buffer->Vertices[buffer->Indices[i+2]].Normal = normal; | ||
154 | } | ||
155 | |||
156 | if (material) | ||
157 | buffer->Material = *material; | ||
158 | |||
159 | buffer->recalculateBoundingBox(); | ||
160 | buffer->setHardwareMappingHint(EHM_STATIC); | ||
161 | |||
162 | SMesh* mesh = new SMesh(); | ||
163 | mesh->addMeshBuffer(buffer); | ||
164 | mesh->recalculateBoundingBox(); | ||
165 | buffer->drop(); | ||
166 | return mesh; | ||
167 | } | ||
168 | |||
169 | |||
170 | IMesh* CGeometryCreator::createTerrainMesh(video::IImage* texture, | ||
171 | video::IImage* heightmap, const core::dimension2d<f32>& stretchSize, | ||
172 | f32 maxHeight, video::IVideoDriver* driver, | ||
173 | const core::dimension2d<u32>& maxVtxBlockSize, | ||
174 | bool debugBorders) const | ||
175 | { | ||
176 | if (!texture || !heightmap) | ||
177 | return 0; | ||
178 | |||
179 | // debug border | ||
180 | const s32 borderSkip = debugBorders ? 0 : 1; | ||
181 | |||
182 | video::S3DVertex vtx; | ||
183 | vtx.Color.set(255,255,255,255); | ||
184 | |||
185 | SMesh* mesh = new SMesh(); | ||
186 | |||
187 | const u32 tm = os::Timer::getRealTime()/1000; | ||
188 | const core::dimension2d<u32> hMapSize= heightmap->getDimension(); | ||
189 | const core::dimension2d<u32> tMapSize= texture->getDimension(); | ||
190 | const core::position2d<f32> thRel(static_cast<f32>(tMapSize.Width) / hMapSize.Width, static_cast<f32>(tMapSize.Height) / hMapSize.Height); | ||
191 | maxHeight /= 255.0f; // height step per color value | ||
192 | |||
193 | core::position2d<u32> processed(0,0); | ||
194 | while (processed.Y<hMapSize.Height) | ||
195 | { | ||
196 | while(processed.X<hMapSize.Width) | ||
197 | { | ||
198 | core::dimension2d<u32> blockSize = maxVtxBlockSize; | ||
199 | if (processed.X + blockSize.Width > hMapSize.Width) | ||
200 | blockSize.Width = hMapSize.Width - processed.X; | ||
201 | if (processed.Y + blockSize.Height > hMapSize.Height) | ||
202 | blockSize.Height = hMapSize.Height - processed.Y; | ||
203 | |||
204 | SMeshBuffer* buffer = new SMeshBuffer(); | ||
205 | buffer->setHardwareMappingHint(scene::EHM_STATIC); | ||
206 | buffer->Vertices.reallocate(blockSize.getArea()); | ||
207 | // add vertices of vertex block | ||
208 | u32 y; | ||
209 | core::vector2df pos(0.f, processed.Y*stretchSize.Height); | ||
210 | const core::vector2df bs(1.f/blockSize.Width, 1.f/blockSize.Height); | ||
211 | core::vector2df tc(0.f, 0.5f*bs.Y); | ||
212 | for (y=0; y<blockSize.Height; ++y) | ||
213 | { | ||
214 | pos.X=processed.X*stretchSize.Width; | ||
215 | tc.X=0.5f*bs.X; | ||
216 | for (u32 x=0; x<blockSize.Width; ++x) | ||
217 | { | ||
218 | const f32 height = heightmap->getPixel(x+processed.X, y+processed.Y).getAverage() * maxHeight; | ||
219 | |||
220 | vtx.Pos.set(pos.X, height, pos.Y); | ||
221 | vtx.TCoords.set(tc); | ||
222 | buffer->Vertices.push_back(vtx); | ||
223 | pos.X += stretchSize.Width; | ||
224 | tc.X += bs.X; | ||
225 | } | ||
226 | pos.Y += stretchSize.Height; | ||
227 | tc.Y += bs.Y; | ||
228 | } | ||
229 | |||
230 | buffer->Indices.reallocate((blockSize.Height-1)*(blockSize.Width-1)*6); | ||
231 | // add indices of vertex block | ||
232 | s32 c1 = 0; | ||
233 | for (y=0; y<blockSize.Height-1; ++y) | ||
234 | { | ||
235 | for (u32 x=0; x<blockSize.Width-1; ++x) | ||
236 | { | ||
237 | const s32 c = c1 + x; | ||
238 | |||
239 | buffer->Indices.push_back(c); | ||
240 | buffer->Indices.push_back(c + blockSize.Width); | ||
241 | buffer->Indices.push_back(c + 1); | ||
242 | |||
243 | buffer->Indices.push_back(c + 1); | ||
244 | buffer->Indices.push_back(c + blockSize.Width); | ||
245 | buffer->Indices.push_back(c + 1 + blockSize.Width); | ||
246 | } | ||
247 | c1 += blockSize.Width; | ||
248 | } | ||
249 | |||
250 | // recalculate normals | ||
251 | for (u32 i=0; i<buffer->Indices.size(); i+=3) | ||
252 | { | ||
253 | const core::vector3df normal = core::plane3d<f32>( | ||
254 | buffer->Vertices[buffer->Indices[i+0]].Pos, | ||
255 | buffer->Vertices[buffer->Indices[i+1]].Pos, | ||
256 | buffer->Vertices[buffer->Indices[i+2]].Pos).Normal; | ||
257 | |||
258 | buffer->Vertices[buffer->Indices[i+0]].Normal = normal; | ||
259 | buffer->Vertices[buffer->Indices[i+1]].Normal = normal; | ||
260 | buffer->Vertices[buffer->Indices[i+2]].Normal = normal; | ||
261 | } | ||
262 | |||
263 | if (buffer->Vertices.size()) | ||
264 | { | ||
265 | c8 textureName[64]; | ||
266 | // create texture for this block | ||
267 | video::IImage* img = driver->createImage(texture->getColorFormat(), core::dimension2d<u32>(core::floor32(blockSize.Width*thRel.X), core::floor32(blockSize.Height*thRel.Y))); | ||
268 | texture->copyTo(img, core::position2di(0,0), core::recti( | ||
269 | core::position2d<s32>(core::floor32(processed.X*thRel.X), core::floor32(processed.Y*thRel.Y)), | ||
270 | core::dimension2d<u32>(core::floor32(blockSize.Width*thRel.X), core::floor32(blockSize.Height*thRel.Y))), 0); | ||
271 | |||
272 | sprintf(textureName, "terrain%u_%u", tm, mesh->getMeshBufferCount()); | ||
273 | |||
274 | buffer->Material.setTexture(0, driver->addTexture(textureName, img)); | ||
275 | |||
276 | if (buffer->Material.getTexture(0)) | ||
277 | { | ||
278 | c8 tmp[255]; | ||
279 | sprintf(tmp, "Generated terrain texture (%dx%d): %s", | ||
280 | buffer->Material.getTexture(0)->getSize().Width, | ||
281 | buffer->Material.getTexture(0)->getSize().Height, | ||
282 | textureName); | ||
283 | os::Printer::log(tmp); | ||
284 | } | ||
285 | else | ||
286 | os::Printer::log("Could not create terrain texture.", textureName, ELL_ERROR); | ||
287 | |||
288 | img->drop(); | ||
289 | } | ||
290 | |||
291 | buffer->recalculateBoundingBox(); | ||
292 | mesh->addMeshBuffer(buffer); | ||
293 | buffer->drop(); | ||
294 | |||
295 | // keep on processing | ||
296 | processed.X += maxVtxBlockSize.Width - borderSkip; | ||
297 | } | ||
298 | |||
299 | // keep on processing | ||
300 | processed.X = 0; | ||
301 | processed.Y += maxVtxBlockSize.Height - borderSkip; | ||
302 | } | ||
303 | |||
304 | mesh->recalculateBoundingBox(); | ||
305 | return mesh; | ||
306 | } | ||
307 | |||
308 | |||
309 | /* | ||
310 | a cylinder, a cone and a cross | ||
311 | point up on (0,1.f, 0.f ) | ||
312 | */ | ||
313 | IMesh* CGeometryCreator::createArrowMesh(const u32 tesselationCylinder, | ||
314 | const u32 tesselationCone, | ||
315 | const f32 height, | ||
316 | const f32 cylinderHeight, | ||
317 | const f32 width0, | ||
318 | const f32 width1, | ||
319 | const video::SColor vtxColor0, | ||
320 | const video::SColor vtxColor1) const | ||
321 | { | ||
322 | SMesh* mesh = (SMesh*)createCylinderMesh(width0, cylinderHeight, tesselationCylinder, vtxColor0, false); | ||
323 | |||
324 | IMesh* mesh2 = createConeMesh(width1, height-cylinderHeight, tesselationCone, vtxColor1, vtxColor0); | ||
325 | for (u32 i=0; i<mesh2->getMeshBufferCount(); ++i) | ||
326 | { | ||
327 | scene::IMeshBuffer* buffer = mesh2->getMeshBuffer(i); | ||
328 | for (u32 j=0; j<buffer->getVertexCount(); ++j) | ||
329 | buffer->getPosition(j).Y += cylinderHeight; | ||
330 | buffer->setDirty(EBT_VERTEX); | ||
331 | buffer->recalculateBoundingBox(); | ||
332 | mesh->addMeshBuffer(buffer); | ||
333 | } | ||
334 | mesh2->drop(); | ||
335 | mesh->setHardwareMappingHint(EHM_STATIC); | ||
336 | |||
337 | mesh->recalculateBoundingBox(); | ||
338 | return mesh; | ||
339 | } | ||
340 | |||
341 | |||
342 | /* A sphere with proper normals and texture coords */ | ||
343 | IMesh* CGeometryCreator::createSphereMesh(f32 radius, u32 polyCountX, u32 polyCountY) const | ||
344 | { | ||
345 | // thanks to Alfaz93 who made his code available for Irrlicht on which | ||
346 | // this one is based! | ||
347 | |||
348 | // we are creating the sphere mesh here. | ||
349 | |||
350 | if (polyCountX < 2) | ||
351 | polyCountX = 2; | ||
352 | if (polyCountY < 2) | ||
353 | polyCountY = 2; | ||
354 | while (polyCountX * polyCountY > 32767) // prevent u16 overflow | ||
355 | { | ||
356 | polyCountX /= 2; | ||
357 | polyCountY /= 2; | ||
358 | } | ||
359 | |||
360 | const u32 polyCountXPitch = polyCountX+1; // get to same vertex on next level | ||
361 | |||
362 | SMeshBuffer* buffer = new SMeshBuffer(); | ||
363 | |||
364 | buffer->Indices.reallocate((polyCountX * polyCountY) * 6); | ||
365 | |||
366 | const video::SColor clr(255, 255,255,255); | ||
367 | |||
368 | u32 level = 0; | ||
369 | |||
370 | for (u32 p1 = 0; p1 < polyCountY-1; ++p1) | ||
371 | { | ||
372 | //main quads, top to bottom | ||
373 | for (u32 p2 = 0; p2 < polyCountX - 1; ++p2) | ||
374 | { | ||
375 | const u32 curr = level + p2; | ||
376 | buffer->Indices.push_back(curr + polyCountXPitch); | ||
377 | buffer->Indices.push_back(curr); | ||
378 | buffer->Indices.push_back(curr + 1); | ||
379 | buffer->Indices.push_back(curr + polyCountXPitch); | ||
380 | buffer->Indices.push_back(curr+1); | ||
381 | buffer->Indices.push_back(curr + 1 + polyCountXPitch); | ||
382 | } | ||
383 | |||
384 | // the connectors from front to end | ||
385 | buffer->Indices.push_back(level + polyCountX - 1 + polyCountXPitch); | ||
386 | buffer->Indices.push_back(level + polyCountX - 1); | ||
387 | buffer->Indices.push_back(level + polyCountX); | ||
388 | |||
389 | buffer->Indices.push_back(level + polyCountX - 1 + polyCountXPitch); | ||
390 | buffer->Indices.push_back(level + polyCountX); | ||
391 | buffer->Indices.push_back(level + polyCountX + polyCountXPitch); | ||
392 | level += polyCountXPitch; | ||
393 | } | ||
394 | |||
395 | const u32 polyCountSq = polyCountXPitch * polyCountY; // top point | ||
396 | const u32 polyCountSq1 = polyCountSq + 1; // bottom point | ||
397 | const u32 polyCountSqM1 = (polyCountY - 1) * polyCountXPitch; // last row's first vertex | ||
398 | |||
399 | for (u32 p2 = 0; p2 < polyCountX - 1; ++p2) | ||
400 | { | ||
401 | // create triangles which are at the top of the sphere | ||
402 | |||
403 | buffer->Indices.push_back(polyCountSq); | ||
404 | buffer->Indices.push_back(p2 + 1); | ||
405 | buffer->Indices.push_back(p2); | ||
406 | |||
407 | // create triangles which are at the bottom of the sphere | ||
408 | |||
409 | buffer->Indices.push_back(polyCountSqM1 + p2); | ||
410 | buffer->Indices.push_back(polyCountSqM1 + p2 + 1); | ||
411 | buffer->Indices.push_back(polyCountSq1); | ||
412 | } | ||
413 | |||
414 | // create final triangle which is at the top of the sphere | ||
415 | |||
416 | buffer->Indices.push_back(polyCountSq); | ||
417 | buffer->Indices.push_back(polyCountX); | ||
418 | buffer->Indices.push_back(polyCountX-1); | ||
419 | |||
420 | // create final triangle which is at the bottom of the sphere | ||
421 | |||
422 | buffer->Indices.push_back(polyCountSqM1 + polyCountX - 1); | ||
423 | buffer->Indices.push_back(polyCountSqM1); | ||
424 | buffer->Indices.push_back(polyCountSq1); | ||
425 | |||
426 | // calculate the angle which separates all points in a circle | ||
427 | const f64 AngleX = 2 * core::PI / polyCountX; | ||
428 | const f64 AngleY = core::PI / polyCountY; | ||
429 | |||
430 | u32 i=0; | ||
431 | f64 axz; | ||
432 | |||
433 | // we don't start at 0. | ||
434 | |||
435 | f64 ay = 0;//AngleY / 2; | ||
436 | |||
437 | buffer->Vertices.set_used((polyCountXPitch * polyCountY) + 2); | ||
438 | for (u32 y = 0; y < polyCountY; ++y) | ||
439 | { | ||
440 | ay += AngleY; | ||
441 | const f64 sinay = sin(ay); | ||
442 | axz = 0; | ||
443 | |||
444 | // calculate the necessary vertices without the doubled one | ||
445 | for (u32 xz = 0;xz < polyCountX; ++xz) | ||
446 | { | ||
447 | // calculate points position | ||
448 | |||
449 | const core::vector3df pos(static_cast<f32>(radius * cos(axz) * sinay), | ||
450 | static_cast<f32>(radius * cos(ay)), | ||
451 | static_cast<f32>(radius * sin(axz) * sinay)); | ||
452 | // for spheres the normal is the position | ||
453 | core::vector3df normal(pos); | ||
454 | normal.normalize(); | ||
455 | |||
456 | // calculate texture coordinates via sphere mapping | ||
457 | // tu is the same on each level, so only calculate once | ||
458 | f32 tu = 0.5f; | ||
459 | if (y==0) | ||
460 | { | ||
461 | if (normal.Y != -1.0f && normal.Y != 1.0f) | ||
462 | tu = static_cast<f32>(acos(core::clamp(normal.X/sinay, -1.0, 1.0)) * 0.5 *core::RECIPROCAL_PI64); | ||
463 | if (normal.Z < 0.0f) | ||
464 | tu=1-tu; | ||
465 | } | ||
466 | else | ||
467 | tu = buffer->Vertices[i-polyCountXPitch].TCoords.X; | ||
468 | buffer->Vertices[i] = video::S3DVertex(pos.X, pos.Y, pos.Z, | ||
469 | normal.X, normal.Y, normal.Z, | ||
470 | clr, tu, | ||
471 | static_cast<f32>(ay*core::RECIPROCAL_PI64)); | ||
472 | ++i; | ||
473 | axz += AngleX; | ||
474 | } | ||
475 | // This is the doubled vertex on the initial position | ||
476 | buffer->Vertices[i] = video::S3DVertex(buffer->Vertices[i-polyCountX]); | ||
477 | buffer->Vertices[i].TCoords.X=1.0f; | ||
478 | ++i; | ||
479 | } | ||
480 | |||
481 | // the vertex at the top of the sphere | ||
482 | buffer->Vertices[i] = video::S3DVertex(0.0f,radius,0.0f, 0.0f,1.0f,0.0f, clr, 0.5f, 0.0f); | ||
483 | |||
484 | // the vertex at the bottom of the sphere | ||
485 | ++i; | ||
486 | buffer->Vertices[i] = video::S3DVertex(0.0f,-radius,0.0f, 0.0f,-1.0f,0.0f, clr, 0.5f, 1.0f); | ||
487 | |||
488 | // recalculate bounding box | ||
489 | |||
490 | buffer->BoundingBox.reset(buffer->Vertices[i].Pos); | ||
491 | buffer->BoundingBox.addInternalPoint(buffer->Vertices[i-1].Pos); | ||
492 | buffer->BoundingBox.addInternalPoint(radius,0.0f,0.0f); | ||
493 | buffer->BoundingBox.addInternalPoint(-radius,0.0f,0.0f); | ||
494 | buffer->BoundingBox.addInternalPoint(0.0f,0.0f,radius); | ||
495 | buffer->BoundingBox.addInternalPoint(0.0f,0.0f,-radius); | ||
496 | |||
497 | SMesh* mesh = new SMesh(); | ||
498 | mesh->addMeshBuffer(buffer); | ||
499 | buffer->drop(); | ||
500 | |||
501 | mesh->setHardwareMappingHint(EHM_STATIC); | ||
502 | mesh->recalculateBoundingBox(); | ||
503 | return mesh; | ||
504 | } | ||
505 | |||
506 | |||
507 | /* A cylinder with proper normals and texture coords */ | ||
508 | IMesh* CGeometryCreator::createCylinderMesh(f32 radius, f32 length, | ||
509 | u32 tesselation, const video::SColor& color, | ||
510 | bool closeTop, f32 oblique) const | ||
511 | { | ||
512 | SMeshBuffer* buffer = new SMeshBuffer(); | ||
513 | |||
514 | const f32 recTesselation = core::reciprocal((f32)tesselation); | ||
515 | const f32 recTesselationHalf = recTesselation * 0.5f; | ||
516 | const f32 angleStep = (core::PI * 2.f ) * recTesselation; | ||
517 | const f32 angleStepHalf = angleStep*0.5f; | ||
518 | |||
519 | u32 i; | ||
520 | video::S3DVertex v; | ||
521 | v.Color = color; | ||
522 | buffer->Vertices.reallocate(tesselation*4+4+(closeTop?2:1)); | ||
523 | buffer->Indices.reallocate((tesselation*2+1)*(closeTop?12:9)); | ||
524 | f32 tcx = 0.f; | ||
525 | for ( i = 0; i <= tesselation; ++i ) | ||
526 | { | ||
527 | const f32 angle = angleStep * i; | ||
528 | v.Pos.X = radius * cosf(angle); | ||
529 | v.Pos.Y = 0.f; | ||
530 | v.Pos.Z = radius * sinf(angle); | ||
531 | v.Normal = v.Pos; | ||
532 | v.Normal.normalize(); | ||
533 | v.TCoords.X=tcx; | ||
534 | v.TCoords.Y=0.f; | ||
535 | buffer->Vertices.push_back(v); | ||
536 | |||
537 | v.Pos.X += oblique; | ||
538 | v.Pos.Y = length; | ||
539 | v.Normal = v.Pos; | ||
540 | v.Normal.normalize(); | ||
541 | v.TCoords.Y=1.f; | ||
542 | buffer->Vertices.push_back(v); | ||
543 | |||
544 | v.Pos.X = radius * cosf(angle + angleStepHalf); | ||
545 | v.Pos.Y = 0.f; | ||
546 | v.Pos.Z = radius * sinf(angle + angleStepHalf); | ||
547 | v.Normal = v.Pos; | ||
548 | v.Normal.normalize(); | ||
549 | v.TCoords.X=tcx+recTesselationHalf; | ||
550 | v.TCoords.Y=0.f; | ||
551 | buffer->Vertices.push_back(v); | ||
552 | |||
553 | v.Pos.X += oblique; | ||
554 | v.Pos.Y = length; | ||
555 | v.Normal = v.Pos; | ||
556 | v.Normal.normalize(); | ||
557 | v.TCoords.Y=1.f; | ||
558 | buffer->Vertices.push_back(v); | ||
559 | tcx += recTesselation; | ||
560 | } | ||
561 | |||
562 | // indices for the main hull part | ||
563 | const u32 nonWrappedSize = tesselation* 4; | ||
564 | for (i=0; i != nonWrappedSize; i += 2) | ||
565 | { | ||
566 | buffer->Indices.push_back(i + 2); | ||
567 | buffer->Indices.push_back(i + 0); | ||
568 | buffer->Indices.push_back(i + 1); | ||
569 | |||
570 | buffer->Indices.push_back(i + 2); | ||
571 | buffer->Indices.push_back(i + 1); | ||
572 | buffer->Indices.push_back(i + 3); | ||
573 | } | ||
574 | |||
575 | // two closing quads between end and start | ||
576 | buffer->Indices.push_back(0); | ||
577 | buffer->Indices.push_back(i + 0); | ||
578 | buffer->Indices.push_back(i + 1); | ||
579 | |||
580 | buffer->Indices.push_back(0); | ||
581 | buffer->Indices.push_back(i + 1); | ||
582 | buffer->Indices.push_back(1); | ||
583 | |||
584 | // close down | ||
585 | v.Pos.X = 0.f; | ||
586 | v.Pos.Y = 0.f; | ||
587 | v.Pos.Z = 0.f; | ||
588 | v.Normal.X = 0.f; | ||
589 | v.Normal.Y = -1.f; | ||
590 | v.Normal.Z = 0.f; | ||
591 | v.TCoords.X = 1.f; | ||
592 | v.TCoords.Y = 1.f; | ||
593 | buffer->Vertices.push_back(v); | ||
594 | |||
595 | u32 index = buffer->Vertices.size() - 1; | ||
596 | |||
597 | for ( i = 0; i != nonWrappedSize; i += 2 ) | ||
598 | { | ||
599 | buffer->Indices.push_back(index); | ||
600 | buffer->Indices.push_back(i + 0); | ||
601 | buffer->Indices.push_back(i + 2); | ||
602 | } | ||
603 | |||
604 | buffer->Indices.push_back(index); | ||
605 | buffer->Indices.push_back(i + 0); | ||
606 | buffer->Indices.push_back(0); | ||
607 | |||
608 | if (closeTop) | ||
609 | { | ||
610 | // close top | ||
611 | v.Pos.X = oblique; | ||
612 | v.Pos.Y = length; | ||
613 | v.Pos.Z = 0.f; | ||
614 | v.Normal.X = 0.f; | ||
615 | v.Normal.Y = 1.f; | ||
616 | v.Normal.Z = 0.f; | ||
617 | v.TCoords.X = 0.f; | ||
618 | v.TCoords.Y = 0.f; | ||
619 | buffer->Vertices.push_back(v); | ||
620 | |||
621 | index = buffer->Vertices.size() - 1; | ||
622 | |||
623 | for ( i = 0; i != nonWrappedSize; i += 2 ) | ||
624 | { | ||
625 | buffer->Indices.push_back(i + 1); | ||
626 | buffer->Indices.push_back(index); | ||
627 | buffer->Indices.push_back(i + 3); | ||
628 | } | ||
629 | |||
630 | buffer->Indices.push_back(i + 1); | ||
631 | buffer->Indices.push_back(index); | ||
632 | buffer->Indices.push_back(1); | ||
633 | } | ||
634 | |||
635 | buffer->recalculateBoundingBox(); | ||
636 | SMesh* mesh = new SMesh(); | ||
637 | mesh->addMeshBuffer(buffer); | ||
638 | mesh->setHardwareMappingHint(EHM_STATIC); | ||
639 | mesh->recalculateBoundingBox(); | ||
640 | buffer->drop(); | ||
641 | return mesh; | ||
642 | } | ||
643 | |||
644 | |||
645 | /* A cone with proper normals and texture coords */ | ||
646 | IMesh* CGeometryCreator::createConeMesh(f32 radius, f32 length, u32 tesselation, | ||
647 | const video::SColor& colorTop, | ||
648 | const video::SColor& colorBottom, | ||
649 | f32 oblique) const | ||
650 | { | ||
651 | SMeshBuffer* buffer = new SMeshBuffer(); | ||
652 | |||
653 | const f32 angleStep = (core::PI * 2.f ) / tesselation; | ||
654 | const f32 angleStepHalf = angleStep*0.5f; | ||
655 | |||
656 | video::S3DVertex v; | ||
657 | u32 i; | ||
658 | |||
659 | v.Color = colorTop; | ||
660 | for ( i = 0; i != tesselation; ++i ) | ||
661 | { | ||
662 | f32 angle = angleStep * f32(i); | ||
663 | |||
664 | v.Pos.X = radius * cosf(angle); | ||
665 | v.Pos.Y = 0.f; | ||
666 | v.Pos.Z = radius * sinf(angle); | ||
667 | v.Normal = v.Pos; | ||
668 | v.Normal.normalize(); | ||
669 | buffer->Vertices.push_back(v); | ||
670 | |||
671 | angle += angleStepHalf; | ||
672 | v.Pos.X = radius * cosf(angle); | ||
673 | v.Pos.Y = 0.f; | ||
674 | v.Pos.Z = radius * sinf(angle); | ||
675 | v.Normal = v.Pos; | ||
676 | v.Normal.normalize(); | ||
677 | buffer->Vertices.push_back(v); | ||
678 | } | ||
679 | const u32 nonWrappedSize = buffer->Vertices.size() - 1; | ||
680 | |||
681 | // close top | ||
682 | v.Pos.X = oblique; | ||
683 | v.Pos.Y = length; | ||
684 | v.Pos.Z = 0.f; | ||
685 | v.Normal.X = 0.f; | ||
686 | v.Normal.Y = 1.f; | ||
687 | v.Normal.Z = 0.f; | ||
688 | buffer->Vertices.push_back(v); | ||
689 | |||
690 | u32 index = buffer->Vertices.size() - 1; | ||
691 | |||
692 | for ( i = 0; i != nonWrappedSize; i += 1 ) | ||
693 | { | ||
694 | buffer->Indices.push_back(i + 0); | ||
695 | buffer->Indices.push_back(index); | ||
696 | buffer->Indices.push_back(i + 1); | ||
697 | } | ||
698 | |||
699 | buffer->Indices.push_back(i + 0); | ||
700 | buffer->Indices.push_back(index); | ||
701 | buffer->Indices.push_back(0); | ||
702 | |||
703 | // close down | ||
704 | v.Color = colorBottom; | ||
705 | v.Pos.X = 0.f; | ||
706 | v.Pos.Y = 0.f; | ||
707 | v.Pos.Z = 0.f; | ||
708 | v.Normal.X = 0.f; | ||
709 | v.Normal.Y = -1.f; | ||
710 | v.Normal.Z = 0.f; | ||
711 | buffer->Vertices.push_back(v); | ||
712 | |||
713 | index = buffer->Vertices.size() - 1; | ||
714 | |||
715 | for ( i = 0; i != nonWrappedSize; i += 1 ) | ||
716 | { | ||
717 | buffer->Indices.push_back(index); | ||
718 | buffer->Indices.push_back(i + 0); | ||
719 | buffer->Indices.push_back(i + 1); | ||
720 | } | ||
721 | |||
722 | buffer->Indices.push_back(index); | ||
723 | buffer->Indices.push_back(i + 0); | ||
724 | buffer->Indices.push_back(0); | ||
725 | |||
726 | buffer->recalculateBoundingBox(); | ||
727 | SMesh* mesh = new SMesh(); | ||
728 | mesh->addMeshBuffer(buffer); | ||
729 | buffer->drop(); | ||
730 | |||
731 | mesh->setHardwareMappingHint(EHM_STATIC); | ||
732 | mesh->recalculateBoundingBox(); | ||
733 | return mesh; | ||
734 | } | ||
735 | |||
736 | |||
737 | void CGeometryCreator::addToBuffer(const video::S3DVertex& v, SMeshBuffer* Buffer) const | ||
738 | { | ||
739 | const s32 tnidx = Buffer->Vertices.linear_reverse_search(v); | ||
740 | const bool alreadyIn = (tnidx != -1); | ||
741 | u16 nidx = (u16)tnidx; | ||
742 | if (!alreadyIn) | ||
743 | { | ||
744 | nidx = (u16)Buffer->Vertices.size(); | ||
745 | Buffer->Indices.push_back(nidx); | ||
746 | Buffer->Vertices.push_back(v); | ||
747 | } | ||
748 | else | ||
749 | Buffer->Indices.push_back(nidx); | ||
750 | } | ||
751 | |||
752 | |||
753 | IMesh* CGeometryCreator::createVolumeLightMesh( | ||
754 | const u32 subdivideU, const u32 subdivideV, | ||
755 | const video::SColor footColor, const video::SColor tailColor, | ||
756 | const f32 lpDistance, const core::vector3df& lightDim) const | ||
757 | { | ||
758 | SMeshBuffer* Buffer = new SMeshBuffer(); | ||
759 | Buffer->setHardwareMappingHint(EHM_STATIC); | ||
760 | |||
761 | const core::vector3df lightPoint(0, -(lpDistance*lightDim.Y), 0); | ||
762 | const f32 ax = lightDim.X * 0.5f; // X Axis | ||
763 | const f32 az = lightDim.Z * 0.5f; // Z Axis | ||
764 | |||
765 | Buffer->Vertices.clear(); | ||
766 | Buffer->Vertices.reallocate(6+12*(subdivideU+subdivideV)); | ||
767 | Buffer->Indices.clear(); | ||
768 | Buffer->Indices.reallocate(6+12*(subdivideU+subdivideV)); | ||
769 | //draw the bottom foot.. the glowing region | ||
770 | addToBuffer(video::S3DVertex(-ax, 0, az, 0,0,0, footColor, 0, 1),Buffer); | ||
771 | addToBuffer(video::S3DVertex( ax, 0, az, 0,0,0, footColor, 1, 1),Buffer); | ||
772 | addToBuffer(video::S3DVertex( ax, 0,-az, 0,0,0, footColor, 1, 0),Buffer); | ||
773 | |||
774 | addToBuffer(video::S3DVertex( ax, 0,-az, 0,0,0, footColor, 1, 0),Buffer); | ||
775 | addToBuffer(video::S3DVertex(-ax, 0,-az, 0,0,0, footColor, 0, 0),Buffer); | ||
776 | addToBuffer(video::S3DVertex(-ax, 0, az, 0,0,0, footColor, 0, 1),Buffer); | ||
777 | |||
778 | f32 tu = 0.f; | ||
779 | const f32 tuStep = 1.f/subdivideU; | ||
780 | f32 bx = -ax; | ||
781 | const f32 bxStep = lightDim.X * tuStep; | ||
782 | // Slices in X/U space | ||
783 | for (u32 i = 0; i <= subdivideU; ++i) | ||
784 | { | ||
785 | // These are the two endpoints for a slice at the foot | ||
786 | core::vector3df end1(bx, 0.0f, -az); | ||
787 | core::vector3df end2(bx, 0.0f, az); | ||
788 | |||
789 | end1 -= lightPoint; // get a vector from point to lightsource | ||
790 | end1.normalize(); // normalize vector | ||
791 | end1 *= lightDim.Y; // multiply it out by shootlength | ||
792 | |||
793 | end1.X += bx; // Add the original point location to the vector | ||
794 | end1.Z -= az; | ||
795 | |||
796 | // Do it again for the other point. | ||
797 | end2 -= lightPoint; | ||
798 | end2.normalize(); | ||
799 | end2 *= lightDim.Y; | ||
800 | |||
801 | end2.X += bx; | ||
802 | end2.Z += az; | ||
803 | |||
804 | addToBuffer(video::S3DVertex(bx , 0, az, 0,0,0, footColor, tu, 1),Buffer); | ||
805 | addToBuffer(video::S3DVertex(bx , 0, -az, 0,0,0, footColor, tu, 0),Buffer); | ||
806 | addToBuffer(video::S3DVertex(end2.X , end2.Y, end2.Z, 0,0,0, tailColor, tu, 1),Buffer); | ||
807 | |||
808 | addToBuffer(video::S3DVertex(bx , 0, -az, 0,0,0, footColor, tu, 0),Buffer); | ||
809 | addToBuffer(video::S3DVertex(end1.X , end1.Y, end1.Z, 0,0,0, tailColor, tu, 0),Buffer); | ||
810 | addToBuffer(video::S3DVertex(end2.X , end2.Y, end2.Z, 0,0,0, tailColor, tu, 1),Buffer); | ||
811 | |||
812 | //back side | ||
813 | addToBuffer(video::S3DVertex(-end2.X , end2.Y, -end2.Z, 0,0,0, tailColor, tu, 1),Buffer); | ||
814 | addToBuffer(video::S3DVertex(-bx , 0, -az, 0,0,0, footColor, tu, 1),Buffer); | ||
815 | addToBuffer(video::S3DVertex(-bx , 0, az, 0,0,0, footColor, tu, 0),Buffer); | ||
816 | |||
817 | addToBuffer(video::S3DVertex(-bx , 0, az, 0,0,0, footColor, tu, 0),Buffer); | ||
818 | addToBuffer(video::S3DVertex(-end1.X , end1.Y, -end1.Z, 0,0,0, tailColor, tu, 0),Buffer); | ||
819 | addToBuffer(video::S3DVertex(-end2.X , end2.Y, -end2.Z, 0,0,0, tailColor, tu, 1),Buffer); | ||
820 | tu += tuStep; | ||
821 | bx += bxStep; | ||
822 | } | ||
823 | |||
824 | f32 tv = 0.f; | ||
825 | const f32 tvStep = 1.f/subdivideV; | ||
826 | f32 bz = -az; | ||
827 | const f32 bzStep = lightDim.Z * tvStep; | ||
828 | // Slices in Z/V space | ||
829 | for(u32 i = 0; i <= subdivideV; ++i) | ||
830 | { | ||
831 | // These are the two endpoints for a slice at the foot | ||
832 | core::vector3df end1(-ax, 0.0f, bz); | ||
833 | core::vector3df end2(ax, 0.0f, bz); | ||
834 | |||
835 | end1 -= lightPoint; // get a vector from point to lightsource | ||
836 | end1.normalize(); // normalize vector | ||
837 | end1 *= lightDim.Y; // multiply it out by shootlength | ||
838 | |||
839 | end1.X -= ax; // Add the original point location to the vector | ||
840 | end1.Z += bz; | ||
841 | |||
842 | // Do it again for the other point. | ||
843 | end2 -= lightPoint; | ||
844 | end2.normalize(); | ||
845 | end2 *= lightDim.Y; | ||
846 | |||
847 | end2.X += ax; | ||
848 | end2.Z += bz; | ||
849 | |||
850 | addToBuffer(video::S3DVertex(-ax , 0, bz, 0,0,0, footColor, 0, tv),Buffer); | ||
851 | addToBuffer(video::S3DVertex(ax , 0, bz, 0,0,0, footColor, 1, tv),Buffer); | ||
852 | addToBuffer(video::S3DVertex(end2.X , end2.Y, end2.Z, 0,0,0, tailColor, 1, tv),Buffer); | ||
853 | |||
854 | addToBuffer(video::S3DVertex(end2.X , end2.Y, end2.Z, 0,0,0, tailColor, 1, tv),Buffer); | ||
855 | addToBuffer(video::S3DVertex(end1.X , end1.Y, end1.Z, 0,0,0, tailColor, 0, tv),Buffer); | ||
856 | addToBuffer(video::S3DVertex(-ax , 0, bz, 0,0,0, footColor, 0, tv),Buffer); | ||
857 | |||
858 | //back side | ||
859 | addToBuffer(video::S3DVertex(ax , 0, -bz, 0,0,0, footColor, 0, tv),Buffer); | ||
860 | addToBuffer(video::S3DVertex(-ax , 0, -bz, 0,0,0, footColor, 1, tv),Buffer); | ||
861 | addToBuffer(video::S3DVertex(-end2.X , end2.Y, -end2.Z, 0,0,0, tailColor, 1, tv),Buffer); | ||
862 | |||
863 | addToBuffer(video::S3DVertex(-end2.X , end2.Y, -end2.Z, 0,0,0, tailColor, 1, tv),Buffer); | ||
864 | addToBuffer(video::S3DVertex(-end1.X , end1.Y, -end1.Z, 0,0,0, tailColor, 0, tv),Buffer); | ||
865 | addToBuffer(video::S3DVertex(ax , 0, -bz, 0,0,0, footColor, 0, tv),Buffer); | ||
866 | tv += tvStep; | ||
867 | bz += bzStep; | ||
868 | } | ||
869 | |||
870 | Buffer->recalculateBoundingBox(); | ||
871 | |||
872 | Buffer->Material.MaterialType = video::EMT_ONETEXTURE_BLEND; | ||
873 | Buffer->Material.MaterialTypeParam = pack_textureBlendFunc( video::EBF_SRC_COLOR, video::EBF_SRC_ALPHA, video::EMFN_MODULATE_1X ); | ||
874 | |||
875 | Buffer->Material.Lighting = false; | ||
876 | Buffer->Material.ZWriteEnable = false; | ||
877 | |||
878 | Buffer->setDirty(EBT_VERTEX_AND_INDEX); | ||
879 | |||
880 | Buffer->recalculateBoundingBox(); | ||
881 | SMesh* mesh = new SMesh(); | ||
882 | mesh->addMeshBuffer(Buffer); | ||
883 | Buffer->drop(); | ||
884 | |||
885 | mesh->recalculateBoundingBox(); | ||
886 | return mesh; | ||
887 | } | ||
888 | |||
889 | |||
890 | } // end namespace scene | ||
891 | } // end namespace irr | ||
892 | |||