From 6b2a0fab782d06e5be4578ffa18b1f297de52873 Mon Sep 17 00:00:00 2001 From: cutealien Date: Sun, 31 Dec 2023 18:04:15 +0000 Subject: [PATCH] Fix tessellation numbers in createCylinderMesh, createConeMesh, createArrowMesh Double tessellation numbers for these 3 functions in your code to get same results as in Irrlicht 1.8 I noticed in last commit those all tessellated semi-circles instead of circles. I just documented it there, but it's annoying as that bug doesn't allow odd numbered tessellation. So for example one couldn't create a triangle pyramid. I considered adding another parameter to describe what this number means, but... just too ugly. And it was always documented otherwise, so this could be considered a bug. Sorry if this changes the look of existing apps. Also cleaned up code in CGeometryCreator::createCylinderMesh. No idea what the idea behind old code was. Aside from creating twice the tessellation numbers. git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@6581 dfc29bdd-3216-0410-991c-e03cc46cb475 --- changes.txt | 3 + include/IGeometryCreator.h | 12 ++-- source/Irrlicht/CGeometryCreator.cpp | 57 ++---------------- .../Burning's Video-testGeometryCreator.png | Bin 8828 -> 9224 bytes tests/tests-last-passed-at.txt | 2 +- 5 files changed, 16 insertions(+), 58 deletions(-) diff --git a/changes.txt b/changes.txt index 0000a6de..d851b6af 100644 --- a/changes.txt +++ b/changes.txt @@ -1,6 +1,9 @@ -------------------------- Changes in 1.9 (not yet released) +- createCylinderMesh and createConeMesh in GeometryCreator tessellation numbers now for full instead of semi-circle. + Double your tessellation numbers to get same results as in 1.8 + Sorry had to break as old solution didn't allow for odd numbers. Also was documented otherwise, so was a bug. - Change in UV's for top/bottom center vertex in CGeometryCreator::createCylinderMesh - Add some default UV's in CGeometryCreator::createConeMesh - Bugfix: CTriangleSelector::getTriangles with bounding-box parameter no longer ignores an additionally passed matrix transformation in the box check diff --git a/include/IGeometryCreator.h b/include/IGeometryCreator.h index 5e411432..aa2e1c2f 100644 --- a/include/IGeometryCreator.h +++ b/include/IGeometryCreator.h @@ -135,8 +135,8 @@ public: //! Create an arrow mesh, composed of a cylinder and a cone. /** - \param tessellationCylinder Number of quads composing half the cylinder. - \param tessellationCone Number of triangles composing half the cone's roof. + \param tessellationCylinder Number of quads composing the cylinder. + \param tessellationCone Number of triangles composing the cone's roof. \param height Total height of the arrow \param cylinderHeight Total height of the cylinder, should be lesser than total height @@ -147,8 +147,8 @@ public: \param colorCone color of the cone \return Generated mesh. */ - virtual IMesh* createArrowMesh(const u32 tessellationCylinder = 4, - const u32 tessellationCone = 8, const f32 height = 1.f, + virtual IMesh* createArrowMesh(const u32 tessellationCylinder = 16, + const u32 tessellationCone = 16, const f32 height = 1.f, const f32 cylinderHeight = 0.6f, const f32 widthCylinder = 0.05f, const f32 widthCone = 0.3f, const video::SColor colorCylinder = 0xFFFFFFFF, const video::SColor colorCone = 0xFFFFFFFF) const =0; @@ -168,7 +168,7 @@ public: /** \param radius Radius of the cylinder. \param length Length of the cylinder. - \param tessellation Number of quads around half the circumference of the cylinder. + \param tessellation Number of quads around the circumference of the cylinder. \param color The color of the cylinder. \param closeTop If true, close the ends of the cylinder, otherwise leave them open. \param oblique X-offset (shear) of top compared to bottom. @@ -191,7 +191,7 @@ public: /** \param radius Radius of the cone. \param length Length of the cone. - \param tessellation Number of triangles around half the circumference of the cone. + \param tessellation Number of triangles around the circumference of the cone. \param colorTop The color of the top of the cone. \param colorBottom The color of the bottom of the cone. \param oblique (to be documented) diff --git a/source/Irrlicht/CGeometryCreator.cpp b/source/Irrlicht/CGeometryCreator.cpp index 8aa12ba9..eb6e772d 100644 --- a/source/Irrlicht/CGeometryCreator.cpp +++ b/source/Irrlicht/CGeometryCreator.cpp @@ -748,16 +748,17 @@ IMesh* CGeometryCreator::createCylinderMesh(f32 radius, f32 length, { SMeshBuffer* buffer = new SMeshBuffer(); + if ( tessellation < 2 ) + tessellation = 2; + const f32 recTessellation = core::reciprocal((f32)tessellation); - const f32 recTessellationHalf = recTessellation * 0.5f; const f32 angleStep = (core::PI * 2.f ) * recTessellation; - const f32 angleStepHalf = angleStep*0.5f; u32 i; video::S3DVertex v; v.Color = color; - buffer->Vertices.reallocate(tessellation*4+4+(closeTop?2:1)); - buffer->Indices.reallocate((tessellation*2+1)*(closeTop?12:9)); + buffer->Vertices.reallocate(tessellation*2+2+(closeTop?2:1)); + buffer->Indices.reallocate(tessellation*(closeTop?12:9)); f32 tcx = 0.f; for ( i = 0; i <= tessellation; ++i ) { @@ -775,30 +776,6 @@ IMesh* CGeometryCreator::createCylinderMesh(f32 radius, f32 length, v.TCoords.Y=0.f; buffer->Vertices.push_back(v); - v.Pos.X += oblique; - v.Pos.Y = length; - switch (normalType) - { - case 0: v.Normal = v.Pos; break; - case 1: v.Normal = core::vector3df(v.Pos.X-oblique, 0, v.Pos.Z); break; - } - v.Normal.normalize(); - v.TCoords.Y=1.f; - buffer->Vertices.push_back(v); - - v.Pos.X = radius * cosf(angle + angleStepHalf); - v.Pos.Y = 0.f; - v.Pos.Z = radius * sinf(angle + angleStepHalf); - switch (normalType) - { - case 0: v.Normal = v.Pos; break; - case 1: v.Normal = v.Pos; break; - } - v.Normal.normalize(); - v.TCoords.X=tcx+recTessellationHalf; - v.TCoords.Y=0.f; - buffer->Vertices.push_back(v); - v.Pos.X += oblique; v.Pos.Y = length; switch (normalType) @@ -812,8 +789,7 @@ IMesh* CGeometryCreator::createCylinderMesh(f32 radius, f32 length, tcx += recTessellation; } - // indices for the main hull part - const u32 nonWrappedSize = tessellation* 4; + const u32 nonWrappedSize = tessellation*2; for (i=0; i != nonWrappedSize; i += 2) { buffer->Indices.push_back(i + 2); @@ -825,15 +801,6 @@ IMesh* CGeometryCreator::createCylinderMesh(f32 radius, f32 length, buffer->Indices.push_back(i + 3); } - // two closing quads between end and start - buffer->Indices.push_back(0); - buffer->Indices.push_back(i + 0); - buffer->Indices.push_back(i + 1); - - buffer->Indices.push_back(0); - buffer->Indices.push_back(i + 1); - buffer->Indices.push_back(1); - // close down v.Pos.X = 0.f; v.Pos.Y = 0.f; @@ -854,10 +821,6 @@ IMesh* CGeometryCreator::createCylinderMesh(f32 radius, f32 length, buffer->Indices.push_back(i + 2); } - buffer->Indices.push_back(index); - buffer->Indices.push_back(i + 0); - buffer->Indices.push_back(0); - if (closeTop) { // close top @@ -879,10 +842,6 @@ IMesh* CGeometryCreator::createCylinderMesh(f32 radius, f32 length, buffer->Indices.push_back(index); buffer->Indices.push_back(i + 3); } - - buffer->Indices.push_back(i + 1); - buffer->Indices.push_back(index); - buffer->Indices.push_back(1); } buffer->recalculateBoundingBox(); @@ -903,10 +862,6 @@ IMesh* CGeometryCreator::createConeMesh(f32 radius, f32 length, u32 tessellation { SMeshBuffer* buffer = new SMeshBuffer(); - // TODO: For backward compatibility tessellation is per semi-circle - // We probably need another parameter to allow odd numbered tesselation without breaking existing code :-( - if ( tessellation > 0 ) - tessellation = 2*tessellation; if ( tessellation < 2 ) tessellation = 2; diff --git a/tests/media/Burning's Video-testGeometryCreator.png b/tests/media/Burning's Video-testGeometryCreator.png index 998663770e95148f442074a87054282b887c22a4..c1f3a3396a4e5b370bebbc70c2a73a845f127e42 100644 GIT binary patch literal 9224 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 EKONcOs{jB1 literal 8828 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