1 /********************************************************************************
2 * ReactPhysics3D physics library, http://www.reactphysics3d.com                 *
3 * Copyright (c) 2010-2020 Daniel Chappuis                                       *
4 *********************************************************************************
5 *                                                                               *
6 * This software is provided 'as-is', without any express or implied warranty.   *
7 * In no event will the authors be held liable for any damages arising from the  *
8 * use of this software.                                                         *
9 *                                                                               *
10 * Permission is granted to anyone to use this software for any purpose,         *
11 * including commercial applications, and to alter it and redistribute it        *
12 * freely, subject to the following restrictions:                                *
13 *                                                                               *
14 * 1. The origin of this software must not be misrepresented; you must not claim *
15 *    that you wrote the original software. If you use this software in a        *
16 *    product, an acknowledgment in the product documentation would be           *
17 *    appreciated but is not required.                                           *
18 *                                                                               *
19 * 2. Altered source versions must be plainly marked as such, and must not be    *
20 *    misrepresented as being the original software.                             *
21 *                                                                               *
22 * 3. This notice may not be removed or altered from any source distribution.    *
23 *                                                                               *
24 ********************************************************************************/
25 
26 // Libraries
27 #include <reactphysics3d/components/Components.h>
28 #include <cassert>
29 
30 // We want to use the ReactPhysics3D namespace
31 using namespace reactphysics3d;
32 
33 // Constructor
Components(MemoryAllocator & allocator,size_t componentDataSize)34 Components::Components(MemoryAllocator& allocator, size_t componentDataSize)
35     : mMemoryAllocator(allocator), mNbComponents(0), mComponentDataSize(componentDataSize),
36       mNbAllocatedComponents(0), mBuffer(nullptr), mMapEntityToComponentIndex(allocator),
37       mDisabledStartIndex(0) {
38 
39 }
40 
~Components()41 Components::~Components() {
42 
43     // If there are allocated components
44     if (mNbAllocatedComponents > 0) {
45 
46         // Destroy all the remaining components
47         for (uint32 i = 0; i < mNbComponents; i++) {
48 
49             destroyComponent(i);
50         }
51 
52         // Size for the data of a single component (in bytes)
53         const size_t totalSizeBytes = mNbAllocatedComponents * mComponentDataSize;
54 
55         // Release the allocated memory
56         mMemoryAllocator.release(mBuffer, totalSizeBytes);
57     }
58 }
59 
60 // Compute the index where we need to insert the new component
prepareAddComponent(bool isSleeping)61 uint32 Components::prepareAddComponent(bool isSleeping) {
62 
63     // If we need to allocate more components
64     if (mNbComponents == mNbAllocatedComponents) {
65         allocate(mNbAllocatedComponents * 2);
66     }
67 
68     uint32 index;
69 
70     // If the component to add is part of a disabled entity or there are no disabled entity
71     if (isSleeping) {
72 
73         // Add the component at the end of the array
74         index = mNbComponents;
75     }
76     // If the component to add is not part of a disabled entity
77     else {
78 
79         // If there already are disabled components
80         if (mDisabledStartIndex != mNbComponents) {
81 
82             // Move the first disabled component to the end of the array
83             moveComponentToIndex(mDisabledStartIndex, mNbComponents);
84         }
85 
86         index = mDisabledStartIndex;
87 
88         mDisabledStartIndex++;
89     }
90 
91     return index;
92 }
93 
94 // Destroy a component at a given index
destroyComponent(uint32 index)95 void Components::destroyComponent(uint32 index) {
96 
97     assert(index < mNbComponents);
98 }
99 
100 // Remove a component at a given index
removeComponent(Entity entity)101 void Components::removeComponent(Entity entity) {
102 
103     assert(mMapEntityToComponentIndex.containsKey(entity));
104 
105     uint index = mMapEntityToComponentIndex[entity];
106 
107     assert(index < mNbComponents);
108 
109     // We want to keep the arrays tightly packed. Therefore, when a component is removed,
110     // we replace it with the last element of the array. But we need to make sure that enabled
111     // and disabled components stay grouped together.
112 
113     // Destroy the component
114     destroyComponent(index);
115 
116     // If the component to remove is disabled
117     if (index >= mDisabledStartIndex) {
118 
119         // If the component is not the last one
120         if (index != mNbComponents - 1) {
121 
122             // We replace it by the last disabled component
123             moveComponentToIndex(mNbComponents - 1, index);
124         }
125     }
126     else {   // If the component to remove is enabled
127 
128         // If it not the last enabled component
129         if (index != mDisabledStartIndex - 1) {
130 
131             // We replace it by the last enabled component
132             moveComponentToIndex(mDisabledStartIndex - 1, index);
133         }
134 
135         // If there are disabled components at the end
136         if (mDisabledStartIndex != mNbComponents) {
137 
138             // We replace the last enabled component by the last disabled component
139             moveComponentToIndex(mNbComponents - 1, mDisabledStartIndex - 1);
140         }
141 
142         mDisabledStartIndex--;
143     }
144 
145     mNbComponents--;
146 
147     assert(mDisabledStartIndex <= mNbComponents);
148     assert(mNbComponents == static_cast<uint32>(mMapEntityToComponentIndex.size()));
149 }
150 
151 // Notify if a given entity is disabled (sleeping) or not
setIsEntityDisabled(Entity entity,bool isDisabled)152 void Components::setIsEntityDisabled(Entity entity, bool isDisabled) {
153 
154     const uint32 index = mMapEntityToComponentIndex[entity];
155 
156     // If the component was disabled and is not disabled anymore
157     if (!isDisabled && index >= mDisabledStartIndex) {
158 
159         assert(mDisabledStartIndex < mNbComponents);
160 
161         // If the disabled component is not the first disabled component
162         if (mDisabledStartIndex != index) {
163 
164             // Swap the first disabled component with the one we need to enable it
165             swapComponents(index, mDisabledStartIndex);
166         }
167 
168         mDisabledStartIndex++;
169     }
170     // If the component was enabled and must now be disabled
171     else if (isDisabled && index < mDisabledStartIndex) {
172 
173         assert(mDisabledStartIndex > 0);
174 
175         // If the enabled component is not the only enabled component
176         if (index != mDisabledStartIndex - 1) {
177 
178             // Swap the last enabled component with the one we need to disable
179             swapComponents(index, mDisabledStartIndex - 1);
180         }
181 
182         mDisabledStartIndex--;
183     }
184 
185     assert(mDisabledStartIndex <= mNbComponents);
186     assert(mNbComponents == static_cast<uint32>(mMapEntityToComponentIndex.size()));
187 }
188