diff --git a/src/Primitives/Capsule.cpp b/src/Primitives/Capsule.cpp index ccf2d2a9f..30b5f5def 100644 --- a/src/Primitives/Capsule.cpp +++ b/src/Primitives/Capsule.cpp @@ -19,28 +19,31 @@ using namespace std; namespace Magnum { namespace Primitives { -Capsule::Capsule(unsigned int rings, unsigned int segments, GLfloat length, TextureCoords textureCoords): MeshData("", Mesh::Primitive::Triangles, new vector, {new vector()}, {new vector()}, textureCoords == TextureCoords::Generate ? vector*>{new vector()} : vector*>()), segments(segments), textureCoords(textureCoords) { - CORRADE_ASSERT(rings >= 1 && segments >= 3, "Capsule must have at least one ring and three segments", ); +Capsule::Capsule(unsigned int hemisphereRings, unsigned int cylinderRings, unsigned int segments, GLfloat length, TextureCoords textureCoords): MeshData("", Mesh::Primitive::Triangles, new vector, {new vector()}, {new vector()}, textureCoords == TextureCoords::Generate ? vector*>{new vector()} : vector*>()), segments(segments), textureCoords(textureCoords) { + CORRADE_ASSERT(hemisphereRings >= 1 && cylinderRings >= 1 && segments >= 3, "Capsule must have at least one hemisphere ring, one cylinder ring and three segments", ); GLfloat height = 2.0f+length; - GLfloat textureCoordsVIncrement = 1.0f/(rings*height); - GLfloat ringAngleIncrement = Math::Constants::pi()/(2*rings); + GLfloat hemisphereTextureCoordsVIncrement = 1.0f/(hemisphereRings*height); + GLfloat hemisphereRingAngleIncrement = Math::Constants::pi()/(2*hemisphereRings); /* Bottom cap vertex */ capVertex(-height/2, -1.0f, 0.0f); /* Rings of bottom hemisphere */ - vertexRings(rings, -length/2, -Math::Constants::pi()/2+ringAngleIncrement, ringAngleIncrement, textureCoordsVIncrement, textureCoordsVIncrement); + hemisphereVertexRings(hemisphereRings-1, -length/2, -Math::Constants::pi()/2+hemisphereRingAngleIncrement, hemisphereRingAngleIncrement, hemisphereTextureCoordsVIncrement, hemisphereTextureCoordsVIncrement); + + /* Rings of cylinder */ + cylinderVertexRings(cylinderRings+1, -length/2, length/cylinderRings, 1.0f/height, length/(cylinderRings*height)); /* Rings of top hemisphere */ - vertexRings(rings, length/2, 0.0f, ringAngleIncrement, (1.0f + length)/height, textureCoordsVIncrement); + hemisphereVertexRings(hemisphereRings-1, length/2, hemisphereRingAngleIncrement, hemisphereRingAngleIncrement, (1.0f + length)/height+hemisphereTextureCoordsVIncrement, hemisphereTextureCoordsVIncrement); /* Top cap vertex */ capVertex(height/2, 1.0f, 1.0f); /* Faces */ bottomFaceRing(); - faceRings(rings*2-1); + faceRings(hemisphereRings*2-2+cylinderRings); topFaceRing(); } @@ -52,7 +55,7 @@ void Capsule::capVertex(GLfloat y, GLfloat normalY, GLfloat textureCoordsV) { textureCoords2D(0)->push_back({0.5, textureCoordsV}); } -void Capsule::vertexRings(unsigned int count, GLfloat centerY, GLfloat startRingAngle, GLfloat ringAngleIncrement, GLfloat startTextureCoordsV, GLfloat textureCoordsVIncrement) { +void Capsule::hemisphereVertexRings(unsigned int count, GLfloat centerY, GLfloat startRingAngle, GLfloat ringAngleIncrement, GLfloat startTextureCoordsV, GLfloat textureCoordsVIncrement) { GLfloat segmentAngleIncrement = 2*Math::Constants::pi()/segments; GLfloat x, y, z; for(unsigned int i = 0; i != count; ++i) { @@ -78,6 +81,29 @@ void Capsule::vertexRings(unsigned int count, GLfloat centerY, GLfloat startRing } } +void Capsule::cylinderVertexRings(unsigned int count, GLfloat startY, GLfloat yIncrement, GLfloat startTextureCoordsV, GLfloat textureCoordsVIncrement) { + GLfloat segmentAngleIncrement = 2*Math::Constants::pi()/segments; + for(unsigned int i = 0; i != count; ++i) { + for(unsigned int j = 0; j != segments; ++j) { + GLfloat segmentAngle = j*segmentAngleIncrement; + positions(0)->push_back({sin(segmentAngle), startY, cos(segmentAngle)}); + normals(0)->push_back({sin(segmentAngle), 0.0f, cos(segmentAngle)}); + + if(textureCoords == TextureCoords::Generate) + textureCoords2D(0)->push_back({j*1.0f/segments, startTextureCoordsV + i*textureCoordsVIncrement}); + } + + /* Duplicate first segment in the ring for additional vertex for texture coordinate */ + if(textureCoords == TextureCoords::Generate) { + positions(0)->push_back((*positions(0))[positions(0)->size()-segments]); + normals(0)->push_back((*normals(0))[normals(0)->size()-segments]); + textureCoords2D(0)->push_back({1.0f, startTextureCoordsV + i*textureCoordsVIncrement}); + } + + startY += yIncrement; + } +} + void Capsule::bottomFaceRing() { for(unsigned int j = 0; j != segments; ++j) { /* Bottom vertex */ diff --git a/src/Primitives/Capsule.h b/src/Primitives/Capsule.h index 3923beba1..f487a9ae5 100644 --- a/src/Primitives/Capsule.h +++ b/src/Primitives/Capsule.h @@ -40,8 +40,10 @@ class Capsule: public Trade::MeshData { /** * @brief Constructor - * @param rings Number of (face) rings for each hemisphere. + * @param hemisphereRings Number of (face) rings for each hemisphere. * Must be larger or equal to 1. + * @param cylinderRings Number of (face) rings for cylinder. Must be + * larger or equal to 1. * @param segments Number of (face) segments. Must be larger or equal to 3. * @param length Length of the capsule, excluding hemispheres. * @param textureCoords Whether to generate texture coordinates. @@ -49,13 +51,14 @@ class Capsule: public Trade::MeshData { * If texture coordinates are generated, vertices of one segment are * duplicated for texture wrapping. */ - Capsule(unsigned int rings, unsigned int segments, GLfloat length, TextureCoords textureCoords = TextureCoords::DontGenerate); + Capsule(unsigned int hemisphereRings, unsigned int cylinderRings, unsigned int segments, GLfloat length, TextureCoords textureCoords = TextureCoords::DontGenerate); private: inline Capsule(unsigned int segments, TextureCoords textureCoords): MeshData("", Mesh::Primitive::Triangles, new std::vector, {new std::vector()}, {new std::vector()}, textureCoords == TextureCoords::Generate ? std::vector*>{new std::vector()} : std::vector*>()), segments(segments), textureCoords(textureCoords) {} void capVertex(GLfloat y, GLfloat normalY, GLfloat textureCoordsV); - void vertexRings(unsigned int count, GLfloat centerY, GLfloat startRingAngle, GLfloat ringAngleIncrement, GLfloat startTextureCoordsV, GLfloat textureCoordsVIncrement); + void hemisphereVertexRings(unsigned int count, GLfloat centerY, GLfloat startRingAngle, GLfloat ringAngleIncrement, GLfloat startTextureCoordsV, GLfloat textureCoordsVIncrement); + void cylinderVertexRings(unsigned int count, GLfloat startY, GLfloat yIncrement, GLfloat startTextureCoordsV, GLfloat textureCoordsVIncrement); void bottomFaceRing(); void faceRings(unsigned int count); void topFaceRing(); diff --git a/src/Primitives/Test/CapsuleTest.cpp b/src/Primitives/Test/CapsuleTest.cpp index 4e23ce175..d0b743714 100644 --- a/src/Primitives/Test/CapsuleTest.cpp +++ b/src/Primitives/Test/CapsuleTest.cpp @@ -35,7 +35,7 @@ CapsuleTest::CapsuleTest() { } void CapsuleTest::withoutTextureCoords() { - Capsule capsule(2, 3, 1.0f); + Capsule capsule(2, 2, 3, 1.0f); CORRADE_COMPARE_AS(*capsule.positions(0), (vector{ Vector4(0.0f, -1.5f, 0.0f), @@ -48,6 +48,10 @@ void CapsuleTest::withoutTextureCoords() { Vector4(0.866025f, -0.5f, -0.5f), Vector4(-0.866025f, -0.5f, -0.5f), + Vector4(0.0f, 0.0f, 1.0f), + Vector4(0.866025f, 0.0f, -0.5f), + Vector4(-0.866025f, 0.0f, -0.5f), + Vector4(0.0f, 0.5f, 1.0f), Vector4(0.866025f, 0.5f, -0.5f), Vector4(-0.866025f, 0.5f, -0.5f), @@ -74,6 +78,10 @@ void CapsuleTest::withoutTextureCoords() { Vector3(0.866025f, 0.0f, -0.5f), Vector3(-0.866025f, 0.0f, -0.5f), + Vector3(0.0f, 0.0f, 1.0f), + Vector3(0.866025f, 0.0f, -0.5f), + Vector3(-0.866025f, 0.0f, -0.5f), + Vector3(0.0f, 0.707107f, 0.707107f), Vector3(0.612372f, 0.707107f, -0.353553f), Vector3(-0.612372f, 0.707107f, -0.353553f), @@ -86,12 +94,13 @@ void CapsuleTest::withoutTextureCoords() { 1, 2, 5, 1, 5, 4, 2, 3, 6, 2, 6, 5, 3, 1, 4, 3, 4, 6, 4, 5, 8, 4, 8, 7, 5, 6, 9, 5, 9, 8, 6, 4, 7, 6, 7, 9, 7, 8, 11, 7, 11, 10, 8, 9, 12, 8, 12, 11, 9, 7, 10, 9, 10, 12, - 10, 11, 13, 11, 12, 13, 12, 10, 13 + 10, 11, 14, 10, 14, 13, 11, 12, 15, 11, 15, 14, 12, 10, 13, 12, 13, 15, + 13, 14, 16, 14, 15, 16, 15, 13, 16 }), Container); } void CapsuleTest::withTextureCoords() { - Capsule capsule(2, 3, 1.0f, Capsule::TextureCoords::Generate); + Capsule capsule(2, 2, 3, 1.0f, Capsule::TextureCoords::Generate); CORRADE_COMPARE_AS(*capsule.positions(0), (vector{ Vector4(0.0f, -1.5f, 0.0f), @@ -106,6 +115,11 @@ void CapsuleTest::withTextureCoords() { Vector4(-0.866025f, -0.5f, -0.5f), Vector4(0.0f, -0.5f, 1.0f), + Vector4(0.0f, 0.0f, 1.0f), + Vector4(0.866025f, 0.0f, -0.5f), + Vector4(-0.866025f, 0.0f, -0.5f), + Vector4(0.0f, 0.0f, 1.0f), + Vector4(0.0f, 0.5f, 1.0f), Vector4(0.866025f, 0.5f, -0.5f), Vector4(-0.866025f, 0.5f, -0.5f), @@ -132,6 +146,11 @@ void CapsuleTest::withTextureCoords() { Vector2(0.666667f, 0.333333f), Vector2(1.0f, 0.333333f), + Vector2(0.0f, 0.5f), + Vector2(0.333333f, 0.5f), + Vector2(0.666667f, 0.5f), + Vector2(1.0f, 0.5f), + Vector2(0.0f, 0.666667f), Vector2(0.333333f, 0.666667f), Vector2(0.666667f, 0.666667f), @@ -150,7 +169,8 @@ void CapsuleTest::withTextureCoords() { 1, 2, 6, 1, 6, 5, 2, 3, 7, 2, 7, 6, 3, 4, 8, 3, 8, 7, 5, 6, 10, 5, 10, 9, 6, 7, 11, 6, 11, 10, 7, 8, 12, 7, 12, 11, 9, 10, 14, 9, 14, 13, 10, 11, 15, 10, 15, 14, 11, 12, 16, 11, 16, 15, - 13, 14, 17, 14, 15, 17, 15, 16, 17 + 13, 14, 18, 13, 18, 17, 14, 15, 19, 14, 19, 18, 15, 16, 20, 15, 20, 19, + 17, 18, 21, 18, 19, 21, 19, 20, 21 }), Container); } diff --git a/src/Primitives/UVSphere.cpp b/src/Primitives/UVSphere.cpp index 825a5ee26..724242a03 100644 --- a/src/Primitives/UVSphere.cpp +++ b/src/Primitives/UVSphere.cpp @@ -29,7 +29,7 @@ UVSphere::UVSphere(unsigned int rings, unsigned int segments, TextureCoords text capVertex(-1.0f, -1.0f, 0.0f); /* Vertex rings */ - vertexRings(rings-1, 0.0f, -Math::Constants::pi()/2+ringAngleIncrement, ringAngleIncrement, textureCoordsVIncrement, textureCoordsVIncrement); + hemisphereVertexRings(rings-1, 0.0f, -Math::Constants::pi()/2+ringAngleIncrement, ringAngleIncrement, textureCoordsVIncrement, textureCoordsVIncrement); /* Top cap vertex */ capVertex(1.0f, 1.0f, 1.0f);