Demos big update

-Added some more math functions
-fixed many memory leaks
-added AABB and BVHTree support to collision.d
 *BVHTree has only incrementally adding entities implemented by now (and bad BottomUp algorithm)
 *ECS Systems use two trees, one for static and one for dynamic entities, dynamic BVH is builded every frame from scratch by now
-BrickBreaker now uses BVHTree to collision detection
 *balls only use tree for checks (they aren't adding to tree)
-fixed bug leading to crash
This commit is contained in:
Mergul 2020-07-17 13:38:41 +02:00
parent 96bbcb9956
commit 64dc099e0a
9 changed files with 973 additions and 70 deletions

View file

@ -117,12 +117,12 @@ struct Launcher
gui_manager.clear(); gui_manager.clear();
//launcher.ent //launcher.ent
if(this.demo.deinitialize)this.demo.deinitialize();
manager.begin(); manager.begin();
manager.update("clean"); manager.update("clean");
manager.end(); manager.end();
if(this.demo.deinitialize)this.demo.deinitialize();
foreach(ref system; manager.systems) foreach(ref system; manager.systems)
{ {
if(system.id != CountSystem.system_id && system.id != CleanSystem.system_id)system.disable(); if(system.id != CountSystem.system_id && system.id != CleanSystem.system_id)system.disable();
@ -946,12 +946,19 @@ void mainLoop(void* arg)
void quit() void quit()
{ {
import game_core.rendering : TexCoordsManager;
launcher.gui_manager.clear(); launcher.gui_manager.clear();
Mallocator.dispose(launcher.gui_manager); Mallocator.dispose(launcher.gui_manager);
if(launcher.demo.deinitialize)launcher.demo.deinitialize();
launcher.manager.destroy(); launcher.manager.destroy();
launcher.manager = null; launcher.manager = null;
TexCoordsManager.destroy();
SDL_Quit();
version(WebAssembly)emscripten_cancel_main_loop(); version(WebAssembly)emscripten_cancel_main_loop();
} }
@ -1060,10 +1067,11 @@ int app_main(int argc, char** argv)
} }
} }
ImFontConfig* config = ImFontConfig_ImFontConfig(); //ImFontConfig* config = ImFontConfig_ImFontConfig();
ImGuiIO* io = igGetIO(); ImGuiIO* io = igGetIO();
const ushort* font_ranges = ImFontAtlas_GetGlyphRangesDefault(io.Fonts); const ushort* font_ranges = ImFontAtlas_GetGlyphRangesDefault(io.Fonts);
ImFontAtlas_AddFontFromFileTTF(io.Fonts,"assets/fonts/Ruda-Bold.ttf", 15.0f, config, font_ranges); ImFontAtlas_AddFontFromFileTTF(io.Fonts,"assets/fonts/Ruda-Bold.ttf", 15.0f, null, font_ranges);
//ImFontConfig_destroy(config);
setStyle(3); setStyle(3);
@ -1139,9 +1147,6 @@ int app_main(int argc, char** argv)
} }
} }
TexCoordsManager.destroy();
EntityManager.destroy();
return 0; return 0;
} }

View file

