celestia/src/celmodel/model.h

166 lines
4.9 KiB
C++

// model.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 <vector>
#include <Eigen/Core>
#include "material.h"
#include "mesh.h"
namespace cmod
{
/*!
* Model is the standard geometry object in Celestia. A Model
* consists of a library of materials together with a list of
* meshes. Each mesh object contains a pool of vertices and a
* set of primitive groups. A primitive groups consists of a
* a primitive group type and a list of vertex indices. This
* structure is exactly the one used in Celestia model (.cmod)
* files.
*/
class Model
{
public:
Model();
~Model();
const Material* getMaterial(unsigned int index) const;
void setMaterial(unsigned int index, const Material* material);
unsigned int addMaterial(const Material* material);
/*! Return the number of materials in the model
*/
unsigned int getMaterialCount() const;
/*! Return the total number of vertices in the model
*/
unsigned int getVertexCount() const;
/*! Return the total number of primitives in the model
*/
unsigned int getPrimitiveCount() const;
/*! Return the mesh with the specified index, or nullptr if the
* index is out of range.
*/
Mesh* getMesh(unsigned int index) const;
/*! Return the total number of meshes withing the model.
*/
unsigned int getMeshCount() const;
/*! Add a new mesh to the model; the return value is the
* total number of meshes in the model.
*/
unsigned int addMesh(Mesh* mesh);
/** Find the closest intersection between the ray (given
* by origin and direction) and the model. If the ray
* intersects the model, return true and fill in the
* pick result record. If the result record is nullptr, it
* ignored, and the function just computes whether or
* not the ray intersected the model.
*/
bool pick(const Eigen::Vector3d& rayOrigin,
const Eigen::Vector3d& rayDirection,
Mesh::PickResult* result) const;
/** Find the closest intersection between the ray (given
* by origin and direction) and the model. If the ray
* intersects the model, return true and set distance;
* otherwise return false and leave distance unmodified.
*/
bool pick(const Eigen::Vector3d& rayOrigin,
const Eigen::Vector3d& rayDirection,
double& distance) const;
void transform(const Eigen::Vector3f& translation, float scale);
/** Apply a uniform scale to the model so that it fits into
* a box with a center at centerOffset and a maximum side
* length of one.
*/
void normalize(const Eigen::Vector3f& centerOffset);
/** Return true if the specified texture map type is used at
* all within a mesh. This information is used to decide
* if multiple rendering passes are required.
*/
bool usesTextureType(TextureSemantic) const;
/** Return true if the model has no translucent components. */
bool isOpaque() const
{
return opaque;
}
bool isNormalized() const
{
return normalized;
}
/*! Set the opacity flag based on material usage within the model */
void determineOpacity();
class MeshComparator
{
public:
virtual ~MeshComparator() = default;
virtual bool operator()(const Mesh&, const Mesh&) const = 0;
};
/*! Sort the model's meshes in place. */
void sortMeshes(const MeshComparator&);
/*! Optimize the model by eliminating all duplicated materials */
void uniquifyMaterials();
/*! This comparator will roughly sort the model's meshes by
* opacity so that transparent meshes are rendered last. It's far
* from perfect, but covers a lot of cases. A better method of
* opacity sorting would operate at the primitive group level, or
* even better at the triangle level.
*
* Standard usage for this class is:
* model->sortMeshes(Model::OpacityComparator());
*
* uniquifyMaterials() should be used before sortMeshes(), since
* the opacity comparison depends on material indices being ordered
* by opacity.
*/
class OpacityComparator : public MeshComparator
{
public:
OpacityComparator() = default;
virtual ~OpacityComparator() = default;
virtual bool operator()(const Mesh&, const Mesh&) const;
};
private:
std::vector<const Material*> materials;
std::vector<Mesh*> meshes;
std::array<bool, static_cast<std::size_t>(TextureSemantic::TextureSemanticMax)> textureUsage;
bool opaque{ true };
bool normalized{ false };
};
} // namespace