ICT290 / src / scene / theArchanist / map / gameRoom.h
gameRoom.h
Raw
#pragma once

#include <glm/glm.hpp>
#include <map>
#include <memory>
#include <random>
#include "../../../engine/resources.h"

const float GR_OBJ_SCALE{0.5f};      /// Object scale reduction from blender 1x1
const float GR_WALL_OFFSET{0.425f};  /// Wall offset to line up no edge of floor
const float GR_CORNER_OFFSET{0.5f};  /// Corner offset for floor from walls
#define GR_ENTITY_FLOOR "EntityF_"
#define GR_ENTITY_WALL "EntityW_"
#define GR_FLOOR "Floor_"
#define GR_DOOR "Door_"
#define GR_WALL "Wall_"
#define GR_ROTATION "Rotation_"

/**
 * @class gameRoom
 * @brief A class to create a room according to a size, location, and models.
 *
 * @author Chase Percy
 *
 */
class gameRoom {
   public:
    struct RoomModels {
        std::vector<std::shared_ptr<Model>> floors;
        std::vector<std::shared_ptr<Model>> walls;
        std::shared_ptr<Model> debugCube{nullptr};
        std::shared_ptr<Model> debugSphere{nullptr};
    };

    /**
     * Generates a room given a x,z, an origin (bottom left), and a set of
     * models
     * @param x the size of the room on the x axis
     * @param z the size of the room on the z axis
     * @param wallFillPercent The percent of the walls to fill with decorations
     * @param floors the floors for the room, the first element is the default
     * floor
     * @param floorFillPercent The percent of the floor to fill with decoration.
     * @param xOrigin the x origin of the room
     * @param zOrigin the z origin of the room
     * @param roomModels the models for the room
     * @param seed the seed for room generation
     *
     */
    gameRoom(int x,
             int z,
             int wallFillPercent,
             int floorFillPercent,
             int xOrigin,
             int zOrigin,
             const RoomModels& roomModels,
             int seed,
             const std::vector<std::pair<int, int>>& doors);

    ~gameRoom();

    gameRoom() = delete;

    gameRoom(const gameRoom& other);

    gameRoom& operator=(const gameRoom&);

    /**
     * Returns all the wall points for the room
     * @return wall points
     */
    const std::vector<std::vector<glm::vec3>>& getWallPoints() const;

    /**
     * Returns all bounding spheres for entities in the room
     * @return bounding spheres
     */
    const std::vector<std::pair<glm::vec3, float>>& getBoundingSpheres() const;

    glm::vec3 getMin() const;

    glm::vec3 getMax() const;

    /**
     * Draw all objects that represent a room.
     */
    void draw();

    /**
     * Draw all debug data for wall points and bounding spheres.
     */
    void drawDebug();

    /**
     * Returns the coordinates at the centre of the room (used for draw
     * distance)
     * @return the coords at centre of room
     */
    glm::vec3 getLocation() const;

   private:
    struct Dimension {
        int xMax{0};
        int zMax{0};
        int max{0};
    };

    struct Normals {
        glm::vec3 negX{-1, 0, 0};
        glm::vec3 posX{1, 0, 0};
        glm::vec3 negZ{0, 0, -1};
        glm::vec3 posZ{0, 0, 1};
    };

    struct Offset {
        int xMin{0};
        int zMin{0};
        int xMax{0};
        int zMax{0};
        int xCent{0};
        int zCent{0};
    };

    enum accessTypes { wall, floor, empty, floorEntity, wallEntity, door };

    enum direction {
        NaD = -1,
        negZ,
        negX,
        posZ,
        posX
    };  /// NaD is used to represent an invalid direction

    accessTypes* m_accessible{
        nullptr};  /// Array of accessible cells in the room
    std::vector<std::vector<glm::vec3>>
        m_wallPoints{};  /// the wall points for the room
    std::vector<std::pair<glm::vec3, float>>
        m_entityBoundingSpheres{};  /// The bounding spheres of the room's
                                    /// entities
    Dimension m_floor;              /// the dimensions of the floor
    Dimension m_wall;               /// the dimensions of the floor + walls
    Dimension m_dimensions;         /// The dimensions of the room
    Offset m_offset;                /// The offsets for the room
    Normals m_normals;              /// A predefined set of normals to copy
    RoomModels m_models;            /// the models for the room to use
    std::map<std::string, Object> m_objects{};  /// The objects for this room
    bool m_debugData{
        false};  /// Tracks if debug data has been generated or not.
    std::vector<Object> m_debugObjects{};  /// The debug objects fro this room
    int m_seed;                            /// The seed for the room
    int m_randomRotationOffset{0};         /// Offset for random rotations
    std::map<std::string, float> m_rotationAngles;
    std::vector<std::pair<int, int>> m_doors;

    /**
     * Creates a room as specified by the x & z values in the constructor.
     */
    void createRoom();

    /**
     * Creates a wall at a given location
     * @param row the row to create the wall
     * @param col the col to create the wall
     * @param model the model to create the wall as
     */
    void createWallType(int row,
                        int col,
                        std::shared_ptr<Model>& model,
                        accessTypes accessType);

