1 module nudge_ext; 2 3 import core.memory; 4 import core.stdc.string : memset; 5 static import nudge; 6 7 /// represents a context for nudge 8 class NudgeRealm { 9 public const(uint) max_bodies; 10 public const(uint) max_boxes; 11 public const(uint) max_spheres; 12 13 public size_t arena_size = 64 * 1024 * 1024; // 64M 14 15 public enum float[3] zero_vec = [0, 0, 0]; 16 public enum nudge.Transform identity_transform = nudge.Transform([0, 0, 0], 17 0, [0.0f, 0.0f, 0.0f, 1.0f]); 18 public enum nudge.BodyMomentum zero_momentum = nudge.BodyMomentum(zero_vec, 0, zero_vec, 0); 19 20 public nudge.Arena arena; 21 public nudge.BodyData bodies; 22 public nudge.ColliderData colliders; 23 public nudge.ContactData contact_data; 24 public nudge.ContactCache contact_cache; 25 public nudge.ActiveBodies active_bodies; 26 27 /// initializes a nudge realm with the given maximums 28 this(uint max_bodies, uint max_boxes, uint max_spheres) { 29 assert(max_boxes <= max_bodies, "boxes exceeds max body count"); 30 assert(max_spheres <= max_bodies, "spheres exceeds max body count"); 31 32 this.max_bodies = max_bodies; 33 this.max_boxes = max_boxes; 34 this.max_spheres = max_spheres; 35 } 36 37 /// allocate memory for nudge 38 public void allocate() { 39 // Allocate memory for simulation arena. 40 arena.size = arena_size; 41 arena.data = GC.malloc(arena.size); 42 43 // Allocate memory for bodies, colliders, and contacts. 44 active_bodies.capacity = max_bodies; 45 active_bodies.indices = new ushort[max_bodies].ptr; 46 47 bodies.idle_counters = new ubyte[max_bodies].ptr; 48 bodies.transforms = new nudge.Transform[max_bodies].ptr; 49 bodies.momentum = new nudge.BodyMomentum[max_bodies].ptr; 50 bodies.properties = new nudge.BodyProperties[max_bodies].ptr; 51 52 colliders.boxes.data = new nudge.BoxCollider[max_boxes].ptr; 53 colliders.boxes.tags = new uint[max_boxes].ptr; 54 colliders.boxes.transforms = new nudge.Transform[max_boxes].ptr; 55 56 colliders.spheres.data = new nudge.SphereCollider[max_spheres].ptr; 57 colliders.spheres.tags = new uint[max_spheres].ptr; 58 colliders.spheres.transforms = new nudge.Transform[max_spheres].ptr; 59 60 contact_data.capacity = max_bodies * 64; 61 contact_data.bodies = new nudge.BodyPair[contact_data.capacity].ptr; 62 contact_data.data = new nudge.Contact[contact_data.capacity].ptr; 63 contact_data.tags = new ulong[contact_data.capacity].ptr; 64 contact_data.sleeping_pairs = new uint[contact_data.capacity].ptr; 65 66 contact_cache.capacity = max_bodies * 64; 67 contact_cache.data = new nudge.CachedContactImpulse[contact_cache.capacity].ptr; 68 contact_cache.tags = new ulong[contact_cache.capacity].ptr; 69 } 70 71 public void destroy() { 72 // free the arena data, because we used malloc() 73 GC.free(arena.data); 74 } 75 76 pragma(inline) { 77 /// append a new body, return the id 78 public uint append_body(nudge.Transform transform, 79 nudge.BodyProperties properties, nudge.BodyMomentum momentum) { 80 if (bodies.count >= max_bodies) { 81 assert(0, "max body count exceeded"); 82 } 83 84 uint id = bodies.count++; 85 86 bodies.transforms[id] = transform; 87 bodies.properties[id] = properties; 88 bodies.momentum[id] = momentum; 89 bodies.idle_counters[id] = 0; 90 91 return id; 92 } 93 94 /// pop the last body off 95 public void pop_last_body() { 96 bodies.count--; 97 } 98 99 /// clear the data of a body with matching id 100 public void clear_body(uint id) { 101 // zero out the body 102 bodies.transforms[id] = identity_transform; 103 memset(&bodies.properties[id], 0, bodies.properties[id].sizeof); 104 memset(&bodies.momentum[id], 0, bodies.momentum[id].sizeof); 105 bodies.idle_counters[id] = 0; 106 } 107 108 /// swap two bodies given their indices 109 public void swap_bodies(uint id_src, uint id_dst) { 110 auto tmp_transform = bodies.transforms[id_dst]; 111 bodies.transforms[id_dst] = bodies.transforms[id_src]; 112 bodies.transforms[id_src] = tmp_transform; 113 114 auto tmp_props = bodies.properties[id_dst]; 115 bodies.properties[id_dst] = bodies.properties[id_src]; 116 bodies.properties[id_src] = tmp_props; 117 118 auto tmp_momentum = bodies.momentum[id_dst]; 119 bodies.momentum[id_dst] = bodies.momentum[id_src]; 120 bodies.momentum[id_src] = tmp_momentum; 121 122 auto tmp_idle = bodies.idle_counters[id_dst]; 123 bodies.idle_counters[id_dst] = bodies.idle_counters[id_src]; 124 bodies.idle_counters[id_src] = tmp_idle; 125 } 126 127 /// append a box collider and get its index 128 public uint append_box_collider(uint body_id, nudge.BoxCollider collider, 129 nudge.Transform transform, uint tag = 0) { 130 if (colliders.boxes.count >= max_boxes) { 131 assert(0, "max body count exceeded (boxes)"); 132 } 133 134 uint box_id = colliders.boxes.count++; 135 136 colliders.boxes.tags[box_id] = tag; 137 colliders.boxes.data[box_id] = collider; 138 colliders.boxes.transforms[box_id] = transform; 139 colliders.boxes.transforms[box_id].body = body_id; 140 141 return box_id; 142 } 143 144 /// zero the data of a box collider index 145 public void clear_box_collider(uint id) { 146 colliders.boxes.tags[id] = 0; 147 memset(&colliders.boxes.data[id], 0, colliders.boxes.data[id].sizeof); 148 memset(&colliders.boxes.transforms[id], 0, colliders.boxes.transforms[id].sizeof); 149 } 150 151 /// swap two box colliders given their indices 152 public void swap_box_colliders(uint id_src, uint id_dst) { 153 auto tmp_transform = colliders.boxes.transforms[id_dst]; 154 colliders.boxes.transforms[id_dst] = colliders.boxes.transforms[id_src]; 155 colliders.boxes.transforms[id_src] = tmp_transform; 156 157 auto tmp_data = colliders.boxes.data[id_dst]; 158 colliders.boxes.data[id_dst] = colliders.boxes.data[id_src]; 159 colliders.boxes.data[id_src] = tmp_data; 160 161 auto tmp_tag = colliders.boxes.tags[id_dst]; 162 colliders.boxes.tags[id_dst] = colliders.boxes.tags[id_src]; 163 colliders.boxes.tags[id_src] = tmp_tag; 164 } 165 166 /// pop the last box collider off 167 public void pop_last_box_collider() { 168 colliders.boxes.count--; 169 } 170 171 /// append a sphere collider and get its index 172 public uint append_sphere_collider(uint body_id, 173 nudge.SphereCollider collider, nudge.Transform transform, uint tag = 0) { 174 if (colliders.spheres.count >= max_spheres) { 175 assert(0, "max body count exceeded (spheres)"); 176 } 177 178 uint sphere_id = colliders.spheres.count++; 179 180 colliders.spheres.tags[sphere_id] = tag; 181 colliders.spheres.data[sphere_id] = collider; 182 colliders.spheres.transforms[sphere_id] = transform; 183 colliders.spheres.transforms[sphere_id].body = body_id; 184 185 return sphere_id; 186 } 187 188 /// zero the data of a sphere collider index 189 public void clear_sphere_collider(uint id) { 190 colliders.spheres.tags[id] = 0; 191 memset(&colliders.spheres.data[id], 0, colliders.spheres.data[id].sizeof); 192 memset(&colliders.spheres.transforms[id], 0, colliders.spheres.transforms[id].sizeof); 193 } 194 195 /// swap two sphere colliders given their indices 196 public void swap_sphere_colliders(uint id_src, uint id_dst) { 197 auto tmp_transform = colliders.spheres.transforms[id_dst]; 198 colliders.spheres.transforms[id_dst] = colliders.spheres.transforms[id_src]; 199 colliders.spheres.transforms[id_src] = tmp_transform; 200 201 auto tmp_data = colliders.spheres.data[id_dst]; 202 colliders.spheres.data[id_dst] = colliders.spheres.data[id_src]; 203 colliders.spheres.data[id_src] = tmp_data; 204 205 auto tmp_tag = colliders.spheres.tags[id_dst]; 206 colliders.spheres.tags[id_dst] = colliders.spheres.tags[id_src]; 207 colliders.spheres.tags[id_src] = tmp_tag; 208 } 209 210 /// pop the last sphere collider off 211 public void pop_last_sphere_collider() { 212 colliders.spheres.count--; 213 } 214 } 215 } 216 217 unittest { 218 // try setting one up 219 220 auto realm = new NudgeRealm(64, 64, 64); 221 222 realm.allocate(); 223 realm.destroy(); 224 }