diff --git a/changes.txt b/changes.txt index 5d2c49d6..501769de 100644 --- a/changes.txt +++ b/changes.txt @@ -1,5 +1,6 @@ -------------------------- Changes in 1.9 (not yet released) +- Add IGeometryCreator::createTorusMesh to create donuts. - Don't try loading broken image files twice with same loader anymore. - Make CImageLoaderJPG thread safe. Thanks @ Edoardo Lolletti for report and patch (patch #324) - Add ETCF_SUPPORT_VERTEXT_TEXTURE flag which can be used to enable vertex texture sampling support in Direct3D 9. diff --git a/include/IGeometryCreator.h b/include/IGeometryCreator.h index 6083f5b4..277a3b64 100644 --- a/include/IGeometryCreator.h +++ b/include/IGeometryCreator.h @@ -183,6 +183,16 @@ public: const video::SColor& colorBottom=video::SColor(0xffffffff), f32 oblique=0.f) const =0; + //! Create a torus mesh + /** Note: Segments might get reduced to ensure it fits into 16-bit meshbuffer. + With 256 segments for minor and major circle you'll hit the maximum. + \param majorRadius Starting from mesh center + \param minorRadius Starting from a circle at majorRadius distance around center + \param majorSegments Segments for major circle. Will use at least 3. + \param minorSegments Segments for minor circle. Will use at least 3 + */ + virtual IMesh* createTorusMesh(f32 majorRadius, f32 minorRadius, u32 majorSegments = 32, u32 minorSegments = 16) const = 0; + //! Create a volume light mesh. /** \param subdivideU Horizontal patch count. diff --git a/source/Irrlicht/CGeometryCreator.cpp b/source/Irrlicht/CGeometryCreator.cpp index 22ce7170..c9413e77 100644 --- a/source/Irrlicht/CGeometryCreator.cpp +++ b/source/Irrlicht/CGeometryCreator.cpp @@ -378,7 +378,7 @@ IMesh* CGeometryCreator::createTerrainMesh(video::IImage* texture, blockSize.Height = hMapSize.Height - processed.Y; SMeshBuffer* buffer = new SMeshBuffer(); - buffer->setHardwareMappingHint(scene::EHM_STATIC); + buffer->setHardwareMappingHint(EHM_STATIC); buffer->Vertices.reallocate(blockSize.getArea()); // add vertices of vertex block u32 y; @@ -500,7 +500,7 @@ IMesh* CGeometryCreator::createArrowMesh(const u32 tesselationCylinder, IMesh* mesh2 = createConeMesh(width1, height-cylinderHeight, tesselationCone, vtxColor1, vtxColor0); for (u32 i=0; igetMeshBufferCount(); ++i) { - scene::IMeshBuffer* buffer = mesh2->getMeshBuffer(i); + IMeshBuffer* buffer = mesh2->getMeshBuffer(i); for (u32 j=0; jgetVertexCount(); ++j) buffer->getPosition(j).Y += cylinderHeight; buffer->setDirty(EBT_VERTEX); @@ -925,6 +925,101 @@ IMesh* CGeometryCreator::createConeMesh(f32 radius, f32 length, u32 tesselation, return mesh; } +irr::scene::IMesh* CGeometryCreator::createTorusMesh(irr::f32 majorRadius, irr::f32 minorRadius, irr::u32 majorSegments, irr::u32 minorSegments) const +{ + if ( majorRadius == 0.f || minorRadius == 0.f ) + return 0; + + if ( majorSegments < 3 ) + majorSegments = 3; + if ( minorSegments < 3 ) + minorSegments = 3; + + // Note: first/last vertices of major and minor lines are on same position, but not shared to allow for independent uv's. + + // prevent 16-bit vertex buffer overflow + u32 numVertices = (majorSegments+1)*(minorSegments+1); + while (numVertices > 65536) + { + if ( majorSegments > 2*minorSegments ) + majorSegments /= 2; + else if ( minorSegments > 2*majorSegments ) + minorSegments /= 2; + else + { + majorSegments /= 2; + minorSegments /= 2; + } + numVertices = (majorSegments+1)*(minorSegments+1); + } + + const u32 majorLines = majorSegments+1; + const u32 minorLines = minorSegments+1; + + const video::SColor color(255,255,255,255); + SMeshBuffer* buffer = new SMeshBuffer(); + buffer->Indices.reallocate(majorSegments*minorSegments*6); + buffer->Vertices.reallocate(numVertices); + + const f32 TWO_PI = 2.f*core::PI; + const f32 angleStepMajor = TWO_PI / majorSegments; + const f32 angleStepMinor = TWO_PI / minorSegments; + + // vertices + for ( irr::u32 major = 0; major < majorLines; ++major) + { + const f32 angleMajor = major*angleStepMajor; + const f32 cosMajor = cos(angleMajor); + const f32 sinMajor = sin(angleMajor); + + // points of major circle + const core::vector3df pm(majorRadius*cosMajor, 0.f, majorRadius * sinMajor); + + for ( irr::u32 minor = 0; minor < minorLines; ++minor) + { + const f32 angleMinor = minor*angleStepMinor; + const f32 cosMinor = cos(angleMinor); + + core::vector3df p; + p.X = pm.X + minorRadius * cosMinor * cosMajor; + p.Z = pm.Z + minorRadius * cosMinor * sinMajor; + p.Y = minorRadius * sin(angleMinor); + const core::vector3df n((p-pm)/minorRadius); + const core::vector2df uv(angleMajor/TWO_PI, angleMinor/TWO_PI); + buffer->Vertices.push_back( video::S3DVertex(p, n, color, uv) ); + } + } + + // indices + for ( irr::u32 major = 0; major < majorSegments; ++major) + { + for ( irr::u32 minor = 0; minor < minorSegments; ++minor) + { + irr::u16 i = major*minorLines+minor; + buffer->Indices.push_back(i+1); + buffer->Indices.push_back(i+minorLines); + buffer->Indices.push_back(i); + + buffer->Indices.push_back(i+1); + buffer->Indices.push_back(i+minorLines+1); + buffer->Indices.push_back(i+minorLines); + } + } + + // recalculate bounding box + buffer->BoundingBox.MaxEdge.X = core::abs_(majorRadius)+core::abs_(minorRadius); + buffer->BoundingBox.MaxEdge.Z = buffer->BoundingBox.MaxEdge.X; + buffer->BoundingBox.MaxEdge.Y = core::abs_(minorRadius); + buffer->BoundingBox.MinEdge = buffer->BoundingBox.MaxEdge*-1.f; + + SMesh* mesh = new SMesh(); + mesh->addMeshBuffer(buffer); + buffer->drop(); + + mesh->setHardwareMappingHint(EHM_STATIC); + mesh->recalculateBoundingBox(); + return mesh; +} void CGeometryCreator::addToBuffer(const video::S3DVertex& v, SMeshBuffer* Buffer) const { diff --git a/source/Irrlicht/CGeometryCreator.h b/source/Irrlicht/CGeometryCreator.h index 4c918bdc..ddf213de 100644 --- a/source/Irrlicht/CGeometryCreator.h +++ b/source/Irrlicht/CGeometryCreator.h @@ -51,6 +51,9 @@ public: const video::SColor& colorBottom=0xffffffff, f32 oblique=0.f) const _IRR_OVERRIDE_; + virtual IMesh* createTorusMesh(f32 majorRadius, f32 minorRadius, + u32 majorSegments, u32 minorSegments) const _IRR_OVERRIDE_; + virtual IMesh* createVolumeLightMesh( const u32 subdivideU=32, const u32 subdivideV=32, const video::SColor footColor=0xffffffff,