aboutsummaryrefslogtreecommitdiff
path: root/apps/openmb/scene/VoxelEditor.hpp
blob: a77f547bafed906ee5bf92993476a94c554be3d3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#ifndef OPENMB_APPS_OPENMB_SCENE_VOXELEDITOR_H
#define OPENMB_APPS_OPENMB_SCENE_VOXELEDITOR_H

#include <glm/glm.hpp>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>

namespace scene {
class GridSystem;

struct IVec3Hash {
    size_t operator()( const glm::ivec3& v ) const noexcept {
        uint32_t x = static_cast<uint32_t>( v.x );
        uint32_t y = static_cast<uint32_t>( v.y );
        uint32_t z = static_cast<uint32_t>( v.z );
        return (size_t)( ( x * 73856093u ) ^ ( y * 19349663u ) ^ ( z * 83492791u ) );
    }
};

struct IVec3Eq {
    bool operator()( const glm::ivec3& a, const glm::ivec3& b ) const noexcept {
        return a.x == b.x && a.y == b.y && a.z == b.z;
    }
};

class VoxelEditor {
  public:
    VoxelEditor( const GridSystem& gridSystem );
    ~VoxelEditor() = default;

    void processInput( const glm::vec3& rayOrigin, const glm::vec3& rayDir, bool leftMouseDown, bool rightMouseDown,
                       bool shiftPressed, const std::vector<std::pair<glm::vec3, glm::vec3>>& baseWorldBoxes,
                       int currentTextureId, bool placeCollidable );

    void applyCircularBrush( const glm::vec3& centerWorld, float radiusWorld, float heightWorld, int textureId,
                             bool placeCollidable );

    void undo();

    void redo();

    const std::vector<glm::ivec3>& getPlacedCells() const;

    const std::vector<glm::ivec3>& getPreviewCells() const;

    size_t getUndoStackSize() const;

    size_t getRedoStackSize() const;

    glm::ivec3 worldPosToCell( const glm::vec3& pos ) const;

    glm::vec3 cellToWorldCenter( const glm::ivec3& cell ) const;

    std::pair<glm::vec3, glm::vec3> cellToAABB( const glm::ivec3& cell ) const;

    std::vector<std::pair<glm::vec3, glm::vec3>>
    getAllCollisionBoxes( const std::vector<std::pair<glm::vec3, glm::vec3>>& baseWorldBoxes ) const;

    int getTextureIdForCell( const glm::ivec3& cell ) const;

    bool saveToFile( const std::string& filepath ) const;

    bool loadFromFile( const std::string& filepath );

    void clear();

    struct ModelInstance {
        int       modelIndex;
        glm::vec3 pos;
        float     yaw;
        float     scale;
        bool      mCollidable;
    };

    void                              addModelInstance( const ModelInstance& mi );
    const std::vector<ModelInstance>& getPlacedModels() const;

  private:
    struct VoxelData {
        glm::ivec3 mCell;
        int        mTextureId;
        bool       mCollidable;
    };

    struct Action {
        std::vector<VoxelData> mAddedCells;
        std::vector<VoxelData> mRemovedCells;
        struct ModelInstance {
            int       modelIndex;
            glm::vec3 pos;
            float     yaw;
            float     scale;
            bool      mCollidable;
        };
        std::vector<ModelInstance> mAddedModels;
        std::vector<ModelInstance> mRemovedModels;
    };

    bool rayAABBIntersect( const glm::vec3& ro, const glm::vec3& rd, const glm::vec3& bmin, const glm::vec3& bmax,
                           float& outT ) const;

    std::vector<glm::ivec3> rasterizeGridBox( const glm::ivec3& a, const glm::ivec3& b ) const;

    std::vector<glm::ivec3> rasterizeCircle( const glm::ivec3& centerCell, int radiusCells,
                                             int heightLayers ) const;

    const GridSystem& mGridSystem;

    std::unordered_set<glm::ivec3, IVec3Hash, IVec3Eq>       mPlacedSet;
    std::vector<glm::ivec3>                                  mPlacedList;
    std::unordered_map<glm::ivec3, int, IVec3Hash, IVec3Eq>  mCellTextureIds;
    std::unordered_map<glm::ivec3, bool, IVec3Hash, IVec3Eq> mCellCollidable;

    std::vector<Action>  mUndoStack;
    std::vector<Action>  mRedoStack;
    static constexpr int mMaxUndoSteps = 100;

    std::vector<ModelInstance> mPlacedModels;

    bool                    mDragging;
    int                     mDragButton;
    glm::ivec3              mDragStartCell;
    std::vector<glm::ivec3> mPreviewCells;

    bool mPrevLeftDown;
    bool mPrevRightDown;
};
}   // namespace scene

#endif