summaryrefslogtreecommitdiff
path: root/src/KingSystem/Physics/System/physContactLayerCollisionInfoGroup.h
blob: 69f0bbec49d871677aa17fba89848008865d2f45 (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
#pragma once

#include <container/seadBuffer.h>
#include <container/seadListImpl.h>
#include <container/seadPtrArray.h>
#include <prim/seadNamable.h>
#include "KingSystem/Physics/physDefines.h"

namespace ksys::phys {

struct CollidingBodies;
class ContactLayerCollisionInfo;

/// Container for ContactLayerCollisionInfo instances that pertain to a contact layer
/// paired with other layers.
class ContactLayerCollisionInfoGroup : public sead::INamable {
public:
    class CollidingBodiesIterator;
    struct CollidingBodiesRange;

    struct LayerInfo {
        ContactLayer layer;
        /// Is `layer` greater than the layer of the group?
        bool layer_gt;
        /// Is `layer` lower or equal to the layer of the group?
        bool layer_le;
    };

    static ContactLayerCollisionInfoGroup* make(sead::Heap* heap, ContactLayer layer, int capacity,
                                                const sead::SafeString& name);
    static void free(ContactLayerCollisionInfoGroup* group);

    ContactLayerCollisionInfoGroup(ContactLayer layer, const sead::SafeString& name);
    virtual ~ContactLayerCollisionInfoGroup();

    /// @param capacity The maximum number of layers that can be added to this group.
    void init(sead::Heap* heap, int capacity);
    void finalize();

    /// Add (mLayer, layer) to the list of layer pairs in this group.
    void addLayer(ContactLayer layer);

    /// Call this to ensure that all layer pairs in this group are being tracked by
    /// the relevant contact listener. This may be necessary if the listener has been reset.
    void ensureLayersAreTracked();

    CollidingBodiesIterator collidingBodiesBegin() const;
    CollidingBodiesIterator collidingBodiesEnd() const;
    CollidingBodiesRange getCollidingBodies() const;

    const sead::PtrArray<ContactLayerCollisionInfo>& getCollisionInfo() const {
        return mCollisionInfoInstances;
    }

    static constexpr size_t getListNodeOffset() {
        return offsetof(ContactLayerCollisionInfoGroup, mListNode);
    }

private:
    ContactLayer mLayer;
    sead::PtrArray<ContactLayerCollisionInfo> mCollisionInfoInstances;
    sead::Buffer<LayerInfo> mLayers;
    sead::ListNode mListNode;
};

class ContactLayerCollisionInfoGroup::CollidingBodiesIterator {
public:
    enum class IsStart : bool { Yes = true, No = false };

    CollidingBodiesIterator(const ContactLayerCollisionInfoGroup* group, int index, IsStart start);
    ~CollidingBodiesIterator();

    const LayerInfo& getLayerInfo() const { return mGroup->mLayers[mInfoIndex]; }

    const CollidingBodies& operator*() const { return *mCollidingBodiesEntry; }
    const CollidingBodies* operator->() const { return mCollidingBodiesEntry; }
    CollidingBodiesIterator& operator++();

    bool operator==(const CollidingBodiesIterator& other) const {
        return mInfoIndex == other.mInfoIndex &&
               mCollidingBodiesEntry == other.mCollidingBodiesEntry;
    }

    bool operator!=(const CollidingBodiesIterator& other) const { return !operator==(other); }

private:
    void initIterator(const ContactLayerCollisionInfoGroup* group);

    const ContactLayerCollisionInfoGroup* mGroup{};
    ContactLayerCollisionInfo* mInfo{};
    /// The current CollidingBodies pair within the current ContactLayerCollisionInfo (mInfo).
    const CollidingBodies* mCollidingBodiesEntry{};
    int mInfoIndex{};
};

struct ContactLayerCollisionInfoGroup::CollidingBodiesRange {
    auto begin() const { return group->collidingBodiesBegin(); }
    auto end() const { return group->collidingBodiesEnd(); }

    const ContactLayerCollisionInfoGroup* group;
};

inline ContactLayerCollisionInfoGroup::CollidingBodiesIterator
ContactLayerCollisionInfoGroup::collidingBodiesBegin() const {
    return {this, 0, CollidingBodiesIterator::IsStart::Yes};
}

inline ContactLayerCollisionInfoGroup::CollidingBodiesIterator
ContactLayerCollisionInfoGroup::collidingBodiesEnd() const {
    return {this, mCollisionInfoInstances.size(), CollidingBodiesIterator::IsStart::No};
}

inline ContactLayerCollisionInfoGroup::CollidingBodiesRange
ContactLayerCollisionInfoGroup::getCollidingBodies() const {
    return {this};
}

}  // namespace ksys::phys