@ -54,6 +54,15 @@ struct CBall
ubyte radius; ubyte radius;
} }
struct CHitPoints
{
mixin ECS.Component;
alias value this;
short value;
}
// struct CVelocityFactor // struct CVelocityFactor
// { // {
// mixin ECS.Component; // mixin ECS.Component;
@ -72,6 +81,13 @@ struct CBall
// vec2 value = vec2(0); // vec2 value = vec2(0);
// } // }
struct EDamage
{
mixin ECS.Event;
ubyte damage = 1;
}
/*####################################################################################################################### /*#######################################################################################################################
------------------------------------------------ Systems ------------------------------------------------------------------ ------------------------------------------------ Systems ------------------------------------------------------------------
#######################################################################################################################*/ #######################################################################################################################*/
@ -152,7 +168,7 @@ struct BallCollisionSystem
{ {
mixin ECS.System!64; mixin ECS.System!64;
mixin ECS.ReadOnlyDependencies!(ShootGridDependency); mixin ECS.ReadOnlyDependencies!(ShootGridDependency, BVHDependency);
struct EntitiesData struct EntitiesData
{ {
@ -165,23 +181,9 @@ struct BallCollisionSystem
@readonly CBall[] ball_flag; @readonly CBall[] ball_flag;
} }
ShootGrid* grid; struct State
bool onBegin()
{ {
grid = launcher.manager.getSystem!ShootGridManager().grid; bool test(EntityID id)
if(grid is null)return false;
else return true;
}
void onUpdate(EntitiesData data)
{
EntityID id;
foreach(i; 0..data.length)
{
float radius = data.scale[i].x;
//if(grid.test(id, data.location[i], ubyte.max))
if(grid.test(id, data.location[i] - radius, data.location[i] + radius, ubyte.max))
{ {
Entity* entity = launcher.manager.getEntity(id); Entity* entity = launcher.manager.getEntity(id);
if(entity) if(entity)
@ -190,6 +192,7 @@ struct BallCollisionSystem
CScale* scale = entity.getComponent!CScale; CScale* scale = entity.getComponent!CScale;
if(location && scale) if(location && scale)
{ {
float radius = data.scale[i].x;
vec2 rel_pos = *location - data.location[i]; vec2 rel_pos = *location - data.location[i];
vec2 abs_rel_pos = rel_pos; vec2 abs_rel_pos = rel_pos;
if(abs_rel_pos.x < 0)abs_rel_pos.x = -abs_rel_pos.x; if(abs_rel_pos.x < 0)abs_rel_pos.x = -abs_rel_pos.x;
@ -202,11 +205,21 @@ struct BallCollisionSystem
{ {
if(abs_rel_pos.x < half_scale.x) if(abs_rel_pos.x < half_scale.x)
{ {
if(rel_pos.y * data.velocity[i].y > 0)data.velocity[i].y = -data.velocity[i].y; if(rel_pos.y * data.velocity[i].y > 0)
{
data.velocity[i].y = -data.velocity[i].y;
launcher.manager.sendEvent(id,EDamage(1));
return false;
}
} }
else if(abs_rel_pos.y < half_scale.y) else if(abs_rel_pos.y < half_scale.y)
{ {
if(rel_pos.x * data.velocity[i].x > 0)data.velocity[i].x = -data.velocity[i].x; if(rel_pos.x * data.velocity[i].x > 0)
{
data.velocity[i].x = -data.velocity[i].x;
launcher.manager.sendEvent(id,EDamage(1));
return false;
}
} }
else else
{ {
@ -219,16 +232,83 @@ struct BallCollisionSystem
{ {
vector = vector / sqrtf(pow_dist); vector = vector / sqrtf(pow_dist);
data.velocity[i] = data.velocity[i] - vector * (2 * dot(vector, data.velocity[i])); data.velocity[i] = data.velocity[i] - vector * (2 * dot(vector, data.velocity[i]));
launcher.manager.sendEvent(id,EDamage(1));
return false;
} }
} }
} }
} }
} }
//launcher.manager.sendEvent(id, EBulletHit(data.entity[i].id,data.bullet[i].damage)); return true;
//launcher.manager.removeEntity(data.entity[i].id); }
EntitiesData data;
uint i;
}
ShootGrid* grid;
BVHTree* tree;
BVHTree* static_tree;
bool onBegin()
{
//grid = launcher.manager.getSystem!ShootGridManager().grid;
tree = launcher.manager.getSystem!BVHBuilder().tree;
static_tree = launcher.manager.getSystem!StaticBVHBuilder().tree;
//if(grid is null)return false;
if(tree is null || static_tree is null)return false;
else return true;
}
void onUpdate(EntitiesData data)
{
// State state;
// state.data = data;
// EntityID id;
// foreach(i; 0..data.length)
// {
// state.i = i;
// float radius = data.scale[i].x;
// if(grid.test(id, data.location[i] - radius, data.location[i] + radius, ubyte.max))
// {
// state.test(id);
// }
// }
State state;
state.data = data;
foreach(i; 0..data.length)
{
state.i = i;
//float radius = data.scale[i].x;
AABB bounding = AABB(data.location[i]-data.scale[i], data.location[i]+data.scale[i]);
tree.test(bounding, cast(bool delegate(EntityID id))&state.test);
static_tree.test(bounding, cast(bool delegate(EntityID id))&state.test);
} }
} }
}
struct DamageSystem
{
mixin ECS.System!64;
mixin ECS.ReadOnlyDependencies!(ShootGridDependency);
struct EntitiesData
{
///variable named "length" contain entites count
uint length;
const (Entity)[] entity;
CHitPoints[] hit_points;
} }
void handleEvent(Entity* entity, EDamage event)
{
EntityMeta meta = entity.getMeta();
CHitPoints* hp = meta.getComponent!CHitPoints;
hp.value -= event.damage;
if(hp.value < 0)launcher.manager.removeEntity(entity.id);
}
} }
/*####################################################################################################################### /*#######################################################################################################################
@ -239,7 +319,7 @@ struct BrickBreakerDemo
{ {
__gshared const (char)* tips = "Brick breaker demo. It's a game about destroying evil bricks."; __gshared const (char)* tips = "Brick breaker demo. It's a game about destroying evil bricks.";
EntityTemplate* tmpl; //EntityTemplate* tmpl;
Texture texture; Texture texture;
} }
@ -268,12 +348,16 @@ void brickBreakerRegister()
launcher.manager.registerComponent!CDamping; launcher.manager.registerComponent!CDamping;
launcher.manager.registerComponent!CVelocityFactor; launcher.manager.registerComponent!CVelocityFactor;
launcher.manager.registerComponent!CBall; launcher.manager.registerComponent!CBall;
launcher.manager.registerComponent!CHitPoints;
launcher.manager.registerEvent!EDamage;
launcher.manager.registerSystem!MoveSystem(-100); launcher.manager.registerSystem!MoveSystem(-100);
launcher.manager.registerSystem!EdgeCollisionSystem(-99); launcher.manager.registerSystem!EdgeCollisionSystem(-99);
launcher.manager.registerSystem!BallCollisionSystem(-79); launcher.manager.registerSystem!BallCollisionSystem(-79);
launcher.manager.registerSystem!InputMovementSystem(-120); launcher.manager.registerSystem!InputMovementSystem(-120);
launcher.manager.registerSystem!DampingSystem(-120); launcher.manager.registerSystem!DampingSystem(-120);
launcher.manager.registerSystem!DamageSystem(-120);
launcher.manager.endRegister(); launcher.manager.endRegister();
} }
@ -289,11 +373,14 @@ void brickBreakerStart()
EntityTemplate* brick_tmpl = launcher.manager.allocateTemplate( EntityTemplate* brick_tmpl = launcher.manager.allocateTemplate(
[CLocation.component_id, CScale.component_id, CColor.component_id, [CLocation.component_id, CScale.component_id, CColor.component_id,
CTexCoordsIndex.component_id, CShootGrid.component_id].staticArray CTexCoordsIndex.component_id, CBVH.component_id, CHitPoints.component_id,
CAABB.component_id, CStatic.component_id].staticArray
); );
brick_tmpl.getComponent!CTexCoordsIndex().value = TexCoordsManager.instance.getCoordIndex(vec4(304,40,16,8)*px); brick_tmpl.getComponent!CTexCoordsIndex().value = TexCoordsManager.instance.getCoordIndex(vec4(304,40,16,8)*px);
brick_tmpl.getComponent!CColor().value = 0x80206020; brick_tmpl.getComponent!CColor().value = 0x80206020;
brick_tmpl.getComponent!CScale().value = vec2(16,8); brick_tmpl.getComponent!CScale().value = vec2(16,8);
brick_tmpl.getComponent!CHitPoints().value = 2;
//brick_tmpl.getComponent!CAABB().bounding = AABB(vec2(),vec2());
EntityTemplate* big_brick_tmpl = launcher.manager.allocateTemplate(brick_tmpl); EntityTemplate* big_brick_tmpl = launcher.manager.allocateTemplate(brick_tmpl);
big_brick_tmpl.getComponent!CTexCoordsIndex().value = TexCoordsManager.instance.getCoordIndex(vec4(320,32,16,16)*px); big_brick_tmpl.getComponent!CTexCoordsIndex().value = TexCoordsManager.instance.getCoordIndex(vec4(320,32,16,16)*px);
@ -302,7 +389,8 @@ void brickBreakerStart()
EntityTemplate* paddle_tmpl = launcher.manager.allocateTemplate( EntityTemplate* paddle_tmpl = launcher.manager.allocateTemplate(
[CLocation.component_id, CScale.component_id, CInput.component_id, [CLocation.component_id, CScale.component_id, CInput.component_id,
CTexCoordsIndex.component_id, CPaddle.component_id, CVelocity.component_id, CTexCoordsIndex.component_id, CPaddle.component_id, CVelocity.component_id,
CDamping.component_id, CVelocityFactor.component_id, CShootGrid.component_id].staticArray CDamping.component_id, CVelocityFactor.component_id, CBVH.component_id,
CAABB.component_id].staticArray
); );
paddle_tmpl.getComponent!CTexCoordsIndex().value = TexCoordsManager.instance.getCoordIndex(vec4(272,48,64,10)*px); paddle_tmpl.getComponent!CTexCoordsIndex().value = TexCoordsManager.instance.getCoordIndex(vec4(272,48,64,10)*px);
paddle_tmpl.getComponent!CScale().value = vec2(64,10); paddle_tmpl.getComponent!CScale().value = vec2(64,10);
@ -330,7 +418,11 @@ void brickBreakerStart()
launcher.gui_manager.addComponent(CBall(), "Ball"); launcher.gui_manager.addComponent(CBall(), "Ball");
launcher.gui_manager.addSystem(MoveSystem.system_id, "Move System"); launcher.gui_manager.addSystem(MoveSystem.system_id, "Move System");
launcher.gui_manager.addSystem(EdgeCollisionSystem.system_id, "Edge Collision System");
launcher.gui_manager.addSystem(BallCollisionSystem.system_id, "Ball Collision System"); launcher.gui_manager.addSystem(BallCollisionSystem.system_id, "Ball Collision System");
launcher.gui_manager.addSystem(InputMovementSystem.system_id, "Input Movement System");
launcher.gui_manager.addSystem(DampingSystem.system_id, "Damping System");
launcher.gui_manager.addSystem(DamageSystem.system_id, "Damage System");
launcher.gui_manager.addTemplate(brick_tmpl, "Brick"); launcher.gui_manager.addTemplate(brick_tmpl, "Brick");
launcher.gui_manager.addTemplate(big_brick_tmpl, "Big Brick"); launcher.gui_manager.addTemplate(big_brick_tmpl, "Big Brick");

View file

@ -72,7 +72,7 @@ struct Snake
bool move_system = true; bool move_system = true;
bool draw_system = true; bool draw_system = true;
const int map_size = 18; enum int map_size = 18;
MapElement[map_size * map_size] map; MapElement[map_size * map_size] map;
@ -83,7 +83,7 @@ struct Snake
if(apple_tmpl)launcher.manager.freeTemplate(apple_tmpl); if(apple_tmpl)launcher.manager.freeTemplate(apple_tmpl);
if(snake_tmpl)launcher.manager.freeTemplate(snake_tmpl); if(snake_tmpl)launcher.manager.freeTemplate(snake_tmpl);
if(snake_destroy_particle)launcher.manager.freeTemplate(snake_destroy_particle); if(snake_destroy_particle)launcher.manager.freeTemplate(snake_destroy_particle);
texture.destory(); texture.destroy();
} }
MapElement element(ivec2 pos) MapElement element(ivec2 pos)

View file

@ -64,7 +64,7 @@ struct SpaceInvaders
{ {
if(tmpl)launcher.manager.freeTemplate(tmpl); if(tmpl)launcher.manager.freeTemplate(tmpl);
} }
texture.destory(); texture.destroy();
} }
} }
@ -90,7 +90,7 @@ struct SceneGrid
cells = Mallocator.makeArray!Cell(cells_count.x * cells_count.y); cells = Mallocator.makeArray!Cell(cells_count.x * cells_count.y);
} }
void destory() void destroy()
{ {
if(cells) if(cells)
{ {
@ -707,6 +707,7 @@ struct ShipWeaponSystem
void onDestroy() void onDestroy()
{ {
__xdtor();
/*launcher.manager.freeTemplate(laser1_tmpl); /*launcher.manager.freeTemplate(laser1_tmpl);
launcher.manager.freeTemplate(laser2_tmpl); launcher.manager.freeTemplate(laser2_tmpl);
launcher.manager.freeTemplate(main_weapon_tmpl);*/ launcher.manager.freeTemplate(main_weapon_tmpl);*/

