ICT290 / src / engine / modelManager.h
modelManager.h
Raw
#pragma once
#include <memory>
#include <string>
#include <vector>
#include "../glIncludes.h"
#include "glm/glm.hpp"
#include "textureManager.h"

#define MODEL_PATH_OBJ "../res/models/obj/"
#define MODEL_PATH_OFF "../res/models/off/"

/**
 * @struct VBOData
 * @brief Stores all VBO related data for a model.
 *
 * @author Chase Percy
 *
 */
struct VBOData {
    bool vboSafe{true};  /// True if a model has 3 vertices for every face and
                         /// a material
    GLsizei totalBytes{0};  /// The size of the vbo data
    GLuint vboID{0};        /// The vertex buffer ID
    GLuint iboID{0};        /// The index buffer ID
    GLuint nboID{0};        /// The normal buffer ID
    GLuint cboID{0};        /// The colour buffer ID
};

/**
 * @struct Face
 * @brief Contains all the data for a given face on a model.
 *
 * @author Chase Percy
 *
 */
struct Face {
    std::vector<std::size_t> vertIndices;  /// Vertex indices (f with no '/')
    std::vector<std::size_t>
        texCoordsIndices;  /// Texture coordinates (f with one '/')
    std::vector<std::size_t> normalIndices;  /// Normal indices (f with two '/')
    glm::vec3 colour;                        /// 0 - 255 stored in .r .g .b
    std::size_t materialID{0};  /// Id to associate to material index
    bool hasMaterial{false};    /// Flag for material or not
};

/**
 * @struct Material
 * @brief Contains all the material data for a single material from a mtl file.
 *
 * @author Chase Percy
 *
 */
struct Material {
    std::string name;     /// The name of the material (newmtl)
    float ambient[4];     /// The ambient colour, RGB (Ka)
    float diffuse[4];     /// The diffuse colour, RGB (Kd)
    float specular[4];    /// The specular colour and weighting, RGBW (Ks, Ns)
    float transparency;   /// The transparency values (d / Tr)
    std::string mapKD;    /// Name of the image to map to (texture)
    GLuint textureID{0};  /// Texture id for this material, 0 if none.
};

/**
 * @struct Mesh
 * @brief Contains all the raw mesh data for a model.
 *
 * @warning All data stored is not homogenous.
 *
 * @author Chase Percy
 *
 */
struct Mesh {
    // NON-HOMOGENOUS
    std::vector<glm::vec3> verts;              /// Vertex data (v)
    std::vector<glm::vec2> texCoords;          /// Texture Coordinates (vt)
    std::vector<glm::vec3> normals;            /// Normal data (vn)
    std::vector<glm::vec3> psVerts;            /// Polygonal Face element (vp)
    std::vector<std::shared_ptr<Face>> faces;  /// Face data (f)
    std::vector<std::size_t> lineElements;     /// Line element data (l)
    std::vector<std::shared_ptr<Material>> material;  /// Material data (newmtl)
};

struct BoundingSphere {
    glm::vec3 centre{0};     /// The centre of the model
    glm::vec3 centreNoY{0};  /// The centre of the model with Y at 0
    float radius{0};         /// The Max radius of the model
    float radiusAverage{0};  /// The average radius of the model
    float radiusNoY{0};      /// The max radius of the model, x & z only
};

/**
 * @class Model
 * @brief A class that contains all the data for a model as well as the
 * functions for it to draw itself. The draw function will internally decide if
 * the model will be drawn in immediate or retained mode rendering.
 *
 * @author Chase Percy
 *
 */
class Model {
   public:
    std::size_t ID;    /// ID of the model (location in the vector)
    std::string name;  /// Name of the model (filename with  pathing/extension)
    std::string subPath;  /// Sub path from ..res/models/obj (used for material)
    Mesh mesh;            /// Mesh data for the model
    VBOData vboData;      /// VBO data for the model
    BoundingSphere boundingSphere;  /// The bounding sphere for the model

    /**
     * Draws a model, applies its colour or texture if applicable.
     */
    void draw() const;

   private:
    /**
     * The classic mode of drawing where all data is passed to the gpu each
     * frame. Called if a model has VBOSafe defined as false. (HEAVY PERFORMANCE
     * OVERHEAD)
     */
    void immediateModeDraw() const;

    /**
     * The newer mode of drawing where all data is uploaded to the GPU before
     * runtime so that it can be called internally each frame without being
     * uploaded. Called if a model has VBOSafe defined as true.
     */
    void retainedModeDraw() const;
};

/**
 * @class ModelManager
 * @brief Managers a set of models. Loads a set of models from a txt and stores
 * them internally, providing them when requested. Sorts the VBO data for all
 * its models once they have all been loaded from the txt.
 *
 * @author Chase Percy
 *
 */
class ModelManager {
   public:
    /**
     * Pre loads models from the res/preload/models.txt file. All models must
     * load from the preload list to return true and allow the engine to start.
     * @param modelPreloadPath the path to the file to preload from.
     * @return true if all preloads are successful, false otherwise.
     */
    bool init(const std::string& modelPreloadPath);

    /**
     * Loads a model with the filename given, file must be stored in res/models
     * @param fName the filename of the model to load
     * @return the pointer to the model, else nullptr.
     */
    std::shared_ptr<Model> load(const std::string& fName);

    /**
     * Returns a model based on its ID
     * @param ID the ID of the model to retrieve
     * @return A pointer to the model, else nullptr.
     */
    std::shared_ptr<Model> getModel(std::size_t ID);

    /**
     * Returns a model based on its ID
     * @param name the name of the model to retrieve, i.e. the filename.
     * @return a pointer to the model if found, else nullptr.
     */
    std::shared_ptr<Model> getModel(const std::string& name);

    /**
     * Finds the bounding sphere for a model at its initial scale.
     */
    void findBoundingSpheres();

   private:
    std::vector<std::shared_ptr<Model>>
        m_models;  /// All currently loaded models

    /*
     * Creates VBO's for model who meet the requirement and stores the assigned
     * ID's within the models VBOData struct.
     */
    void VBOSort();
};

/**
 * @namespace OBJ_LOADER
 * @brief A namespace that contains a function to load a model from a obj file.
 *
 * @author Chase Percy
 *
 */
namespace OBJ_LOADER {
    /**
     * Loads an obj file and stores it into a model.
     * @param fName the name of the obj file to open
     * @return the shared ptr to the model with all loaded data, else nullptr if
     * failed to load
     */
    std::shared_ptr<Model> load(const std::string& fName);
}  // namespace OBJ_LOADER

/**
 * @namespace OFF_LOADER
 * @brief A namespace that contains a function to load a model from a off file.
 *
 * @author Chase Percy
 *
 */
namespace OFF_LOADER {
    /**
     * Loads an off file and stores it into a model.
     * @param fName the name of the off file to open
     * @return the shared ptr to the model with all loaded data, else nullptr if
     * failed to load
     */
    std::shared_ptr<Model> load(const std::string& fName);
}  // namespace OFF_LOADER

/**
 * @namespace MTL_LOADER
 * @brief A namespace that contains a function to load a model from a mtl file.
 *
 * @author Chase Percy
 *
 */
namespace MTL_LOADER {
    /**
     * Loads an mtl file and stores it into a model. Takes model as a parameter
     * since multiple materials can be stored in one mtl file.
     * @param fName the name of the mtl file to open
     * @param model the model to load the mtl data into.
     */
    void load(const std::string& fName, std::shared_ptr<Model>& model);
}  // namespace MTL_LOADER