1 module game_core.collision; 2 3 import bubel.ecs.attributes; 4 import bubel.ecs.block_allocator; 5 import bubel.ecs.core; 6 import bubel.ecs.std; 7 import bubel.ecs.vector; 8 9 import ecs_utils.math.vector; 10 import ecs_utils.utils; 11 12 import game_core.basic; 13 14 import gui.attributes; 15 16 void registerCollisionModule(EntityManager* manager) 17 { 18 manager.registerDependency(ShootGridDependency); 19 manager.registerDependency(BVHDependency); 20 manager.registerDependency(StaticBVHDependency); 21 22 manager.registerComponent!CShootGrid; 23 manager.registerComponent!CShootGridMask; 24 manager.registerComponent!CColliderScale; 25 manager.registerComponent!CBVH; 26 manager.registerComponent!CAABB; 27 manager.registerComponent!CStatic; 28 29 manager.registerSystem!ShootGridManager(-80); 30 manager.registerSystem!ShootGridCleaner(-101); 31 manager.registerSystem!BVHBuilder(-80); 32 manager.registerSystem!StaticBVHBuilder(-80); 33 //manager.registerSystem!BVHBuilder2(-79); 34 manager.registerSystem!AABBUpdater(-81); 35 } 36 37 enum ShootGridDependency = "ShootGridDependency"; 38 enum BVHDependency = "BVHDependency"; 39 enum StaticBVHDependency = "StaticBVHDependency"; 40 41 struct CShootGrid 42 { 43 mixin ECS.Component; 44 } 45 46 struct CBVH 47 { 48 mixin ECS.Component; 49 50 @GUIDisabled uint index; 51 } 52 53 struct CAABB 54 { 55 mixin ECS.Component; 56 57 alias bounding this; 58 59 AABB bounding; 60 } 61 62 struct CShootGridMask 63 { 64 mixin ECS.Component; 65 66 alias value this; 67 68 @GUIDisabled ubyte value; 69 } 70 71 struct CColliderScale 72 { 73 mixin ECS.Component; 74 75 alias value this; 76 77 vec2 value = vec2(16,16); 78 } 79 80 81 struct ShootGrid 82 { 83 84 ~this() @nogc nothrow 85 { 86 if(nodes)Mallocator.dispose(nodes); 87 if(masks)Mallocator.dispose(masks); 88 } 89 90 struct Node 91 { 92 alias entity this; 93 94 EntityID entity; 95 } 96 97 void create(ivec2 nodes_count, vec2 node_size) 98 { 99 this.size = nodes_count; 100 this.node_size = node_size; 101 inv_node_size = vec2(1.0/node_size.x, 1.0/node_size.y); 102 nodes = Mallocator.makeArray!Node(nodes_count.x * nodes_count.y); 103 masks = Mallocator.makeArray!ubyte(nodes.length); 104 } 105 106 void mark(EntityID id, vec2 beg, vec2 end, ubyte mask) 107 { 108 ivec2 ibeg = cast(ivec2)(beg * inv_node_size); 109 ivec2 iend = cast(ivec2)(end * inv_node_size + 0.5); 110 if(ibeg.x < 0)ibeg.x = 0; 111 if(ibeg.y < 0)ibeg.y = 0; 112 if(iend.x > size.x)iend.x = size.x; 113 if(iend.y > size.y)iend.y = size.y; 114 foreach(i; ibeg.y .. iend.y) 115 { 116 foreach(j; ibeg.x .. iend.x) 117 { 118 nodes[i * size.x + j] = id; 119 masks[i * size.x + j] = mask; 120 } 121 } 122 } 123 124 void clear() 125 { 126 size_t size = nodes.length * EntityID.sizeof; 127 memset(nodes.ptr, 0, size); 128 memset(masks.ptr, 0, masks.length); 129 } 130 131 bool test(out EntityID id, vec2 beg, vec2 end, ubyte mask) 132 { 133 ivec2 ibeg = cast(ivec2)(beg * inv_node_size); 134 ivec2 iend = cast(ivec2)(end * inv_node_size + 0.5); 135 if(ibeg.x < 0)ibeg.x = 0; 136 if(ibeg.y < 0)ibeg.y = 0; 137 if(iend.x > size.x)iend.x = size.x; 138 if(iend.y > size.y)iend.y = size.y; 139 foreach(i; ibeg.y .. iend.y) 140 { 141 foreach(j; ibeg.x .. iend.x) 142 { 143 uint index = i * size.x + j; 144 if(nodes[index].id != 0) 145 { 146 if((masks[index] & mask) == 0)continue; 147 id = nodes[index]; 148 return true; 149 } 150 } 151 } 152 return false; 153 } 154 155 bool test(out EntityID id, vec2 pos, ubyte mask) 156 { 157 ivec2 ipos = cast(ivec2)(pos * inv_node_size - 0.5); 158 if(ipos.x < 0)ipos.x = 0; 159 if(ipos.y < 0)ipos.y = 0; 160 if(ipos.x >= size.x)ipos.x = size.x - 1; 161 if(ipos.y >= size.y)ipos.y = size.y - 1; 162 size_t index = ipos.y * size.x + ipos.x; 163 if((masks[index] & mask) == 0)return false; 164 if(nodes[index].id != 0) 165 { 166 id = nodes[index]; 167 return true; 168 } 169 return false; 170 } 171 172 vec2 inv_node_size; 173 ivec2 size; 174 vec2 node_size; 175 Node[] nodes; 176 ubyte[] masks; 177 } 178 179 struct ShootGridCleaner 180 { 181 mixin ECS.System!1; 182 183 struct EntitiesData 184 { 185 186 } 187 188 ShootGrid* grid; 189 190 bool onBegin() 191 { 192 grid = gEntityManager.getSystem!ShootGridManager().grid; 193 if(grid != null)return true; 194 else return false; 195 } 196 197 void onUpdate(EntitiesData data) 198 { 199 if(grid)grid.clear(); 200 } 201 } 202 203 struct ShootGridManager 204 { 205 mixin ECS.System!128; 206 207 mixin ECS.WritableDependencies!(ShootGridDependency); 208 209 struct EntitiesData 210 { 211 uint length; 212 //uint thread_id; 213 const (Entity)[] entity; 214 @readonly CLocation[] locations; 215 @readonly CShootGrid[] grid_flag; 216 //@readonly CGuild[] guild; 217 @optional @readonly CShootGridMask[] mask; 218 @optional @readonly CScale[] scale; 219 @optional @readonly CColliderScale[] collider_scale; 220 } 221 222 ShootGrid* grid; 223 224 void onCreate() 225 { 226 //grid = space_invaders.shoot_grid; 227 grid = Mallocator.make!ShootGrid; 228 grid.create(ivec2(80,60), vec2(5,5)); 229 } 230 231 void onDestroy() 232 { 233 Mallocator.dispose(grid); 234 } 235 236 // bool onBegin() 237 // { 238 // //if(!grid)return false; 239 // //grid.clear(); 240 // return true; 241 // } 242 243 void onUpdate(EntitiesData data) 244 { 245 vec2[] scale; 246 if(data.collider_scale)scale = cast(vec2[])data.collider_scale; 247 else if(data.scale)scale = cast(vec2[])data.scale; 248 else return; 249 if(data.mask is null) 250 { 251 foreach(i; 0..data.length) 252 { 253 vec2 half_scale = scale[i] * 0.5; 254 grid.mark(data.entity[i].id, data.locations[i] - half_scale, data.locations[i] + half_scale, ubyte.max);//cast(ubyte)(1 << data.guild[i].guild)); 255 } 256 } 257 else foreach(i; 0..data.length) 258 { 259 vec2 half_scale = scale[i] * 0.5; 260 grid.mark(data.entity[i].id, data.locations[i] - half_scale, data.locations[i] + half_scale, data.mask[i]);//cast(ubyte)(1 << data.guild[i].guild)); 261 } 262 263 } 264 } 265 266 struct AABB 267 { 268 vec2 size() 269 { 270 return max-min; 271 } 272 273 vec2 center() 274 { 275 return (max+min) * 0.5; 276 } 277 278 float area() 279 { 280 return size.x * size.y; 281 } 282 283 void set(ref AABB base, vec2 position, float angle, vec2 scale) 284 { 285 import std.algorithm.comparison : max; 286 287 float sr = sinf(angle); 288 float cr = cosf(angle); 289 /*mat2 m = mat2(cr,-sr, 290 sr,cr);*/ 291 292 293 //vec2 pos = ;//m * ((base.max + base.min)*0.5*scale); 294 vec2 size = (base.max - base.min)*scale; 295 vec2[2] axis = [vec2(cr*size.x,sr*size.y),vec2(-sr*size.x,cr*size.y)]; 296 297 this.max.x = max(fabs(axis[0].x),fabs(axis[1].x)); 298 this.max.y = max(fabs(axis[0].y),fabs(axis[1].y)); 299 300 this.min = -this.max; 301 302 this.min += center + position; 303 this.max += center + position; 304 } 305 306 void set(ref AABB base, vec2 position, vec2 scale) 307 { 308 vec2 size = (base.max - base.min)*scale; 309 310 this.min = -size; 311 this.max = size; 312 313 this.min += center + position; 314 this.max += center + position; 315 } 316 317 void set(ref AABB base, vec2 position, float angle) 318 { 319 import std.algorithm.comparison : max; 320 321 float sr = sinf(angle); 322 float cr = cosf(angle); 323 /*mat2 m = mat2(cr,-sr, 324 sr,cr);*/ 325 326 327 //vec2 pos = ;//m * ((base.max + base.min)*0.5*scale); 328 vec2 size = (base.max - base.min);//*scale; 329 vec2[2] axis = [vec2(cr*size.x,sr*size.y),vec2(-sr*size.x,cr*size.y)]; 330 331 this.max.x = max(fabs(axis[0].x),fabs(axis[1].x)); 332 this.max.y = max(fabs(axis[0].y),fabs(axis[1].y)); 333 334 this.min = -this.max; 335 336 this.min += center + position; 337 this.max += center + position; 338 } 339 340 void set(ref AABB base, vec2 position) 341 { 342 min = base.min + position; 343 max = base.max + position; 344 } 345 346 vec2 min; 347 vec2 max; 348 } 349 350 bool test(AABB a, AABB b) 351 { 352 if((a.max.x>b.min.x && a.max.y>b.min.y) && 353 (a.min.x<b.max.x && a.min.y<b.max.y))return true; 354 else return false; 355 } 356 357 byte intersectTest(AABB a, AABB b) 358 { 359 if(a.min.x < b.min.x && a.min.y < b.min.y && 360 a.max.x > b.max.x && a.max.y > b.max.y)return 2; 361 else if((a.max.x>b.min.x && a.max.y>b.min.y) && 362 (a.min.x<b.max.x && a.min.y<b.max.y))return 1; 363 return 0; 364 } 365 366 bool test(vec2 point, AABB b) 367 { 368 if((point.x>b.min.x && point.y>b.min.y) && 369 (point.x<b.max.x && point.y<b.max.y))return true; 370 else return false; 371 } 372 373 AABB merge(AABB a, AABB b) 374 { 375 import std.algorithm.comparison: min, max; 376 return AABB(vec2(min(a.min.x,b.min.x),min(a.min.y,b.min.y)),vec2(max(a.max.x,b.max.x),max(a.max.y,b.max.y))); 377 } 378 379 struct Quadtree 380 { 381 382 Node* add(EntityID id, AABB aabb) 383 { 384 ubyte depth = void; 385 vec2 ratio = aabb.size / this.aabb.size; 386 //if(ratio.x < ratio.y)depth = log2f(); 387 //else depth = 0; 388 return null; 389 //2^x = size2/size; 390 } 391 392 struct Node 393 { 394 395 AABB aabb; 396 Node*[4] nodes; 397 MemoryBlock* block; 398 MemoryBlock* last_block; 399 } 400 401 struct MemoryBlock 402 { 403 EntityID[10] entities; 404 MemoryBlock* next_block; 405 void* Node; 406 } 407 408 struct MetaBlock 409 { 410 union 411 { 412 MemoryBlock _alignment; 413 struct 414 { 415 Quadtree* quadtree; 416 } 417 } 418 } 419 420 AABB aabb; 421 422 Node main_node; 423 uint max_depth; 424 425 BlockAllocator allocator; 426 } 427 428 struct BVHTree 429 { 430 431 void generateTopDown() 432 { 433 434 } 435 436 void generateBottomUp() 437 { 438 clearNodes(); 439 uint index = 0; 440 while(index < nodes.length - 1) 441 { 442 Node* node = &nodes[index]; 443 if(node.parent != uint.max) 444 { 445 index++; 446 continue; 447 } 448 uint best_index = 0; 449 float best_cost = float.max; 450 foreach(i;index+1 .. nodes.length) 451 { 452 Node* test_node = &nodes[i]; 453 if(test_node.parent != uint.max)continue; 454 // vec2 rel_pos = node.bounding.center - test_node.bounding.center; 455 // float cost = fabs(rel_pos.x) + fabs(rel_pos.y); 456 // float cost = rel_pos.length; 457 // float cost = rel_pos.length2; 458 float cost = merge(node.bounding, test_node.bounding).area(); 459 if(cost < best_cost) 460 { 461 best_cost = cost; 462 best_index = cast(uint)i; 463 } 464 } 465 466 uint new_index = getNode(); 467 Node* new_node = &nodes[new_index]; 468 Node* best_node = &nodes[best_index]; 469 470 new_node.childs[0] = index; 471 new_node.childs[1] = best_index; 472 new_node.bounding = merge(best_node.bounding, node.bounding); 473 474 best_node.parent = new_index; 475 node.parent = new_index; 476 } 477 478 root = cast(uint)nodes.length - 1; 479 } 480 481 uint addIncrementally(AABB bounding, EntityID id) 482 { 483 if(root == uint.max) 484 { 485 root = getNode(); 486 Node* new_node = &nodes[root]; 487 new_node.parent = uint.max; 488 new_node.entity = id; 489 new_node.bounding = bounding; 490 //new_node.childs = [uint.max, uint.max].staticArray; 491 new_node.childs[0] = uint.max; 492 new_node.childs[1] = uint.max; 493 return root; 494 } 495 496 float cost = float.max; 497 uint best_index = 0; 498 findBest(bounding, root, best_index, cost, 0); 499 500 uint new_index = getNode(); 501 uint leaf_index = getNode(); 502 503 Node* new_node = &nodes[new_index]; 504 Node* node = &nodes[best_index]; 505 Node* parent = &nodes[node.parent]; 506 Node* leaf_node = &nodes[leaf_index]; 507 508 leaf_node.entity = id; 509 leaf_node.bounding = bounding; 510 leaf_node.parent = new_index; 511 512 new_node.parent = node.parent; 513 new_node.childs[0] = best_index; 514 new_node.childs[1] = leaf_index; 515 new_node.bounding = merge(bounding, node.bounding); 516 517 if(node.parent != uint.max) 518 { 519 if(parent.childs[0] == best_index) 520 { 521 parent.childs[0] = new_index; 522 } 523 else 524 { 525 parent.childs[1] = new_index; 526 } 527 } 528 else 529 { 530 root = new_index; 531 } 532 533 node.parent = new_index; 534 535 uint index = new_node.parent; 536 537 while(index != uint.max) 538 { 539 Node* lnode = &nodes[index]; 540 541 recalculate(lnode); 542 543 rotate(lnode); 544 545 index = lnode.parent; 546 } 547 548 return leaf_index; 549 } 550 551 void clearNodes() 552 { 553 root = uint.max; 554 uint i = 0; 555 while(i < nodes.length) 556 { 557 Node* node = &nodes[i]; 558 if(node.childs[0] == uint.max) 559 { 560 node.parent = uint.max; 561 i++; 562 } 563 else 564 { 565 removeNode(i); 566 } 567 } 568 } 569 570 void findBest(AABB bounding, uint node_index, ref uint best_index, ref float best_cost, float cost) 571 { 572 Node* node = &nodes[node_index]; 573 //float area = nodes.bounding.area; 574 AABB new_bounding = merge(node.bounding, bounding); 575 float new_area = new_bounding.area; 576 if(new_area + cost < best_cost) 577 { 578 best_index = node_index; 579 best_cost = cost + new_area; 580 } 581 582 if(node.childs[0] == uint.max)return; 583 float area_delta = new_area - node.bounding.area; 584 585 if(bounding.area + area_delta + cost < best_cost) 586 { 587 findBest(bounding, node.childs[0], best_index, best_cost, cost + area_delta); 588 findBest(bounding, node.childs[1], best_index, best_cost, cost + area_delta); 589 } 590 } 591 592 void add(AABB bounding, EntityID id) 593 { 594 Node* node = &nodes[getNode()]; 595 node.entity = id; 596 node.bounding = bounding; 597 // node.childs = [uint.max,uint.max]; 598 node.childs[0] = uint.max; 599 node.childs[1] = uint.max; 600 } 601 602 void test(AABB bounding, bool delegate(EntityID id) callback) 603 { 604 bool traverse(Node* node) 605 { 606 if(.test(bounding, node.bounding)) 607 { 608 if(node.childs[0] == uint.max) 609 { 610 return callback(node.entity); 611 } 612 if(!traverse(&nodes[node.childs[0]]))return false; 613 if(!traverse(&nodes[node.childs[1]]))return false; 614 } 615 /*node.bounding.max.x = max(nodes[node.childs[0]].bounding.max.x,nodes[node.childs[1]].bounding.max.x); 616 node.bounding.max.y = max(nodes[node.childs[0]].bounding.max.y,nodes[node.childs[1]].bounding.max.y); 617 node.bounding.min.x = min(nodes[node.childs[0]].bounding.min.x,nodes[node.childs[1]].bounding.min.x); 618 node.bounding.min.y = min(nodes[node.childs[0]].bounding.min.y,nodes[node.childs[1]].bounding.min.y);*/ 619 return true; 620 } 621 622 if(root < nodes.length)traverse(&nodes[root]); 623 } 624 625 float computeCost() 626 { 627 float cost = 0; 628 foreach(ref Node node;nodes) 629 { 630 if(node.childs[0] != uint.max) 631 { 632 cost += node.bounding.area(); 633 } 634 } 635 return cost; 636 } 637 638 void recalculate(Node* node) 639 { 640 import std.algorithm.comparison: min, max; 641 node.bounding = merge(nodes[node.childs[0]].bounding, nodes[node.childs[1]].bounding); 642 } 643 644 void rotate(Node* node) 645 { 646 import std.algorithm.comparison: min, max; 647 if(node.parent == uint.max)return; 648 Node* parent = &nodes[node.parent]; 649 Node* child1 = &nodes[node.childs[0]]; 650 Node* child2 = &nodes[node.childs[1]]; 651 652 uint child_index = void; 653 if(parent.childs[0] == child1.parent) 654 { 655 child_index = 1; 656 } 657 else 658 { 659 child_index = 0; 660 } 661 Node* to_rotate = &nodes[parent.childs[child_index]]; 662 663 float cost = node.bounding.area(); 664 AABB bounding1 = merge(child1.bounding, to_rotate.bounding); 665 AABB bounding2 = merge(child2.bounding, to_rotate.bounding); 666 float area1 = bounding1.area; 667 float area2 = bounding2.area; 668 if(area1 < area2) 669 { 670 if(area1 < cost) 671 { 672 to_rotate.parent = child1.parent; 673 child2.parent = node.parent; 674 uint swap_index = node.childs[1]; 675 node.childs[1] = parent.childs[child_index]; 676 parent.childs[child_index] = swap_index; 677 node.bounding = bounding1; 678 } 679 } 680 else 681 { 682 if(area2 < cost) 683 { 684 to_rotate.parent = child1.parent; 685 child1.parent = node.parent; 686 uint swap_index = node.childs[0]; 687 node.childs[0] = parent.childs[child_index]; 688 parent.childs[child_index] = swap_index; 689 node.bounding = bounding2; 690 } 691 } 692 } 693 694 void remove(uint i) 695 { 696 //foreach(i, ref Node node; nodes) 697 //{ 698 // if(node.entity == id) 699 // { 700 Node* node = &nodes[i]; 701 if(node.parent != uint.max) 702 { 703 ///parent isn't root, most common beaviour 704 Node* parent = &nodes[node.parent]; 705 if(parent.parent == uint.max) 706 { 707 //delete leaf attached to root 708 if(parent.childs[0] == i) 709 { 710 root = parent.childs[1]; 711 nodes[parent.childs[1]].parent = uint.max; 712 } 713 else 714 { 715 root = parent.childs[0]; 716 nodes[parent.childs[0]].parent = uint.max; 717 } 718 } 719 else 720 { 721 ///remove node from inside of tree 722 Node* grand_parent = &nodes[parent.parent]; 723 uint remain_index = void; 724 if(parent.childs[0] == i)remain_index = parent.childs[1]; 725 else remain_index = parent.childs[0]; 726 if(grand_parent.childs[0] == node.parent) 727 { 728 grand_parent.childs[0] = remain_index; 729 nodes[remain_index].parent = parent.parent; 730 } 731 else 732 { 733 grand_parent.childs[1] = remain_index; 734 nodes[remain_index].parent = parent.parent; 735 } 736 737 uint index = parent.parent; 738 739 while(index != uint.max) 740 { 741 Node* lnode = &nodes[index]; 742 743 recalculate(lnode); 744 745 rotate(lnode); 746 747 index = lnode.parent; 748 } 749 } 750 removeNode(node.parent); 751 } 752 else root = uint.max; 753 removeNode(cast(uint)i); 754 //return; 755 //} 756 //} 757 } 758 759 void clear() 760 { 761 last_node = uint.max; 762 nodes.clear(); 763 root = uint.max; 764 } 765 766 uint getNode() 767 { 768 if(last_node == uint.max) 769 { 770 //nodes.length = nodes.length + 1; 771 nodes.add(Node()); 772 return cast(uint)nodes.length - 1; 773 } 774 else 775 { 776 uint ret = last_node; 777 last_node = nodes[last_node].parent; 778 nodes[ret] = Node(); 779 return ret; 780 } 781 } 782 783 void removeNode(uint index) 784 { 785 Node* node = &nodes[index]; 786 node.parent = last_node; 787 node.ptr = null; 788 last_node = index; 789 } 790 791 /*void create() 792 { 793 root = getNode(); 794 }*/ 795 796 struct Node 797 { 798 union 799 { 800 EntityID entity; 801 void* ptr; 802 } 803 AABB bounding; 804 uint parent = uint.max; 805 union 806 { 807 struct //workaround betterC compilation issue with _memset 808 { 809 uint _c1 = uint.max; 810 uint _c2 = uint.max; 811 } 812 uint[2] childs; 813 } 814 815 } 816 817 Vector!Node nodes; 818 //uint nodes_count; 819 uint last_node = uint.max; 820 uint root = uint.max; 821 } 822 823 struct StaticBVHBuilder 824 { 825 mixin ECS.System!1; 826 827 mixin ECS.WritableDependencies!(StaticBVHDependency); 828 829 struct EntitiesData 830 { 831 uint length; 832 //uint thread_id; 833 const (Entity)[] entity; 834 CBVH[] bvh; 835 @readonly CStatic[] static_flag; 836 @readonly CLocation[] locations; 837 @readonly CAABB[] bounding; 838 } 839 840 BVHTree* tree; 841 842 void onCreate() 843 { 844 tree = Mallocator.make!BVHTree; 845 } 846 847 void onDestroy() 848 { 849 Mallocator.dispose(tree); 850 } 851 852 // bool onBegin() 853 // { 854 // tree.clear(); 855 // return true; 856 // // return false; 857 // } 858 859 void onAddEntity(EntitiesData data) 860 { 861 foreach(i;0..data.length) 862 { 863 data.bvh[i].index = tree.addIncrementally(data.bounding[i], data.entity[i].id); 864 } 865 } 866 867 void onRemoveEntity(EntitiesData data) 868 { 869 foreach(i;0..data.length) 870 { 871 tree.remove(data.bvh[i].index); 872 } 873 } 874 875 // void onUpdate(EntitiesData data) 876 // { 877 // foreach(i; 0..data.length) 878 // { 879 // // tree.add(data.bounding[i], data.entity[i].id); 880 // tree.addIncrementally(data.bounding[i], data.entity[i].id); 881 // } 882 883 // import std.stdio; 884 // writeln("Cost: ",tree.computeCost()); 885 // } 886 } 887 888 struct BVHBuilder 889 { 890 mixin ECS.System!1; 891 892 mixin ECS.WritableDependencies!(BVHDependency); 893 894 struct EntitiesData 895 { 896 uint length; 897 //uint thread_id; 898 const (Entity)[] entity; 899 CBVH[] bvh; 900 @readonly CLocation[] locations; 901 @readonly CAABB[] bounding; 902 } 903 904 mixin ECS.ExcludedComponents!(CStatic); 905 906 BVHTree* tree; 907 908 void onCreate() 909 { 910 tree = Mallocator.make!BVHTree; 911 } 912 913 void onDestroy() 914 { 915 Mallocator.dispose(tree); 916 } 917 918 bool onBegin() 919 { 920 tree.clear(); 921 return true; 922 // return false; 923 } 924 925 // void onAddEntity(EntitiesData data) 926 // { 927 // foreach(i;0..data.length) 928 // { 929 // tree.add(data.bounding[i], data.entity[i].id); 930 // } 931 // } 932 933 // void onRemoveEntity(EntitiesData data) 934 // { 935 // foreach(i;0..data.length) 936 // { 937 // tree.remove(data.entity[i].id); 938 // } 939 // } 940 941 void onUpdate(EntitiesData data) 942 { 943 foreach(i; 0..data.length) 944 { 945 // tree.add(data.bounding[i], data.entity[i].id); 946 data.bvh[i].index = tree.addIncrementally(data.bounding[i], data.entity[i].id); 947 } 948 949 // import std.stdio; 950 // writeln("Cost: ",tree.computeCost()); 951 } 952 } 953 /* 954 struct BVHBuilder2 955 { 956 mixin ECS.System!1; 957 958 mixin ECS.WritableDependencies!(BVHDependency); 959 960 struct EntitiesData 961 { 962 } 963 964 BVHTree* tree; 965 966 void onCreate() 967 { 968 tree = gEntityManager.getSystem!BVHBuilder().tree; 969 } 970 971 bool onBegin() 972 { 973 //if(tree.nodes.length-1 != tree.root)tree.clear(); 974 return true; 975 } 976 977 void onUpdate(EntitiesData data) 978 { 979 if(tree.nodes.length-1 != tree.root) 980 { 981 tree.generateBottomUp(); 982 import std.stdio; 983 writeln("Cost: ",tree.computeCost()); 984 } 985 } 986 }//*/ 987 988 struct AABBUpdater 989 { 990 mixin ECS.System!64; 991 992 struct EntitiesData 993 { 994 uint length; 995 //uint thread_id; 996 const (Entity)[] entity; 997 CAABB[] bounding; 998 999 @readonly CLocation[] location; 1000 @readonly CScale[] scale; 1001 @optional @readonly CRotation[] rotation; 1002 @optional @readonly CStatic[] static_flag; 1003 } 1004 1005 void onAddEntity(EntitiesData data) 1006 { 1007 foreach(i; 0..data.length) 1008 { 1009 data.bounding[i] = AABB(data.location[i]-data.scale[i],data.location[i]+data.scale[i]); 1010 } 1011 } 1012 1013 void onUpdate(EntitiesData data) 1014 { 1015 if(data.static_flag)return; 1016 1017 foreach(i; 0..data.length) 1018 { 1019 data.bounding[i] = AABB(data.location[i]-data.scale[i],data.location[i]+data.scale[i]); 1020 } 1021 } 1022 }