View file

@ -1,10 +1,13 @@
module game_core.collision; module game_core.collision;
import bubel.ecs.attributes; import bubel.ecs.attributes;
import bubel.ecs.block_allocator;
import bubel.ecs.core; import bubel.ecs.core;
import bubel.ecs.std; import bubel.ecs.std;
import bubel.ecs.vector;
import ecs_utils.math.vector; import ecs_utils.math.vector;
import ecs_utils.utils;
import game_core.basic; import game_core.basic;
@ -12,22 +15,54 @@ import game_core.basic;
void registerCollisionModule(EntityManager* manager) void registerCollisionModule(EntityManager* manager)
{ {
manager.registerDependency(ShootGridDependency); manager.registerDependency(ShootGridDependency);
manager.registerDependency(BVHDependency);
manager.registerDependency(StaticBVHDependency);
manager.registerComponent!CShootGrid; manager.registerComponent!CShootGrid;
manager.registerComponent!CShootGridMask; manager.registerComponent!CShootGridMask;
manager.registerComponent!CColliderScale; manager.registerComponent!CColliderScale;
manager.registerComponent!CBVH;
manager.registerComponent!CAABB;
manager.registerComponent!CStatic;
manager.registerSystem!ShootGridManager(-80); manager.registerSystem!ShootGridManager(-80);
manager.registerSystem!ShootGridCleaner(-101); manager.registerSystem!ShootGridCleaner(-101);
manager.registerSystem!BVHBuilder(-80);
manager.registerSystem!StaticBVHBuilder(-80);
//manager.registerSystem!BVHBuilder2(-79);
manager.registerSystem!AABBUpdater(-81);
} }
enum ShootGridDependency = "ShootGridDependency"; enum ShootGridDependency = "ShootGridDependency";
enum BVHDependency = "BVHDependency";
enum StaticBVHDependency = "StaticBVHDependency";
struct CShootGrid struct CShootGrid
{ {
mixin ECS.Component; mixin ECS.Component;
} }
struct CBVH
{
mixin ECS.Component;
uint index;
}
struct CStatic
{
mixin ECS.Component;
}
struct CAABB
{
mixin ECS.Component;
alias bounding this;
AABB bounding;
}
struct CShootGridMask struct CShootGridMask
{ {
mixin ECS.Component; mixin ECS.Component;
@ -46,6 +81,7 @@ struct CColliderScale
vec2 value = vec2(16,16); vec2 value = vec2(16,16);
} }
struct ShootGrid struct ShootGrid
{ {
@ -84,7 +120,7 @@ struct ShootGrid
foreach(j; ibeg.x .. iend.x) foreach(j; ibeg.x .. iend.x)
{ {
nodes[i * size.x + j] = id; nodes[i * size.x + j] = id;
masks[i * size.x +j] = mask; masks[i * size.x + j] = mask;
} }
} }
} }
@ -230,3 +266,758 @@ struct ShootGridManager
} }
} }
struct AABB
{
vec2 size()
{
return max-min;
}
vec2 center()
{
return (max+min) * 0.5;
}
float area()
{
return size.x * size.y;
}
void set(ref AABB base, vec2 position, float angle, vec2 scale)
{
import std.algorithm.comparison : max;
float sr = sinf(angle);
float cr = cosf(angle);
/*mat2 m = mat2(cr,-sr,
sr,cr);*/
//vec2 pos = ;//m * ((base.max + base.min)*0.5*scale);
vec2 size = (base.max - base.min)*scale;
vec2[2] axis = [vec2(cr*size.x,sr*size.y),vec2(-sr*size.x,cr*size.y)];
this.max.x = max(fabs(axis[0].x),fabs(axis[1].x));
this.max.y = max(fabs(axis[0].y),fabs(axis[1].y));
this.min = -this.max;
this.min += center + position;
this.max += center + position;
}
void set(ref AABB base, vec2 position, vec2 scale)
{
vec2 size = (base.max - base.min)*scale;
this.min = -size;
this.max = size;
this.min += center + position;
this.max += center + position;
}
void set(ref AABB base, vec2 position, float angle)
{
import std.algorithm.comparison : max;
float sr = sinf(angle);
float cr = cosf(angle);
/*mat2 m = mat2(cr,-sr,
sr,cr);*/
//vec2 pos = ;//m * ((base.max + base.min)*0.5*scale);
vec2 size = (base.max - base.min);//*scale;
vec2[2] axis = [vec2(cr*size.x,sr*size.y),vec2(-sr*size.x,cr*size.y)];
this.max.x = max(fabs(axis[0].x),fabs(axis[1].x));
this.max.y = max(fabs(axis[0].y),fabs(axis[1].y));
this.min = -this.max;
this.min += center + position;
this.max += center + position;
}
void set(ref AABB base, vec2 position)
{
min = base.min + position;
max = base.max + position;
}
vec2 min;
vec2 max;
}
bool test(AABB a, AABB b)
{
if((a.max.x>b.min.x && a.max.y>b.min.y) &&
(a.min.x<b.max.x && a.min.y<b.max.y))return true;
else return false;
}
byte intersectTest(AABB a, AABB b)
{
if(a.min.x < b.min.x && a.min.y < b.min.y &&
a.max.x > b.max.x && a.max.y > b.max.y)return 2;
else if((a.max.x>b.min.x && a.max.y>b.min.y) &&
(a.min.x<b.max.x && a.min.y<b.max.y))return 1;
return 0;
}
bool test(vec2 point, AABB b)
{
if((point.x>b.min.x && point.y>b.min.y) &&
(point.x<b.max.x && point.y<b.max.y))return true;
else return false;
}
AABB merge(AABB a, AABB b)
{
import std.algorithm.comparison: min, max;
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)));
}
struct Quadtree
{
Node* add(EntityID id, AABB aabb)
{
ubyte depth = void;
vec2 ratio = aabb.size / this.aabb.size;
//if(ratio.x < ratio.y)depth = log2f();
//else depth = 0;
return null;
//2^x = size2/size;
}
struct Node
{
AABB aabb;
Node*[4] nodes;
MemoryBlock* block;
MemoryBlock* last_block;
}
struct MemoryBlock
{
EntityID[10] entities;
MemoryBlock* next_block;
void* Node;
}
struct MetaBlock
{
union
{
MemoryBlock _alignment;
struct
{
Quadtree* quadtree;
}
}
}
AABB aabb;
Node main_node;
uint max_depth;
BlockAllocator allocator;
}
struct BVHTree
{
void generateTopDown()
{
}
void generateBottomUp()
{
clearNodes();
uint index = 0;
while(index < nodes.length - 1)
{
Node* node = &nodes[index];
if(node.parent != uint.max)
{
index++;
continue;
}
uint best_index = 0;
float best_cost = float.max;
foreach(i;index+1 .. nodes.length)
{
Node* test_node = &nodes[i];
if(test_node.parent != uint.max)continue;
// vec2 rel_pos = node.bounding.center - test_node.bounding.center;
// float cost = fabs(rel_pos.x) + fabs(rel_pos.y);
// float cost = rel_pos.length;
// float cost = rel_pos.length2;
float cost = merge(node.bounding, test_node.bounding).area();
if(cost < best_cost)
{
best_cost = cost;
best_index = cast(uint)i;
}
}
uint new_index = getNode();
Node* new_node = &nodes[new_index];
Node* best_node = &nodes[best_index];
new_node.childs[0] = index;
new_node.childs[1] = best_index;
new_node.bounding = merge(best_node.bounding, node.bounding);
best_node.parent = new_index;
node.parent = new_index;
}
root = cast(uint)nodes.length - 1;
}
uint addIncrementally(AABB bounding, EntityID id)
{
if(root == uint.max)
{
root = getNode();
Node* new_node = &nodes[root];
new_node.parent = uint.max;
new_node.entity = id;
new_node.bounding = bounding;
//new_node.childs = [uint.max, uint.max].staticArray;
new_node.childs[0] = uint.max;
new_node.childs[1] = uint.max;
return root;
}
float cost = float.max;
uint best_index = 0;
findBest(bounding, root, best_index, cost, 0);
uint new_index = getNode();
uint leaf_index = getNode();
Node* new_node = &nodes[new_index];
Node* node = &nodes[best_index];
Node* parent = &nodes[node.parent];
Node* leaf_node = &nodes[leaf_index];
leaf_node.entity = id;
leaf_node.bounding = bounding;
leaf_node.parent = new_index;
new_node.parent = node.parent;
new_node.childs[0] = best_index;
new_node.childs[1] = leaf_index;
new_node.bounding = merge(bounding, node.bounding);
if(node.parent != uint.max)
{
if(parent.childs[0] == best_index)
{
parent.childs[0] = new_index;
}
else
{
parent.childs[1] = new_index;
}
}
else
{
root = new_index;
}
node.parent = new_index;
uint index = new_node.parent;
while(index != uint.max)
{
Node* lnode = &nodes[index];
recalculate(lnode);
rotate(lnode);
index = lnode.parent;
}
return leaf_index;
}
void clearNodes()
{
root = uint.max;
uint i = 0;
while(i < nodes.length)
{
Node* node = &nodes[i];
if(node.childs[0] == uint.max)
{
node.parent = uint.max;
i++;
}
else
{
removeNode(i);
}
}
}
void findBest(AABB bounding, uint node_index, ref uint best_index, ref float best_cost, float cost)
{
Node* node = &nodes[node_index];
//float area = nodes.bounding.area;
AABB new_bounding = merge(node.bounding, bounding);
float new_area = new_bounding.area;
if(new_area + cost < best_cost)
{
best_index = node_index;
best_cost = cost + new_area;
}
if(node.childs[0] == uint.max)return;
float area_delta = new_area - node.bounding.area;
if(bounding.area + area_delta + cost < best_cost)
{
findBest(bounding, node.childs[0], best_index, best_cost, cost + area_delta);
findBest(bounding, node.childs[1], best_index, best_cost, cost + area_delta);
}
}
void add(AABB bounding, EntityID id)
{
Node* node = &nodes[getNode()];
node.entity = id;
node.bounding = bounding;
// node.childs = [uint.max,uint.max];
node.childs[0] = uint.max;
node.childs[1] = uint.max;
}
void test(AABB bounding, bool delegate(EntityID id) callback)
{
bool traverse(Node* node)
{
if(.test(bounding, node.bounding))
{
if(node.childs[0] == uint.max)
{
return callback(node.entity);
}
if(!traverse(&nodes[node.childs[0]]))return false;
if(!traverse(&nodes[node.childs[1]]))return false;
}
/*node.bounding.max.x = max(nodes[node.childs[0]].bounding.max.x,nodes[node.childs[1]].bounding.max.x);
node.bounding.max.y = max(nodes[node.childs[0]].bounding.max.y,nodes[node.childs[1]].bounding.max.y);
node.bounding.min.x = min(nodes[node.childs[0]].bounding.min.x,nodes[node.childs[1]].bounding.min.x);
node.bounding.min.y = min(nodes[node.childs[0]].bounding.min.y,nodes[node.childs[1]].bounding.min.y);*/
return true;
}
if(root < nodes.length)traverse(&nodes[root]);
}
float computeCost()
{
float cost = 0;
foreach(ref Node node;nodes)
{
if(node.childs[0] != uint.max)
{
cost += node.bounding.area();
}
}
return cost;
}
void recalculate(Node* node)
{
import std.algorithm.comparison: min, max;
node.bounding = merge(nodes[node.childs[0]].bounding, nodes[node.childs[1]].bounding);
}
void rotate(Node* node)
{
import std.algorithm.comparison: min, max;
if(node.parent == uint.max)return;
Node* parent = &nodes[node.parent];
Node* child1 = &nodes[node.childs[0]];
Node* child2 = &nodes[node.childs[1]];
uint child_index = void;
if(parent.childs[0] == child1.parent)
{
child_index = 1;
}
else
{
child_index = 0;
}
Node* to_rotate = &nodes[parent.childs[child_index]];
float cost = node.bounding.area();
AABB bounding1 = merge(child1.bounding, to_rotate.bounding);
AABB bounding2 = merge(child2.bounding, to_rotate.bounding);
float area1 = bounding1.area;
float area2 = bounding2.area;
if(area1 < area2)
{
if(area1 < cost)
{
to_rotate.parent = child1.parent;
child2.parent = node.parent;
uint swap_index = node.childs[1];
node.childs[1] = parent.childs[child_index];
parent.childs[child_index] = swap_index;
node.bounding = bounding1;
}
}
else
{
if(area2 < cost)
{
to_rotate.parent = child1.parent;
child1.parent = node.parent;
uint swap_index = node.childs[0];
node.childs[0] = parent.childs[child_index];
parent.childs[child_index] = swap_index;
node.bounding = bounding2;
}
}
}
void remove(uint i)
{
//foreach(i, ref Node node; nodes)
//{
// if(node.entity == id)
// {
Node* node = &nodes[i];
if(node.parent != uint.max)
{
///parent isn't root, most common beaviour
Node* parent = &nodes[node.parent];
if(parent.parent == uint.max)
{
//delete leaf attached to root
if(parent.childs[0] == i)
{
root = parent.childs[1];
nodes[parent.childs[1]].parent = uint.max;
}
else
{
root = parent.childs[0];
nodes[parent.childs[0]].parent = uint.max;
}
}
else
{
///remove node from inside of tree
Node* grand_parent = &nodes[parent.parent];
uint remain_index = void;
if(parent.childs[0] == i)remain_index = parent.childs[1];
else remain_index = parent.childs[0];
if(grand_parent.childs[0] == node.parent)
{
grand_parent.childs[0] = remain_index;
nodes[remain_index].parent = parent.parent;
}
else
{
grand_parent.childs[1] = remain_index;
nodes[remain_index].parent = parent.parent;
}
uint index = parent.parent;
while(index != uint.max)
{
Node* lnode = &nodes[index];
recalculate(lnode);
rotate(lnode);
index = lnode.parent;
}
}
removeNode(node.parent);
}
else root = uint.max;
removeNode(cast(uint)i);
//return;
//}
//}
}
void clear()
{
last_node = uint.max;
nodes.clear();
root = uint.max;
}
uint getNode()
{
if(last_node == uint.max)
{
//nodes.length = nodes.length + 1;
nodes.add(Node());
return cast(uint)nodes.length - 1;
}
else
{
uint ret = last_node;
last_node = nodes[last_node].parent;
nodes[ret] = Node();
return ret;
}
}
void removeNode(uint index)
{
Node* node = &nodes[index];
node.parent = last_node;
node.ptr = null;
last_node = index;
}
/*void create()
{
root = getNode();
}*/
struct Node
{
union
{
EntityID entity;
void* ptr;
}
AABB bounding;
uint parent = uint.max;
union
{
struct //workaround betterC compilation issue with _memset
{
uint _c1 = uint.max;
uint _c2 = uint.max;
}
uint[2] childs;
}
}
Vector!Node nodes;
//uint nodes_count;
uint last_node = uint.max;
uint root = uint.max;
}
struct StaticBVHBuilder
{
mixin ECS.System!1;
mixin ECS.WritableDependencies!(StaticBVHDependency);
struct EntitiesData
{
uint length;
//uint thread_id;
const (Entity)[] entity;
CBVH[] bvh;
@readonly CStatic[] static_flag;
@readonly CLocation[] locations;
@readonly CAABB[] bounding;
}
BVHTree* tree;
void onCreate()
{
tree = Mallocator.make!BVHTree;
}
void onDestroy()
{
Mallocator.dispose(tree);
}
// bool onBegin()
// {
// tree.clear();
// return true;
// // return false;
// }
void onAddEntity(EntitiesData data)
{
foreach(i;0..data.length)
{
data.bvh[i].index = tree.addIncrementally(data.bounding[i], data.entity[i].id);
}
}
void onRemoveEntity(EntitiesData data)
{
foreach(i;0..data.length)
{
tree.remove(data.bvh[i].index);
}
}
// void onUpdate(EntitiesData data)
// {
// foreach(i; 0..data.length)
// {
// // tree.add(data.bounding[i], data.entity[i].id);
// tree.addIncrementally(data.bounding[i], data.entity[i].id);
// }
// import std.stdio;
// writeln("Cost: ",tree.computeCost());
// }
}
struct BVHBuilder
{
mixin ECS.System!1;
mixin ECS.WritableDependencies!(BVHDependency);
struct EntitiesData
{
uint length;
//uint thread_id;
const (Entity)[] entity;
CBVH[] bvh;
@readonly CLocation[] locations;
@readonly CAABB[] bounding;
}
mixin ECS.ExcludedComponents!(CStatic);
BVHTree* tree;
void onCreate()
{
tree = Mallocator.make!BVHTree;
}
void onDestroy()
{
Mallocator.dispose(tree);
}
bool onBegin()
{
tree.clear();
return true;
// return false;
}
// void onAddEntity(EntitiesData data)
// {
// foreach(i;0..data.length)
// {
// tree.add(data.bounding[i], data.entity[i].id);
// }
// }
// void onRemoveEntity(EntitiesData data)
// {
// foreach(i;0..data.length)
// {
// tree.remove(data.entity[i].id);
// }
// }
void onUpdate(EntitiesData data)
{
foreach(i; 0..data.length)
{
// tree.add(data.bounding[i], data.entity[i].id);
data.bvh[i].index = tree.addIncrementally(data.bounding[i], data.entity[i].id);
}
// import std.stdio;
// writeln("Cost: ",tree.computeCost());
}
}
/*
struct BVHBuilder2
{
mixin ECS.System!1;
mixin ECS.WritableDependencies!(BVHDependency);
struct EntitiesData
{
}
BVHTree* tree;
void onCreate()
{
tree = gEM.getSystem!BVHBuilder().tree;
}
bool onBegin()
{
//if(tree.nodes.length-1 != tree.root)tree.clear();
return true;
}
void onUpdate(EntitiesData data)
{
if(tree.nodes.length-1 != tree.root)
{
tree.generateBottomUp();
import std.stdio;
writeln("Cost: ",tree.computeCost());
}
}
}//*/
struct AABBUpdater
{
mixin ECS.System!64;
struct EntitiesData
{
uint length;
//uint thread_id;
const (Entity)[] entity;
CAABB[] bounding;
@readonly CLocation[] location;
@readonly CScale[] scale;
@optional @readonly CRotation[] rotation;
}
void onAddEntity(EntitiesData data)
{
foreach(i; 0..data.length)
{
data.bounding[i] = AABB(data.location[i]-data.scale[i],data.location[i]+data.scale[i]);
}
}
void onUpdate(EntitiesData data)
{
foreach(i; 0..data.length)
{
data.bounding[i] = AABB(data.location[i]-data.scale[i],data.location[i]+data.scale[i]);
}
}
}

