Browse Source

Primitives: tangents in the plane primitive.

This turned the primitive from being fully defined at compile time to
being mostly dynamically allocated. Keeping just the positions+normals
case defined at compile time, and splitting the function into two
overloads so the extra code can be DCEd when people call the function
with no flags.
pull/430/head
Vladimír Vondruš 6 years ago
parent
commit
2a88a885c1
  1. 4
      doc/changelog.dox
  2. 110
      src/Magnum/Primitives/Plane.cpp
  3. 24
      src/Magnum/Primitives/Plane.h
  4. 62
      src/Magnum/Primitives/Test/PlaneTest.cpp

4
doc/changelog.dox

@ -196,8 +196,8 @@ See also:
- @ref Primitives::capsule3DSolid(), @ref Primitives::circle3DSolid(),
@ref Primitives::coneSolid(), @ref Primitives::cylinderSolid(),
@ref Primitives::grid3DSolid() and @ref Primitives::uvSphereSolid() can now
have tangents as well
@ref Primitives::grid3DSolid(), @ref Primitives::planeSolid() and
@ref Primitives::uvSphereSolid() can now have tangents as well
@subsubsection changelog-latest-new-scenegraph SceneGraph library

110
src/Magnum/Primitives/Plane.cpp

@ -26,7 +26,7 @@
#include "Plane.h"
#include "Magnum/Mesh.h"
#include "Magnum/Math/Vector3.h"
#include "Magnum/Math/Vector4.h"
#include "Magnum/Trade/MeshData.h"
namespace Magnum { namespace Primitives {
@ -42,16 +42,6 @@ constexpr struct VertexSolid {
{{-1.0f, -1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}},
{{-1.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}}
};
constexpr struct VertexSolidTextureCoords {
Vector3 position;
Vector3 normal;
Vector2 textureCoords;
} VerticesSolidTextureCoords[] {
{VerticesSolid[0].position, VerticesSolid[0].normal, {1.0f, 0.0f}},
{VerticesSolid[1].position, VerticesSolid[1].normal, {1.0f, 1.0f}},
{VerticesSolid[2].position, VerticesSolid[2].normal, {0.0f, 0.0f}},
{VerticesSolid[3].position, VerticesSolid[3].normal, {0.0f, 1.0f}}
};
constexpr Trade::MeshAttributeData AttributesSolid[]{
Trade::MeshAttributeData{Trade::MeshAttribute::Position,
Containers::stridedArrayView(VerticesSolid, &VerticesSolid[0].position,
@ -60,34 +50,92 @@ constexpr Trade::MeshAttributeData AttributesSolid[]{
Containers::stridedArrayView(VerticesSolid, &VerticesSolid[0].normal,
Containers::arraySize(VerticesSolid), sizeof(VertexSolid))}
};
constexpr Trade::MeshAttributeData AttributesSolidTextureCoords[]{
Trade::MeshAttributeData{Trade::MeshAttribute::Position,
Containers::stridedArrayView(VerticesSolidTextureCoords,
&VerticesSolidTextureCoords[0].position,
Containers::arraySize(VerticesSolidTextureCoords), sizeof(VertexSolidTextureCoords))},
Trade::MeshAttributeData{Trade::MeshAttribute::Normal,
Containers::stridedArrayView(VerticesSolidTextureCoords,
&VerticesSolidTextureCoords[0].normal,
Containers::arraySize(VerticesSolidTextureCoords), sizeof(VertexSolidTextureCoords))},
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates,
Containers::stridedArrayView(VerticesSolidTextureCoords,
&VerticesSolidTextureCoords[0].textureCoords,
Containers::arraySize(VerticesSolidTextureCoords), sizeof(VertexSolidTextureCoords))},
};
}
Trade::MeshData planeSolid(const PlaneFlags flags) {
if(flags & PlaneFlag::TextureCoordinates)
return Trade::MeshData{MeshPrimitive::TriangleStrip,
{}, VerticesSolidTextureCoords,
Trade::meshAttributeDataNonOwningArray(AttributesSolidTextureCoords)};
Trade::MeshData planeSolid() {
return Trade::MeshData{MeshPrimitive::TriangleStrip,
{}, VerticesSolid,
Trade::meshAttributeDataNonOwningArray(AttributesSolid)};
}
Trade::MeshData planeSolid(const PlaneFlags flags) {
/* Return the compile-time data if nothing extra is requested */
if(!flags) return planeSolid();
/* Calculate attribute count and vertex size */
std::size_t stride = sizeof(Vector3) + sizeof(Vector3);
std::size_t attributeCount = 2;
if(flags & PlaneFlag::Tangents) {
stride += sizeof(Vector4);
++attributeCount;
}
if(flags & PlaneFlag::TextureCoordinates) {
stride += sizeof(Vector2);
++attributeCount;
}
/* Set up the layout */
Containers::Array<char> vertexData{Containers::NoInit, 4*stride};
Containers::Array<Trade::MeshAttributeData> attributeData{attributeCount};
std::size_t attributeIndex = 0;
std::size_t attributeOffset = 0;
Containers::StridedArrayView1D<Vector3> positions{vertexData,
reinterpret_cast<Vector3*>(vertexData.data() + attributeOffset),
4, std::ptrdiff_t(stride)};
attributeData[attributeIndex++] = Trade::MeshAttributeData{
Trade::MeshAttribute::Position, positions};
attributeOffset += sizeof(Vector3);
Containers::StridedArrayView1D<Vector3> normals{vertexData,
reinterpret_cast<Vector3*>(vertexData.data() + sizeof(Vector3)),
4, std::ptrdiff_t(stride)};
attributeData[attributeIndex++] = Trade::MeshAttributeData{
Trade::MeshAttribute::Normal, normals};
attributeOffset += sizeof(Vector3);
Containers::StridedArrayView1D<Vector4> tangents;
if(flags & PlaneFlag::Tangents) {
tangents = Containers::StridedArrayView1D<Vector4>{vertexData,
reinterpret_cast<Vector4*>(vertexData.data() + attributeOffset),
4, std::ptrdiff_t(stride)};
attributeData[attributeIndex++] = Trade::MeshAttributeData{
Trade::MeshAttribute::Tangent, tangents};
attributeOffset += sizeof(Vector4);
}
Containers::StridedArrayView1D<Vector2> textureCoordinates;
if(flags & PlaneFlag::TextureCoordinates) {
textureCoordinates = Containers::StridedArrayView1D<Vector2>{vertexData,
reinterpret_cast<Vector2*>(vertexData.data() + attributeOffset),
4, std::ptrdiff_t(stride)};
attributeData[attributeIndex++] = Trade::MeshAttributeData{
Trade::MeshAttribute::TextureCoordinates, textureCoordinates};
attributeOffset += sizeof(Vector2);
}
CORRADE_INTERNAL_ASSERT(attributeIndex == attributeCount);
CORRADE_INTERNAL_ASSERT(attributeOffset == stride);
/* Fill the data */
for(std::size_t i = 0; i != 4; ++i) {
positions[i] = VerticesSolid[i].position;
normals[i] = VerticesSolid[i].normal;
if(flags & PlaneFlag::Tangents)
tangents[i] = {1.0f, 0.0f, 0.0f, 1.0f};
}
if(flags & PlaneFlag::TextureCoordinates) {
textureCoordinates[0] = {1.0f, 0.0f};
textureCoordinates[1] = {1.0f, 1.0f};
textureCoordinates[2] = {0.0f, 0.0f};
textureCoordinates[3] = {0.0f, 1.0f};
}
return Trade::MeshData{MeshPrimitive::TriangleStrip,
std::move(vertexData), std::move(attributeData)};
}
#ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_IGNORE_DEPRECATED_PUSH
Trade::MeshData planeSolid(const PlaneTextureCoords textureCoords) {

24
src/Magnum/Primitives/Plane.h

@ -45,7 +45,15 @@ namespace Magnum { namespace Primitives {
*/
enum class PlaneFlag: UnsignedByte {
/** Generate texture coordinates with origin in bottom left corner */
TextureCoordinates = 1 << 0
TextureCoordinates = 1 << 0,
/**
* Generate four-component tangents. The last component can be used to
* reconstruct a bitangent as described in the documentation of
* @ref Trade::MeshAttribute::Tangent.
* @m_since_latest
*/
Tangents = 1 << 1
};
/**
@ -77,16 +85,22 @@ enum class CORRADE_DEPRECATED_ENUM("use PlaneFlags instead") PlaneTextureCoords:
@m_since_latest
2x2 plane. Non-indexed @ref MeshPrimitive::TriangleStrip on the XY plane with
@ref VertexFormat::Vector3 positions and @ref VertexFormat::Vector3 normals in
positive Z direction. The returned instance references data stored in constant
memory.
@ref VertexFormat::Vector3 positions, @ref VertexFormat::Vector3 normals in
positive Z direction, optional @ref VertexFormat::Vector4 tangents and optional
@ref VertexFormat::Vector2 texture coordinates. The returned instance may
reference data stored in constant memory.
@image html primitives-planesolid.png width=256px
@see @ref planeWireframe(), @ref squareSolid(), @ref gradient3D(),
@ref MeshTools::generateTriangleStripIndices()
*/
MAGNUM_PRIMITIVES_EXPORT Trade::MeshData planeSolid(PlaneFlags flags = {});
MAGNUM_PRIMITIVES_EXPORT Trade::MeshData planeSolid(PlaneFlags flags);
/** @overload */
/* Separate API so apps that don't need texture coordinate / tangents don't
need to drag in the extra code needed to allocate & calculate them */
MAGNUM_PRIMITIVES_EXPORT Trade::MeshData planeSolid();
#ifdef MAGNUM_BUILD_DEPRECATED
/**

62
src/Magnum/Primitives/Test/PlaneTest.cpp

@ -26,7 +26,7 @@
#include <Corrade/TestSuite/Tester.h>
#include "Magnum/Mesh.h"
#include "Magnum/Math/Vector3.h"
#include "Magnum/Math/Vector4.h"
#include "Magnum/Primitives/Plane.h"
#include "Magnum/Trade/MeshData.h"
@ -36,42 +36,64 @@ struct PlaneTest: TestSuite::Tester {
explicit PlaneTest();
void solid();
void solidTextured();
void wireframe();
};
constexpr struct {
const char* name;
PlaneFlags flags;
} SolidData[] {
{"", PlaneFlags{}},
{"texture coordinates", PlaneFlag::TextureCoordinates},
{"tangents", PlaneFlag::Tangents},
{"both", PlaneFlag::TextureCoordinates|PlaneFlag::Tangents}
};
PlaneTest::PlaneTest() {
addTests({&PlaneTest::solid,
&PlaneTest::solidTextured,
&PlaneTest::wireframe});
addInstancedTests({&PlaneTest::solid},
Containers::arraySize(SolidData));
addTests({&PlaneTest::wireframe});
}
void PlaneTest::solid() {
Trade::MeshData plane = Primitives::planeSolid();
auto&& data = SolidData[testCaseInstanceId()];
setTestCaseDescription(data.name);
Trade::MeshData plane = Primitives::planeSolid(data.flags);
CORRADE_COMPARE(plane.primitive(), MeshPrimitive::TriangleStrip);
CORRADE_VERIFY(!plane.isIndexed());
CORRADE_COMPARE(plane.vertexCount(), 4);
CORRADE_COMPARE(plane.attributeCount(), 2);
CORRADE_COMPARE(plane.attribute<Vector3>(Trade::MeshAttribute::Position)[3],
(Vector3{-1.0f, 1.0f, 0.0f}));
CORRADE_COMPARE(plane.attribute<Vector3>(Trade::MeshAttribute::Normal)[2],
(Vector3{0.0f, 0.0f, 1.0f}));
}
void PlaneTest::solidTextured() {
Trade::MeshData plane = Primitives::planeSolid(Primitives::PlaneFlag::TextureCoordinates);
if(data.flags & PlaneFlag::Tangents)
CORRADE_COMPARE(plane.attribute<Vector4>(Trade::MeshAttribute::Tangent)[1],
(Vector4{1.0f, 0.0f, 0.0f, 1.0f}));
else CORRADE_VERIFY(!plane.hasAttribute(Trade::MeshAttribute::Tangent));
CORRADE_COMPARE(plane.primitive(), MeshPrimitive::TriangleStrip);
CORRADE_VERIFY(!plane.isIndexed());
CORRADE_COMPARE(plane.vertexCount(), 4);
CORRADE_COMPARE(plane.attributeCount(), 3);
CORRADE_COMPARE(plane.attribute<Vector3>(Trade::MeshAttribute::Position)[3],
(Vector3{-1.0f, 1.0f, 0.0f}));
CORRADE_COMPARE(plane.attribute<Vector3>(Trade::MeshAttribute::Normal)[2],
(Vector3{0.0f, 0.0f, 1.0f}));
CORRADE_COMPARE(plane.attribute<Vector2>(Trade::MeshAttribute::TextureCoordinates)[1],
(Vector2{1.0f, 1.0f}));
if(data.flags & PlaneFlag::TextureCoordinates)
CORRADE_COMPARE(plane.attribute<Vector2>(Trade::MeshAttribute::TextureCoordinates)[1],
(Vector2{1.0f, 1.0f}));
else CORRADE_VERIFY(!plane.hasAttribute(Trade::MeshAttribute::TextureCoordinates));
if(data.flags & PlaneFlag::Tangents) {
auto tangents = plane.attribute<Vector4>(Trade::MeshAttribute::Tangent);
auto normals = plane.attribute<Vector3>(Trade::MeshAttribute::Normal);
for(std::size_t i = 0; i != tangents.size(); ++i) {
CORRADE_ITERATION(i);
CORRADE_ITERATION(tangents[i]);
CORRADE_ITERATION(normals[i]);
CORRADE_VERIFY(tangents[i].xyz().isNormalized());
CORRADE_VERIFY(normals[i].isNormalized());
CORRADE_COMPARE(Math::dot(tangents[i].xyz(), normals[i]), 0.0f);
}
}
}
void PlaneTest::wireframe() {

Loading…
Cancel
Save