259 lines
7.0 KiB
C++
259 lines
7.0 KiB
C++
// mesh.h
|
|
//
|
|
// Copyright (C) 2004-2010, Celestia Development Team
|
|
// Original version by Chris Laurel <claurel@gmail.com>
|
|
//
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU General Public License
|
|
// as published by the Free Software Foundation; either version 2
|
|
// of the License, or (at your option) any later version.
|
|
|
|
#pragma once
|
|
|
|
#include <array>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Geometry>
|
|
|
|
#include "material.h"
|
|
|
|
|
|
namespace cmod
|
|
{
|
|
// 32-bit index type
|
|
using Index32 = std::uint32_t;
|
|
|
|
using VWord = std::uint32_t;
|
|
|
|
enum class VertexAttributeSemantic : std::int16_t
|
|
{
|
|
Position = 0,
|
|
Color0 = 1,
|
|
Color1 = 2,
|
|
Normal = 3,
|
|
Tangent = 4,
|
|
Texture0 = 5,
|
|
Texture1 = 6,
|
|
Texture2 = 7,
|
|
Texture3 = 8,
|
|
PointSize = 9,
|
|
NextPosition = 10,
|
|
ScaleFactor = 11,
|
|
SemanticMax = 12,
|
|
InvalidSemantic = -1,
|
|
};
|
|
|
|
|
|
enum class VertexAttributeFormat : std::int16_t
|
|
{
|
|
Float1 = 0,
|
|
Float2 = 1,
|
|
Float3 = 2,
|
|
Float4 = 3,
|
|
UByte4 = 4,
|
|
FormatMax = 5,
|
|
InvalidFormat = -1,
|
|
};
|
|
|
|
|
|
enum class PrimitiveGroupType : std::int16_t
|
|
{
|
|
TriList = 0,
|
|
TriStrip = 1,
|
|
TriFan = 2,
|
|
LineList = 3,
|
|
LineStrip = 4,
|
|
PointList = 5,
|
|
SpriteList = 6,
|
|
PrimitiveTypeMax = 7,
|
|
InvalidPrimitiveGroupType = -1
|
|
};
|
|
|
|
|
|
struct VertexAttribute
|
|
{
|
|
VertexAttribute() :
|
|
semantic(VertexAttributeSemantic::InvalidSemantic),
|
|
format(VertexAttributeFormat::InvalidFormat),
|
|
offsetWords(0)
|
|
{
|
|
}
|
|
|
|
VertexAttribute(VertexAttributeSemantic _semantic,
|
|
VertexAttributeFormat _format,
|
|
unsigned int _offsetWords) :
|
|
semantic(_semantic),
|
|
format(_format),
|
|
offsetWords(_offsetWords)
|
|
{
|
|
}
|
|
|
|
static constexpr unsigned int getFormatSizeWords(VertexAttributeFormat fmt)
|
|
{
|
|
switch (fmt)
|
|
{
|
|
case VertexAttributeFormat::Float1:
|
|
case VertexAttributeFormat::UByte4:
|
|
return 1;
|
|
case VertexAttributeFormat::Float2:
|
|
return 2;
|
|
case VertexAttributeFormat::Float3:
|
|
return 3;
|
|
case VertexAttributeFormat::Float4:
|
|
return 4;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
VertexAttributeSemantic semantic;
|
|
VertexAttributeFormat format;
|
|
unsigned int offsetWords;
|
|
};
|
|
|
|
bool operator==(const VertexAttribute& a, const VertexAttribute& b);
|
|
bool operator<(const VertexAttribute& a, const VertexAttribute& b);
|
|
|
|
|
|
struct VertexDescription
|
|
{
|
|
VertexDescription() = default;
|
|
explicit VertexDescription(std::vector<VertexAttribute>&& attributes);
|
|
~VertexDescription() = default;
|
|
VertexDescription(VertexDescription&&) = default;
|
|
VertexDescription& operator=(VertexDescription&&) = default;
|
|
|
|
VertexDescription clone() const { return *this; }
|
|
|
|
inline const VertexAttribute& getAttribute(VertexAttributeSemantic semantic) const
|
|
{
|
|
return semanticMap[static_cast<std::size_t>(semantic)];
|
|
}
|
|
|
|
bool validate() const;
|
|
|
|
unsigned int strideBytes{ 0 };
|
|
std::vector<VertexAttribute> attributes{ };
|
|
|
|
private:
|
|
VertexDescription(const VertexDescription&) = default;
|
|
VertexDescription& operator=(const VertexDescription&) = default;
|
|
|
|
void clearSemanticMap();
|
|
void buildSemanticMap();
|
|
|
|
// Vertex attributes indexed by semantic
|
|
std::array<VertexAttribute, static_cast<std::size_t>(VertexAttributeSemantic::SemanticMax)> semanticMap;
|
|
};
|
|
|
|
|
|
bool operator==(const VertexDescription& a, const VertexDescription& b);
|
|
bool operator<(const VertexDescription& a, const VertexDescription& b);
|
|
|
|
|
|
struct PrimitiveGroup
|
|
{
|
|
PrimitiveGroup() = default;
|
|
~PrimitiveGroup() = default;
|
|
PrimitiveGroup(const PrimitiveGroup&) = delete;
|
|
PrimitiveGroup& operator=(const PrimitiveGroup&) = delete;
|
|
PrimitiveGroup(PrimitiveGroup&&) = default;
|
|
PrimitiveGroup& operator=(PrimitiveGroup&&) = default;
|
|
|
|
PrimitiveGroup clone() const;
|
|
unsigned int getPrimitiveCount() const;
|
|
|
|
PrimitiveGroupType prim{ PrimitiveGroupType::InvalidPrimitiveGroupType };
|
|
unsigned int materialIndex{ 0 };
|
|
std::vector<Index32> indices{ };
|
|
PrimitiveGroupType primOverride{ PrimitiveGroupType::InvalidPrimitiveGroupType };
|
|
std::vector<VWord> vertexOverride{ };
|
|
unsigned int vertexCountOverride{ 0 };
|
|
std::vector<Index32> indicesOverride{ };
|
|
VertexDescription vertexDescriptionOverride{ };
|
|
};
|
|
|
|
|
|
class Mesh
|
|
{
|
|
public:
|
|
class PickResult
|
|
{
|
|
public:
|
|
PickResult() = default;
|
|
|
|
const Mesh* mesh{ nullptr };
|
|
const PrimitiveGroup* group{ nullptr };
|
|
unsigned int primitiveIndex{ 0 };
|
|
double distance{ -1.0 };
|
|
};
|
|
|
|
Mesh() = default;
|
|
~Mesh() = default;
|
|
Mesh(const Mesh&) = delete;
|
|
Mesh& operator=(const Mesh&) = delete;
|
|
Mesh(Mesh&&) = default;
|
|
Mesh& operator=(Mesh&&) = default;
|
|
|
|
Mesh clone() const;
|
|
|
|
void setVertices(unsigned int _nVertices, std::vector<VWord>&& vertexData);
|
|
bool setVertexDescription(VertexDescription&& desc);
|
|
const VertexDescription& getVertexDescription() const;
|
|
|
|
const PrimitiveGroup* getGroup(unsigned int index) const;
|
|
PrimitiveGroup* getGroup(unsigned int index);
|
|
unsigned int addGroup(PrimitiveGroup&& group);
|
|
unsigned int addGroup(PrimitiveGroupType prim,
|
|
unsigned int materialIndex,
|
|
std::vector<Index32>&& indices);
|
|
unsigned int getGroupCount() const;
|
|
void remapIndices(const std::vector<Index32>& indexMap);
|
|
void clearGroups();
|
|
|
|
void remapMaterials(const std::vector<unsigned int>& materialMap);
|
|
|
|
/*! Reorder primitive groups so that groups with identical materials
|
|
* appear sequentially in the primitive group list. This will reduce
|
|
* the number of graphics state changes at render time.
|
|
*/
|
|
void aggregateByMaterial();
|
|
|
|
const std::string& getName() const;
|
|
void setName(std::string&&);
|
|
|
|
bool pick(const Eigen::Vector3d& origin, const Eigen::Vector3d& direction, PickResult* result) const;
|
|
bool pick(const Eigen::Vector3d& origin, const Eigen::Vector3d& direction, double& distance) const;
|
|
|
|
Eigen::AlignedBox<float, 3> getBoundingBox() const;
|
|
void transform(const Eigen::Vector3f& translation, float scale);
|
|
|
|
const VWord* getVertexData() const { return vertices.data(); }
|
|
unsigned int getVertexCount() const { return nVertices; }
|
|
unsigned int getVertexStrideWords() const { return vertexDesc.strideBytes / sizeof(cmod::VWord); }
|
|
unsigned int getPrimitiveCount() const;
|
|
|
|
void merge(const Mesh&);
|
|
bool canMerge(const Mesh&, const std::vector<Material> &materials) const;
|
|
void optimize();
|
|
|
|
private:
|
|
PrimitiveGroup createLinePrimitiveGroup(bool lineStrip, const std::vector<Index32>& indices);
|
|
void mergePrimitiveGroups();
|
|
|
|
VertexDescription vertexDesc{ };
|
|
|
|
unsigned int nVertices{ 0 };
|
|
std::vector<VWord> vertices{ };
|
|
|
|
std::vector<PrimitiveGroup> groups;
|
|
|
|
std::string name;
|
|
};
|
|
|
|
} // namespace cmod
|