Browse Source

Primitives: reworked remaining classes to have the same API as the rest.

Now every primitive can be created using `solid()` or `wireframe()`
function returning directly Trade::MeshData.
pull/278/head
Vladimír Vondruš 13 years ago
parent
commit
70ba2bd77c
  1. 4
      src/Primitives/CMakeLists.txt
  2. 138
      src/Primitives/Capsule.cpp
  3. 38
      src/Primitives/Capsule.h
  4. 2
      src/Primitives/Circle.h
  5. 44
      src/Primitives/Cylinder.cpp
  6. 21
      src/Primitives/Cylinder.h
  7. 162
      src/Primitives/Implementation/Spheroid.cpp
  8. 54
      src/Primitives/Implementation/Spheroid.h
  9. 5
      src/Primitives/Test/CapsuleTest.cpp
  10. 5
      src/Primitives/Test/CylinderTest.cpp
  11. 5
      src/Primitives/Test/UVSphereTest.cpp
  12. 23
      src/Primitives/UVSphere.cpp
  13. 29
      src/Primitives/UVSphere.h

4
src/Primitives/CMakeLists.txt

@ -32,7 +32,9 @@ set(MagnumPrimitives_SRCS
Line.cpp
Plane.cpp
Square.cpp
UVSphere.cpp)
UVSphere.cpp
Implementation/Spheroid.cpp)
set(MagnumPrimitives_HEADERS
Capsule.h

138
src/Primitives/Capsule.cpp

@ -24,147 +24,43 @@
#include "Capsule.h"
#include "Math/Functions.h"
#include "Math/Vector3.h"
#include "Math/Angle.h"
#include "Primitives/Implementation/Spheroid.h"
namespace Magnum { namespace Primitives {
Capsule::Capsule(UnsignedInt hemisphereRings, UnsignedInt cylinderRings, UnsignedInt segments, Float length, TextureCoords textureCoords): MeshData3D(Mesh::Primitive::Triangles, new std::vector<UnsignedInt>, {new std::vector<Vector3>()}, {new std::vector<Vector3>()}, textureCoords == TextureCoords::Generate ? std::vector<std::vector<Vector2>*>{new std::vector<Vector2>()} : std::vector<std::vector<Vector2>*>()), 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", );
Trade::MeshData3D Capsule::solid(UnsignedInt hemisphereRings, UnsignedInt cylinderRings, UnsignedInt segments, Float length, TextureCoords textureCoords) {
CORRADE_ASSERT(hemisphereRings >= 1 && cylinderRings >= 1 && segments >= 3, "Capsule must have at least one hemisphere ring, one cylinder ring and three segments", Trade::MeshData3D(Mesh::Primitive::Triangles, nullptr, {}, {}, {}));
Implementation::Spheroid capsule(segments, textureCoords == TextureCoords::Generate ?
Implementation::Spheroid::TextureCoords::Generate :
Implementation::Spheroid::TextureCoords::DontGenerate);
Float height = 2.0f+length;
Float hemisphereTextureCoordsVIncrement = 1.0f/(hemisphereRings*height);
Rad hemisphereRingAngleIncrement(Constants::pi()/(2*hemisphereRings));
/* Bottom cap vertex */
capVertex(-height/2, -1.0f, 0.0f);
capsule.capVertex(-height/2, -1.0f, 0.0f);
/* Rings of bottom hemisphere */
hemisphereVertexRings(hemisphereRings-1, -length/2, -Rad(Constants::pi())/2+hemisphereRingAngleIncrement, hemisphereRingAngleIncrement, hemisphereTextureCoordsVIncrement, hemisphereTextureCoordsVIncrement);
capsule.hemisphereVertexRings(hemisphereRings-1, -length/2, -Rad(Constants::pi())/2+hemisphereRingAngleIncrement, hemisphereRingAngleIncrement, hemisphereTextureCoordsVIncrement, hemisphereTextureCoordsVIncrement);
/* Rings of cylinder */
cylinderVertexRings(cylinderRings+1, -length/2, length/cylinderRings, 1.0f/height, length/(cylinderRings*height));
capsule.cylinderVertexRings(cylinderRings+1, -length/2, length/cylinderRings, 1.0f/height, length/(cylinderRings*height));
/* Rings of top hemisphere */
hemisphereVertexRings(hemisphereRings-1, length/2, hemisphereRingAngleIncrement, hemisphereRingAngleIncrement, (1.0f + length)/height+hemisphereTextureCoordsVIncrement, hemisphereTextureCoordsVIncrement);
capsule.hemisphereVertexRings(hemisphereRings-1, length/2, hemisphereRingAngleIncrement, hemisphereRingAngleIncrement, (1.0f + length)/height+hemisphereTextureCoordsVIncrement, hemisphereTextureCoordsVIncrement);
/* Top cap vertex */
capVertex(height/2, 1.0f, 1.0f);
capsule.capVertex(height/2, 1.0f, 1.0f);
/* Faces */
bottomFaceRing();
faceRings(hemisphereRings*2-2+cylinderRings);
topFaceRing();
}
Capsule::Capsule(UnsignedInt segments, TextureCoords textureCoords): MeshData3D(Mesh::Primitive::Triangles, new std::vector<UnsignedInt>, {new std::vector<Vector3>()}, {new std::vector<Vector3>()}, textureCoords == TextureCoords::Generate ? std::vector<std::vector<Vector2>*>{new std::vector<Vector2>()} : std::vector<std::vector<Vector2>*>()), segments(segments), textureCoords(textureCoords) {}
void Capsule::capVertex(Float y, Float normalY, Float textureCoordsV) {
positions(0)->push_back({0.0f, y, 0.0f});
normals(0)->push_back({0.0f, normalY, 0.0f});
if(textureCoords == TextureCoords::Generate)
textureCoords2D(0)->push_back({0.5, textureCoordsV});
}
void Capsule::hemisphereVertexRings(UnsignedInt count, Float centerY, Rad startRingAngle, Rad ringAngleIncrement, Float startTextureCoordsV, Float textureCoordsVIncrement) {
Rad segmentAngleIncrement(2*Constants::pi()/segments);
Float x, y, z;
for(UnsignedInt i = 0; i != count; ++i) {
Rad ringAngle = startRingAngle + i*ringAngleIncrement;
x = z = Math::cos(ringAngle);
y = Math::sin(ringAngle);
for(UnsignedInt j = 0; j != segments; ++j) {
Rad segmentAngle = j*segmentAngleIncrement;
positions(0)->push_back({x*Math::sin(segmentAngle), centerY+y, z*Math::cos(segmentAngle)});
normals(0)->push_back({x*Math::sin(segmentAngle), y, z*Math::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});
}
}
}
void Capsule::cylinderVertexRings(UnsignedInt count, Float startY, Float yIncrement, Float startTextureCoordsV, Float textureCoordsVIncrement) {
Rad segmentAngleIncrement(2*Constants::pi()/segments);
for(UnsignedInt i = 0; i != count; ++i) {
for(UnsignedInt j = 0; j != segments; ++j) {
Rad segmentAngle = j*segmentAngleIncrement;
positions(0)->push_back({Math::sin(segmentAngle), startY, Math::cos(segmentAngle)});
normals(0)->push_back({Math::sin(segmentAngle), 0.0f, Math::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(UnsignedInt j = 0; j != segments; ++j) {
/* Bottom vertex */
indices()->push_back(0);
/* Top right vertex */
indices()->push_back((j != segments-1 || textureCoords == TextureCoords::Generate) ?
j+2 : 1);
/* Top left vertex */
indices()->push_back(j+1);
}
}
void Capsule::faceRings(UnsignedInt count, UnsignedInt offset) {
UnsignedInt vertexSegments = segments + (textureCoords == TextureCoords::Generate ? 1 : 0);
for(UnsignedInt i = 0; i != count; ++i) {
for(UnsignedInt j = 0; j != segments; ++j) {
UnsignedInt bottomLeft = i*vertexSegments+j+offset;
UnsignedInt bottomRight = ((j != segments-1 || textureCoords == TextureCoords::Generate) ?
i*vertexSegments+j+1+offset : i*segments+offset);
UnsignedInt topLeft = bottomLeft+vertexSegments;
UnsignedInt topRight = bottomRight+vertexSegments;
indices()->push_back(bottomLeft);
indices()->push_back(bottomRight);
indices()->push_back(topRight);
indices()->push_back(bottomLeft);
indices()->push_back(topRight);
indices()->push_back(topLeft);
}
}
}
void Capsule::topFaceRing() {
UnsignedInt vertexSegments = segments + (textureCoords == TextureCoords::Generate ? 1 : 0);
for(UnsignedInt j = 0; j != segments; ++j) {
/* Bottom left vertex */
indices()->push_back(normals(0)->size()-vertexSegments+j-1);
/* Bottom right vertex */
indices()->push_back((j != segments-1 || textureCoords == TextureCoords::Generate) ?
normals(0)->size()-vertexSegments+j : normals(0)->size()-segments-1);
capsule.bottomFaceRing();
capsule.faceRings(hemisphereRings*2-2+cylinderRings);
capsule.topFaceRing();
/* Top vertex */
indices()->push_back(normals(0)->size()-1);
}
return std::move(capsule);
}
}}

38
src/Primitives/Capsule.h

@ -28,56 +28,40 @@
* @brief Class Magnum::Primitives::Capsule
*/
#include "Trade/MeshData3D.h"
#include "Primitives/magnumPrimitivesVisibility.h"
#include "Trade/Trade.h"
namespace Magnum { namespace Primitives {
/**
@brief 3D capsule primitive
%Cylinder along Y axis with hemispheres instead of caps. Indexed @ref Mesh::Primitive "Triangles"
with normals and optional 2D texture coordinates.
%Cylinder of radius `1` along Y axis with hemispheres instead of caps.
*/
class Capsule: public Trade::MeshData3D {
friend class UVSphere;
friend class Cylinder;
class MAGNUM_PRIMITIVES_EXPORT Capsule {
public:
/** @brief Whether to generate texture coordinates */
enum class TextureCoords {
enum class TextureCoords: UnsignedByte {
Generate, /**< Generate texture coordinates */
DontGenerate /**< Don't generate texture coordinates */
};
/**
* @brief Constructor
* @brief Solid capsule
* @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 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.
*
* If texture coordinates are generated, vertices of one segment are
* duplicated for texture wrapping.
* Indexed @ref Mesh::Primitive "Triangles" with normals and optional
* 2D texture coordinates. If texture coordinates are generated,
* vertices of one segment are duplicated for texture wrapping.
*/
explicit MAGNUM_PRIMITIVES_EXPORT Capsule(UnsignedInt hemisphereRings, UnsignedInt cylinderRings, UnsignedInt segments, Float length, TextureCoords textureCoords = TextureCoords::DontGenerate);
private:
Capsule(UnsignedInt segments, TextureCoords textureCoords);
void capVertex(Float y, Float normalY, Float textureCoordsV);
void hemisphereVertexRings(UnsignedInt count, Float centerY, Rad startRingAngle, Rad ringAngleIncrement, Float startTextureCoordsV, Float textureCoordsVIncrement);
void cylinderVertexRings(UnsignedInt count, Float startY, Float yIncrement, Float startTextureCoordsV, Float textureCoordsVIncrement);
void bottomFaceRing();
void faceRings(UnsignedInt count, UnsignedInt offset = 1);
void topFaceRing();
UnsignedInt segments;
TextureCoords textureCoords;
static Trade::MeshData3D solid(UnsignedInt hemisphereRings, UnsignedInt cylinderRings, UnsignedInt segments, Float length, TextureCoords textureCoords = TextureCoords::DontGenerate);
};
}}

2
src/Primitives/Circle.h

@ -37,7 +37,7 @@ namespace Magnum { namespace Primitives {
/**
@brief 2D circle primitive
Circle with radius 1.
Circle with radius `1`.
*/
class MAGNUM_PRIMITIVES_EXPORT Circle {
public:

44
src/Primitives/Cylinder.cpp

@ -24,56 +24,40 @@
#include "Cylinder.h"
#include "Math/Functions.h"
#include "Math/Vector3.h"
#include "Primitives/Implementation/Spheroid.h"
namespace Magnum { namespace Primitives {
Cylinder::Cylinder(UnsignedInt rings, UnsignedInt segments, Float length, Flags flags): Capsule(segments, flags & Flag::GenerateTextureCoords ? TextureCoords::Generate : TextureCoords::DontGenerate) {
CORRADE_ASSERT(rings >= 1 && segments >= 3, "Cylinder must have at least one ring and three segments", );
Trade::MeshData3D Cylinder::solid(UnsignedInt rings, UnsignedInt segments, Float length, Cylinder::Flags flags) {
CORRADE_ASSERT(rings >= 1 && segments >= 3, "Primitives::Cylinder::solid(): cylinder must have at least one ring and three segments", Trade::MeshData3D(Mesh::Primitive::Triangles, nullptr, {}, {}, {}));
Implementation::Spheroid cylinder(segments, flags & Flag::GenerateTextureCoords ? Implementation::Spheroid::TextureCoords::Generate : Implementation::Spheroid::TextureCoords::DontGenerate);
Float y = length*0.5f;
Float textureCoordsV = flags & Flag::CapEnds ? 1.0f/(length+2.0f) : 0.0f;
/* Bottom cap */
if(flags & Flag::CapEnds) {
capVertex(-y, -1.0f, 0.0f);
capVertexRing(-y, textureCoordsV, Vector3::yAxis(-1.0f));
cylinder.capVertex(-y, -1.0f, 0.0f);
cylinder.capVertexRing(-y, textureCoordsV, Vector3::yAxis(-1.0f));
}
/* Vertex rings */
cylinderVertexRings(rings+1, -y, length/rings, textureCoordsV, length/(rings*(flags & Flag::CapEnds ? length + 2.0f : length)));
cylinder.cylinderVertexRings(rings+1, -y, length/rings, textureCoordsV, length/(rings*(flags & Flag::CapEnds ? length + 2.0f : length)));
/* Top cap */
if(flags & Flag::CapEnds) {
capVertexRing(y, 1.0f - textureCoordsV, Vector3::yAxis(1.0f));
capVertex(y, 1.0f, 1.0f);
cylinder.capVertexRing(y, 1.0f - textureCoordsV, Vector3::yAxis(1.0f));
cylinder.capVertex(y, 1.0f, 1.0f);
}
/* Faces */
if(flags & Flag::CapEnds) bottomFaceRing();
faceRings(rings, flags & Flag::CapEnds ? 1 : 0);
if(flags & Flag::CapEnds) topFaceRing();
}
void Cylinder::capVertexRing(Float y, Float textureCoordsV, const Vector3& normal) {
Rad segmentAngleIncrement(2*Constants::pi()/segments);
for(UnsignedInt i = 0; i != segments; ++i) {
Rad segmentAngle = i*segmentAngleIncrement;
positions(0)->push_back({Math::sin(segmentAngle), y, Math::cos(segmentAngle)});
normals(0)->push_back(normal);
if(flags & Flag::CapEnds) cylinder.bottomFaceRing();
cylinder.faceRings(rings, flags & Flag::CapEnds ? 1 : 0);
if(flags & Flag::CapEnds) cylinder.topFaceRing();
if(textureCoords == TextureCoords::Generate)
textureCoords2D(0)->push_back({i*1.0f/segments, textureCoordsV});
}
/* 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(normal);
textureCoords2D(0)->push_back({1.0f, textureCoordsV});
}
return std::move(cylinder);
}
}}

21
src/Primitives/Cylinder.h

@ -30,19 +30,17 @@
#include <Containers/EnumSet.h>
#include "Primitives/Capsule.h"
#include "Primitives/magnumPrimitivesVisibility.h"
#include "Trade/Trade.h"
namespace Magnum { namespace Primitives {
/**
@brief 3D cylinder primitive
Indexed @ref Mesh::Primitive "Triangles" with normals, optional 2D texture
coordinates and optional capped ends.
%Cylinder along Y axis of radius `1`.
*/
class Cylinder: public Capsule {
class MAGNUM_PRIMITIVES_EXPORT Cylinder {
public:
/**
* @brief %Flags
@ -58,7 +56,7 @@ class Cylinder: public Capsule {
typedef Corrade::Containers::EnumSet<Flag, int> Flags;
/**
* @brief Constructor
* @brief Solid cylinder
* @param rings Number of (face) rings. Must be larger or
* equal to 1.
* @param segments Number of (face) segments. Must be larger or
@ -66,13 +64,12 @@ class Cylinder: public Capsule {
* @param length Cylinder length
* @param flags Flags
*
* If texture coordinates are generated, vertices of one segment are
* duplicated for texture wrapping.
* Indexed @ref Mesh::Primitive "Triangles" with normals, optional 2D
* texture coordinates and optional capped ends. If texture coordinates
* are generated, vertices of one segment are duplicated for texture
* wrapping.
*/
explicit MAGNUM_PRIMITIVES_EXPORT Cylinder(UnsignedInt rings, UnsignedInt segments, Float length, Flags flags = Flags());
private:
void capVertexRing(Float y, Float textureCoordsV, const Vector3& normal);
static Trade::MeshData3D solid(UnsignedInt rings, UnsignedInt segments, Float length, Flags flags = Flags());
};
CORRADE_ENUMSET_OPERATORS(Cylinder::Flags)

162
src/Primitives/Implementation/Spheroid.cpp

@ -0,0 +1,162 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include "Spheroid.h"
#include "Math/Functions.h"
#include "Math/Vector3.h"
namespace Magnum { namespace Primitives { namespace Implementation {
Spheroid::Spheroid(UnsignedInt segments, TextureCoords textureCoords): MeshData3D(Mesh::Primitive::Triangles, new std::vector<UnsignedInt>, {new std::vector<Vector3>()}, {new std::vector<Vector3>()}, textureCoords == TextureCoords::Generate ? std::vector<std::vector<Vector2>*>{new std::vector<Vector2>()} : std::vector<std::vector<Vector2>*>()), segments(segments), textureCoords(textureCoords) {}
void Spheroid::capVertex(Float y, Float normalY, Float textureCoordsV) {
positions(0)->push_back({0.0f, y, 0.0f});
normals(0)->push_back({0.0f, normalY, 0.0f});
if(textureCoords == TextureCoords::Generate)
textureCoords2D(0)->push_back({0.5, textureCoordsV});
}
void Spheroid::hemisphereVertexRings(UnsignedInt count, Float centerY, Rad startRingAngle, Rad ringAngleIncrement, Float startTextureCoordsV, Float textureCoordsVIncrement) {
Rad segmentAngleIncrement(2*Constants::pi()/segments);
Float x, y, z;
for(UnsignedInt i = 0; i != count; ++i) {
Rad ringAngle = startRingAngle + i*ringAngleIncrement;
x = z = Math::cos(ringAngle);
y = Math::sin(ringAngle);
for(UnsignedInt j = 0; j != segments; ++j) {
Rad segmentAngle = j*segmentAngleIncrement;
positions(0)->push_back({x*Math::sin(segmentAngle), centerY+y, z*Math::cos(segmentAngle)});
normals(0)->push_back({x*Math::sin(segmentAngle), y, z*Math::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});
}
}
}
void Spheroid::cylinderVertexRings(UnsignedInt count, Float startY, Float yIncrement, Float startTextureCoordsV, Float textureCoordsVIncrement) {
Rad segmentAngleIncrement(2*Constants::pi()/segments);
for(UnsignedInt i = 0; i != count; ++i) {
for(UnsignedInt j = 0; j != segments; ++j) {
Rad segmentAngle = j*segmentAngleIncrement;
positions(0)->push_back({Math::sin(segmentAngle), startY, Math::cos(segmentAngle)});
normals(0)->push_back({Math::sin(segmentAngle), 0.0f, Math::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 Spheroid::bottomFaceRing() {
for(UnsignedInt j = 0; j != segments; ++j) {
/* Bottom vertex */
indices()->push_back(0);
/* Top right vertex */
indices()->push_back((j != segments-1 || textureCoords == TextureCoords::Generate) ?
j+2 : 1);
/* Top left vertex */
indices()->push_back(j+1);
}
}
void Spheroid::faceRings(UnsignedInt count, UnsignedInt offset) {
UnsignedInt vertexSegments = segments + (textureCoords == TextureCoords::Generate ? 1 : 0);
for(UnsignedInt i = 0; i != count; ++i) {
for(UnsignedInt j = 0; j != segments; ++j) {
UnsignedInt bottomLeft = i*vertexSegments+j+offset;
UnsignedInt bottomRight = ((j != segments-1 || textureCoords == TextureCoords::Generate) ?
i*vertexSegments+j+1+offset : i*segments+offset);
UnsignedInt topLeft = bottomLeft+vertexSegments;
UnsignedInt topRight = bottomRight+vertexSegments;
indices()->push_back(bottomLeft);
indices()->push_back(bottomRight);
indices()->push_back(topRight);
indices()->push_back(bottomLeft);
indices()->push_back(topRight);
indices()->push_back(topLeft);
}
}
}
void Spheroid::topFaceRing() {
UnsignedInt vertexSegments = segments + (textureCoords == TextureCoords::Generate ? 1 : 0);
for(UnsignedInt j = 0; j != segments; ++j) {
/* Bottom left vertex */
indices()->push_back(normals(0)->size()-vertexSegments+j-1);
/* Bottom right vertex */
indices()->push_back((j != segments-1 || textureCoords == TextureCoords::Generate) ?
normals(0)->size()-vertexSegments+j : normals(0)->size()-segments-1);
/* Top vertex */
indices()->push_back(normals(0)->size()-1);
}
}
void Spheroid::capVertexRing(Float y, Float textureCoordsV, const Vector3& normal) {
Rad segmentAngleIncrement(2*Constants::pi()/segments);
for(UnsignedInt i = 0; i != segments; ++i) {
Rad segmentAngle = i*segmentAngleIncrement;
positions(0)->push_back({Math::sin(segmentAngle), y, Math::cos(segmentAngle)});
normals(0)->push_back(normal);
if(textureCoords == TextureCoords::Generate)
textureCoords2D(0)->push_back({i*1.0f/segments, textureCoordsV});
}
/* 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(normal);
textureCoords2D(0)->push_back({1.0f, textureCoordsV});
}
}
}}}

54
src/Primitives/Implementation/Spheroid.h

@ -0,0 +1,54 @@
#ifndef Magnum_Primitives_Spheroid_h
#define Magnum_Primitives_Spheroid_h
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include "Trade/MeshData3D.h"
namespace Magnum { namespace Primitives { namespace Implementation {
class Spheroid: public Trade::MeshData3D {
public:
enum class TextureCoords: UnsignedByte {
DontGenerate,
Generate
};
Spheroid(UnsignedInt segments, TextureCoords textureCoords);
void capVertex(Float y, Float normalY, Float textureCoordsV);
void hemisphereVertexRings(UnsignedInt count, Float centerY, Rad startRingAngle, Rad ringAngleIncrement, Float startTextureCoordsV, Float textureCoordsVIncrement);
void cylinderVertexRings(UnsignedInt count, Float startY, Float yIncrement, Float startTextureCoordsV, Float textureCoordsVIncrement);
void bottomFaceRing();
void faceRings(UnsignedInt count, UnsignedInt offset = 1);
void topFaceRing();
void capVertexRing(Float y, Float textureCoordsV, const Vector3& normal);
UnsignedInt segments;
TextureCoords textureCoords;
};
}}}
#endif

5
src/Primitives/Test/CapsuleTest.cpp

@ -29,6 +29,7 @@
#include <TestSuite/Compare/Container.h>
#include "Math/Vector3.h"
#include "Trade/MeshData3D.h"
#include "Primitives/Capsule.h"
using Corrade::TestSuite::Compare::Container;
@ -49,7 +50,7 @@ CapsuleTest::CapsuleTest() {
}
void CapsuleTest::withoutTextureCoords() {
Capsule capsule(2, 2, 3, 1.0f);
Trade::MeshData3D capsule = Capsule::solid(2, 2, 3, 1.0f);
CORRADE_COMPARE_AS(*capsule.positions(0), (std::vector<Vector3>{
{0.0f, -1.5f, 0.0f},
@ -114,7 +115,7 @@ void CapsuleTest::withoutTextureCoords() {
}
void CapsuleTest::withTextureCoords() {
Capsule capsule(2, 2, 3, 1.0f, Capsule::TextureCoords::Generate);
Trade::MeshData3D capsule = Capsule::solid(2, 2, 3, 1.0f, Capsule::TextureCoords::Generate);
CORRADE_COMPARE_AS(*capsule.positions(0), (std::vector<Vector3>{
{0.0f, -1.5f, 0.0f},

5
src/Primitives/Test/CylinderTest.cpp

@ -27,6 +27,7 @@
#include "Math/Vector3.h"
#include "Primitives/Cylinder.h"
#include "Trade/MeshData3D.h"
using Corrade::TestSuite::Compare::Container;
@ -46,7 +47,7 @@ CylinderTest::CylinderTest() {
}
void CylinderTest::withoutAnything() {
Cylinder cylinder(2, 3, 3.0f);
Trade::MeshData3D cylinder = Cylinder::solid(2, 3, 3.0f);
CORRADE_COMPARE_AS(*cylinder.positions(0), (std::vector<Vector3>{
{0.0f, -1.5f, 1.0f},
@ -83,7 +84,7 @@ void CylinderTest::withoutAnything() {
}
void CylinderTest::withTextureCoordsAndCaps() {
Cylinder cylinder(2, 3, 3.0f, Cylinder::Flag::GenerateTextureCoords|Cylinder::Flag::CapEnds);
Trade::MeshData3D cylinder = Cylinder::solid(2, 3, 3.0f, Cylinder::Flag::GenerateTextureCoords|Cylinder::Flag::CapEnds);
CORRADE_COMPARE_AS(*cylinder.positions(0), (std::vector<Vector3>{
{0.0f, -1.5f, 0.0f},

5
src/Primitives/Test/UVSphereTest.cpp

@ -27,6 +27,7 @@
#include "Math/Vector3.h"
#include "Primitives/UVSphere.h"
#include "Trade/MeshData3D.h"
using Corrade::TestSuite::Compare::Container;
@ -46,7 +47,7 @@ UVSphereTest::UVSphereTest() {
}
void UVSphereTest::withoutTextureCoords() {
UVSphere sphere(3, 3);
Trade::MeshData3D sphere = UVSphere::solid(3, 3);
CORRADE_COMPARE_AS(*sphere.positions(0), (std::vector<Vector3>{
{0.0f, -1.0f, 0.0f},
@ -84,7 +85,7 @@ void UVSphereTest::withoutTextureCoords() {
}
void UVSphereTest::withTextureCoords() {
UVSphere sphere(3, 3, UVSphere::TextureCoords::Generate);
Trade::MeshData3D sphere = UVSphere::solid(3, 3, UVSphere::TextureCoords::Generate);
CORRADE_COMPARE_AS(*sphere.positions(0), (std::vector<Vector3>{
{0.0f, -1.0f, 0.0f},

23
src/Primitives/UVSphere.cpp

@ -25,28 +25,35 @@
#include "UVSphere.h"
#include "Math/Angle.h"
#include "Implementation/Spheroid.h"
namespace Magnum { namespace Primitives {
UVSphere::UVSphere(UnsignedInt rings, UnsignedInt segments, TextureCoords textureCoords): Capsule(segments, textureCoords) {
CORRADE_ASSERT(rings >= 2 && segments >= 3, "UVSphere must have at least two rings and three segments", );
Trade::MeshData3D UVSphere::solid(UnsignedInt rings, UnsignedInt segments, TextureCoords textureCoords) {
CORRADE_ASSERT(rings >= 2 && segments >= 3, "UVSphere must have at least two rings and three segments", Trade::MeshData3D(Mesh::Primitive::Triangles, nullptr, {}, {}, {}));
Implementation::Spheroid sphere(segments, textureCoords == TextureCoords::Generate ?
Implementation::Spheroid::TextureCoords::Generate :
Implementation::Spheroid::TextureCoords::DontGenerate);
Float textureCoordsVIncrement = 1.0f/rings;
Rad ringAngleIncrement(Constants::pi()/rings);
/* Bottom cap vertex */
capVertex(-1.0f, -1.0f, 0.0f);
sphere.capVertex(-1.0f, -1.0f, 0.0f);
/* Vertex rings */
hemisphereVertexRings(rings-1, 0.0f, -Rad(Constants::pi())/2+ringAngleIncrement, ringAngleIncrement, textureCoordsVIncrement, textureCoordsVIncrement);
sphere.hemisphereVertexRings(rings-1, 0.0f, -Rad(Constants::pi())/2+ringAngleIncrement, ringAngleIncrement, textureCoordsVIncrement, textureCoordsVIncrement);
/* Top cap vertex */
capVertex(1.0f, 1.0f, 1.0f);
sphere.capVertex(1.0f, 1.0f, 1.0f);
/* Faces */
bottomFaceRing();
faceRings(rings-2);
topFaceRing();
sphere.bottomFaceRing();
sphere.faceRings(rings-2);
sphere.topFaceRing();
return std::move(sphere);
}
}}

29
src/Primitives/UVSphere.h

@ -28,30 +28,37 @@
* @brief Class Magnum::Primitives::UVSphere
*/
#include "Primitives/Capsule.h"
#include "Primitives/magnumPrimitivesVisibility.h"
#include "Trade/Trade.h"
namespace Magnum { namespace Primitives {
/**
@brief 3D UV sphere primitive
Indexed @ref Mesh::Primitive "Triangles" with normals and optional 2D texture
coordinates.
Sphere with radius `1`.
*/
class UVSphere: public Capsule {
class MAGNUM_PRIMITIVES_EXPORT UVSphere {
public:
/** @brief Whether to generate texture coordinates */
enum class TextureCoords: UnsignedByte {
Generate, /**< Generate texture coordinates */
DontGenerate /**< Don't generate texture coordinates */
};
/**
* @brief Constructor
* @param rings Number of (face) rings. Must be larger or equal to 2.
* @param segments Number of (face) segments. Must be larger or equal to 3.
* @brief Solid UV sphere
* @param rings Number of (face) rings. Must be larger or equal
* to 2.
* @param segments Number of (face) segments. Must be larger or
* equal to 3.
* @param textureCoords Whether to generate texture coordinates.
*
* If texture coordinates are generated, vertices of one segment are
* duplicated for texture wrapping.
* Indexed @ref Mesh::Primitive "Triangles" with normals and optional
* 2D texture coordinates. If texture coordinates are generated,
* vertices of one segment are duplicated for texture wrapping.
*/
explicit MAGNUM_PRIMITIVES_EXPORT UVSphere(UnsignedInt rings, UnsignedInt segments, TextureCoords textureCoords = TextureCoords::DontGenerate);
static Trade::MeshData3D solid(UnsignedInt rings, UnsignedInt segments, TextureCoords textureCoords = TextureCoords::DontGenerate);
};
}}

Loading…
Cancel
Save