    /**
     * Creates a floor type at a given location
     * @param row the row to create the floor
     * @param col the col to create the floor
     * @param model the model to create the floor as
     * @param accessType the type of floor (entity or standard) being created
     */
    void createFloorType(int row,
                         int col,
                         std::shared_ptr<Model>& model,
                         accessTypes accessType);

    /**
     * Checks if a element at row,col is a wall.
     * @param row the row to check
     * @param col the col to check
     * @return true if a wall, else false
     */
    bool isWall(int row, int col) const;

    /**
     * Checks if a element is a corner
     * @param row the row to check
     * @param col the col to check
     * @return true if a corner, else false
     */
    bool isCorner(int row, int col) const;

    /**
     * Adds decoration to the room up to the fillPercent's
     * @param floorPercent the amount of the floors to fill
     * @param wallPercent the amount of the walls to fill
     */
    void addDecoration(float floorPercent, float wallPercent);

    /**
     * Returns a 0, 90, 180, 270 angle randomly
     * @return an angle
     */
    float randomRotation();

    /**
     * returns an integer representing an enum in direction based on the walls
     * position.
     * @param row the row to check
     * @param col the col to check
     * @return the walls direction enum
     */
    direction wallPosition(int row, int col) const;

    /**
     * Update a wall points location so that it aligns properly with the offset
     * @param location the wall location to update
     * @param wallPos the current wall direction enum
     */
    void updateWallPointLocation(glm::vec3& location, direction wallPos) const;

    /**
     * Gets a normal for a wall based on its current wall direction enum
     * @param wallPos the wall direction enum
     * @return the normal for the wall
     */
    glm::vec3 getNormal(direction wallPos) const;

    /**
     * Gets the index based on row and col for the accessible array
     * @param row the row to find
     * @param col the col to find
     * @return the index
     */
    std::size_t getIndex(int row, int col) const;

    /**
     * Generates the wall points for the room
     */
    void generateWallPoints();

    /**
     * Inserts the wall points into the wall vector based on their direction and
     * position.
     * @param row the row to check for a wall
     * @param col the col to check for a wall
     * @param wall the wall vector
     * @param pOneInserted if the first point has been inserted
     * @param wallCount the number of wall accessTypes connected to the wall
     * @param dir the location of the wall
     */
    void insertWallPoints(int row,
                          int col,
                          std::vector<glm::vec3>& wall,
                          bool& pOneInserted,
                          int& wallCount,
                          direction dir);

    /**
     * Creates the bounding sphere objects for the entities in the scene
     */
    void generateEntityBoundingSpheres();

    /**
     * Create all debug objects.
     */
    void generateDebugData();

    /**
     * Set the door locations for the room
     */
    void setDoors();

    /**
     * Make sure that doors arent blocked and that there is a way to get to each
     * wall.
     * @param start the starting location to walk from.
     * @param doorAxis the axis the door is aligned with
     */
    void walkRoom(std::pair<int, int> start, direction doorAxis);

    /**
     * Checks if a position in m_accessible is a floor type
     * @param row the row to check
     * @param col the col to check
     * @return true if floor type, else false.
     */
    bool isFloor(int row, int col) const;

    /**
     * Checks if a position in m_accessible is a floor entity type
     * @param row the row to check
     * @param col the col to check
     * @return true if floor entity type, else false.
     */
    bool isFloorEntity(int row, int col) const;

    /**
     * Removes a floor entity at row & col and replaces it with a floor type.
     * @param row the row to remove it from
     * @param col the col to remove it from
     */
    void removeFloorEntity(int row, int col);

    /**
     * Updates the walking position for the walkRoom function based on the
     * direction the door started at.
     * @param walking the walking variable to update
     * @param dir the direction the door started at
     */
    void updateWalking(int& walking, direction dir);

    /**
     * Sets the strafe start and end variable in the walkRoom function.
     * @param strafe The strafe variable to set
     * @param strafeEnd The strafe end variable to set
     * @param dir The direction of the door
     * @param row The current row
     * @param col The current col
     */
    void setStrafe(int& strafe,
                   int& strafeEnd,
                   direction dir,
                   int row,
                   int col) const;

    /**
     * Checks if the strafe position is colliding with any entities at its
     * current position or current position + 1 in the walking direction.
     * @param strafe The current strafe position
     * @param dir The direction of the door
     * @param row The current row
     * @param col The current col
     * @return {true, true} if next position is valid. {true, false} if strafe
     * position is valid but walk position is not. {false, false} is strafe
     * position isn't valid.
     */
    std::pair<bool, bool> checkStrafeCollision(int strafe,
                                               direction dir,
                                               int& row,
                                               int& col) const;

    /**
     * Moves the row and col values forward based on the door location.
     * @param row the row to increase/decrease.
     * @param col the col to increase/decrease.
     * @param dir The direction of the door.
     */
    void walkForward(int& row, int& col, direction dir);

    /**
     * Set the starting & ending points for the walking variables based on the
     * doors direction.
     * @param start The starting spot for walking
     * @param end The ending spot for walking
     * @param dir The direction of the door
     */
    void setWalkingStart(int& start, int& end, direction dir);
};