diff --git a/include/IGeometryCreator.h b/include/IGeometryCreator.h index 9f31b261..6b711fea 100644 --- a/include/IGeometryCreator.h +++ b/include/IGeometryCreator.h @@ -186,12 +186,22 @@ public: //! Create a torus mesh /** Note: Segments might get reduced to ensure it fits into 16-bit meshbuffer. With 255 segments for minor and major circle you'll hit the maximum. + When using caps 2 more vertices are added. + Note: UV's for caps are probably not useful \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 segments. \param minorSegments Segments for minor circle. Will use at least 3 segments. + \param angleStart Start major circle between 0 and 360° and < angleEnd + \param angleEnd End major circle between 0 and 360° and > angleStart + \param capEnds When you don't create a full major circle you might want caps + 0 = no caps (default) + Bit 1: add cap at angleStart + Bit 2: add cap at angleEnd */ - virtual IMesh* createTorusMesh(f32 majorRadius, f32 minorRadius, u32 majorSegments = 32, u32 minorSegments = 16) const = 0; + virtual IMesh* createTorusMesh(f32 majorRadius, f32 minorRadius, + u32 majorSegments = 32, u32 minorSegments = 16, + f32 angleStart=0.f, f32 angleEnd=360.f, int capEnds=0) const = 0; //! Create a volume light mesh. /** diff --git a/source/Irrlicht/CGeometryCreator.cpp b/source/Irrlicht/CGeometryCreator.cpp index 68d65c40..235163d1 100644 --- a/source/Irrlicht/CGeometryCreator.cpp +++ b/source/Irrlicht/CGeometryCreator.cpp @@ -925,7 +925,7 @@ 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 +irr::scene::IMesh* CGeometryCreator::createTorusMesh(irr::f32 majorRadius, irr::f32 minorRadius, irr::u32 majorSegments, irr::u32 minorSegments, f32 angleStart, f32 angleEnd, int capEnds) const { if ( majorRadius == 0.f || minorRadius == 0.f ) return 0; @@ -938,7 +938,8 @@ irr::scene::IMesh* CGeometryCreator::createTorusMesh(irr::f32 majorRadius, irr:: // 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); + const u32 numCapVertices = (capEnds & 1 ? 1 : 0) + (capEnds & 2 ? 1 : 0); + u32 numVertices = (majorSegments+1)*(minorSegments+1)+numCapVertices; while (numVertices > 65536) { if ( majorSegments > 2*minorSegments ) @@ -950,7 +951,7 @@ irr::scene::IMesh* CGeometryCreator::createTorusMesh(irr::f32 majorRadius, irr:: majorSegments /= 2; minorSegments /= 2; } - numVertices = (majorSegments+1)*(minorSegments+1); + numVertices = (majorSegments+1)*(minorSegments+1)+numCapVertices; } const u32 majorLines = majorSegments+1; @@ -961,27 +962,32 @@ irr::scene::IMesh* CGeometryCreator::createTorusMesh(irr::f32 majorRadius, irr:: buffer->Indices.reallocate(majorSegments*minorSegments*6); buffer->Vertices.reallocate(numVertices); + if ( angleStart > angleEnd ) + core::swap(angleStart, angleEnd); + const f32 radStart = angleStart * core::DEGTORAD; + const f32 radEnd = angleEnd * core::DEGTORAD; + const f32 radMajor = radEnd-radStart; + const f32 radStepMajor = radMajor / majorSegments; const f32 TWO_PI = 2.f*core::PI; - const f32 angleStepMajor = TWO_PI / majorSegments; - const f32 angleStepMinor = TWO_PI / minorSegments; + const f32 radStepMinor = TWO_PI / minorSegments; // vertices for ( irr::u32 major = 0; major < majorLines; ++major) { - const f32 angleMajor = major*angleStepMajor; - const f32 cosMajor = cosf(angleMajor); - const f32 sinMajor = sinf(angleMajor); + const f32 radMajor = radStart + major*radStepMajor; + const f32 cosMajor = cosf(radMajor); + const f32 sinMajor = sinf(radMajor); // points of major circle - const core::vector3df pm(majorRadius*cosMajor, 0.f, majorRadius * sinMajor); + 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 = cosf(angleMinor); + const f32 radMinor = minor*radStepMinor; + const f32 cosMinor = cosf(radMinor); - const core::vector3df n(cosMinor * cosMajor, sinf(angleMinor), cosMinor * sinMajor); - const core::vector2df uv(angleMajor/TWO_PI, angleMinor/TWO_PI); + const core::vector3df n(cosMinor * cosMajor, sinf(radMinor), cosMinor * sinMajor); + const core::vector2df uv(radMajor/TWO_PI, radMinor/TWO_PI); buffer->Vertices.push_back( video::S3DVertex(pm+n*minorRadius, n, color, uv) ); } } @@ -991,7 +997,7 @@ irr::scene::IMesh* CGeometryCreator::createTorusMesh(irr::f32 majorRadius, irr:: { for ( irr::u32 minor = 0; minor < minorSegments; ++minor) { - irr::u16 i = major*minorLines+minor; + const irr::u16 i = major*minorLines+minor; buffer->Indices.push_back(i+1); buffer->Indices.push_back(i+minorLines); buffer->Indices.push_back(i); @@ -1002,6 +1008,41 @@ irr::scene::IMesh* CGeometryCreator::createTorusMesh(irr::f32 majorRadius, irr:: } } + // add start caps + if ( capEnds & 1 ) + { + const core::vector3df p(cosf(radStart), 0.f, sinf(radStart)); + const core::vector3df n( p.crossProduct(core::vector3df(0,-1,0)) ); + const core::vector2df uv(radStart/TWO_PI, 0.5f); + buffer->Vertices.push_back( video::S3DVertex(p*majorRadius, n, color, uv) ); + + const irr::u16 i=buffer->Vertices.size()-1; + for ( irr::u32 minor = 0; minor < minorSegments; ++minor) + { + buffer->Indices.push_back(minor+1); + buffer->Indices.push_back(minor); + buffer->Indices.push_back(i); + } + } + + // add end caps + if ( capEnds & 2 ) + { + const core::vector3df p(cosf(radEnd), 0.f, sinf(radEnd)); + const core::vector3df n( p.crossProduct(core::vector3df(0,1,0)) ); + const core::vector2df uv(radEnd/TWO_PI, 0.5f); + buffer->Vertices.push_back( video::S3DVertex(p*majorRadius, n, color, uv) ); + + const irr::u16 i=buffer->Vertices.size()-1; + const irr::u16 k=i-numCapVertices; + for ( irr::u32 minor = 0; minor < minorSegments; ++minor) + { + buffer->Indices.push_back(k-minor-1); + buffer->Indices.push_back(k-minor); + buffer->Indices.push_back(i); + } + } + // recalculate bounding box buffer->BoundingBox.MaxEdge.X = core::abs_(majorRadius)+core::abs_(minorRadius); buffer->BoundingBox.MaxEdge.Z = buffer->BoundingBox.MaxEdge.X; diff --git a/source/Irrlicht/CGeometryCreator.h b/source/Irrlicht/CGeometryCreator.h index ddf213de..e2214a67 100644 --- a/source/Irrlicht/CGeometryCreator.h +++ b/source/Irrlicht/CGeometryCreator.h @@ -52,7 +52,8 @@ public: f32 oblique=0.f) const _IRR_OVERRIDE_; virtual IMesh* createTorusMesh(f32 majorRadius, f32 minorRadius, - u32 majorSegments, u32 minorSegments) const _IRR_OVERRIDE_; + u32 majorSegments, u32 minorSegments, + f32 angleStart, f32 angleEnd, int capEnds) const _IRR_OVERRIDE_; virtual IMesh* createVolumeLightMesh( const u32 subdivideU=32, const u32 subdivideV=32,