CGeometryCreator.cpp 27 KB

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