View file

@ -33,6 +33,11 @@ struct GUIManager
int selected_template = 0; int selected_template = 0;
int selected_component = 0; int selected_component = 0;
~this()
{
clear();
}
void selectTemplate(int id) void selectTemplate(int id)
{ {
if(templates.length == 0)return; if(templates.length == 0)return;
@ -133,6 +138,7 @@ struct GUIManager
edit_components.length = comp.component_id+1;//.extend(comp.component_id + 1); edit_components.length = comp.component_id+1;//.extend(comp.component_id + 1);
} }
//edit_components[comp.component_id] = ComponentEditGUI(name); //edit_components[comp.component_id] = ComponentEditGUI(name);
if(edit_components[comp.component_id].variables)return;
ComponentEditGUI comp_edit; ComponentEditGUI comp_edit;
comp_edit.name = T.stringof; comp_edit.name = T.stringof;
//enum fields = __traits(allMembers, T); //enum fields = __traits(allMembers, T);

View file

@ -55,6 +55,7 @@ struct Texture
data.bpp = surf.format.BytesPerPixel; data.bpp = surf.format.BytesPerPixel;
data.data = Mallocator.makeArray!ubyte(surf.w*surf.h*surf.format.BytesPerPixel); data.data = Mallocator.makeArray!ubyte(surf.w*surf.h*surf.format.BytesPerPixel);
data.data[0..$] = (cast(ubyte*)surf.pixels)[0..data.data.length]; data.data[0..$] = (cast(ubyte*)surf.pixels)[0..data.data.length];
data.size = ivec2(surf.w, surf.h);
SDL_FreeSurface(surf); SDL_FreeSurface(surf);
@ -67,8 +68,8 @@ struct Texture
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
if(data.bpp == 3)glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,surf.w,surf.h,0,GL_RGB,GL_UNSIGNED_BYTE,data.data.ptr); if(data.bpp == 3)glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,data.size.x,data.size.y,0,GL_RGB,GL_UNSIGNED_BYTE,data.data.ptr);
else if(data.bpp == 4)glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,surf.w,surf.h,0,GL_RGBA,GL_UNSIGNED_BYTE,data.data.ptr); else if(data.bpp == 4)glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,data.size.x,data.size.y,0,GL_RGBA,GL_UNSIGNED_BYTE,data.data.ptr);
else return false; else return false;
} }
@ -82,7 +83,7 @@ struct Texture
glBindTexture(GL_TEXTURE_2D, data.gl_handle); glBindTexture(GL_TEXTURE_2D, data.gl_handle);
} }
void destory() @nogc nothrow void destroy() @nogc nothrow
{ {
if(data) if(data)
{ {

View file

@ -44,6 +44,11 @@ struct vec2
else static assert(0, "Operator "~op~" not implemented"); else static assert(0, "Operator "~op~" not implemented");
} }
vec2 opUnary(string op)()if (op == "-")
{
return vec2(-x,-y);
}
ivec2 opCast() ivec2 opCast()
{ {
return ivec2(cast(int)x,cast(int)y); return ivec2(cast(int)x,cast(int)y);

View file

@ -12,6 +12,8 @@ extern(C) float sinf(float x) @nogc nothrow @system;
extern(C) float cosf(float x) @nogc nothrow @system; extern(C) float cosf(float x) @nogc nothrow @system;
extern(C) float powf(float x, float y) @nogc nothrow @system; extern(C) float powf(float x, float y) @nogc nothrow @system;
extern(C) float fabs(float x) @nogc nothrow @system; extern(C) float fabs(float x) @nogc nothrow @system;
extern(C) float log2f(float arg) @nogc nothrow @system;
int randomRange(int min, int max) nothrow @nogc @trusted int randomRange(int min, int max) nothrow @nogc @trusted
{ {