283 lines
No EOL
9.9 KiB
D
283 lines
No EOL
9.9 KiB
D
module demos.simple;
|
|
|
|
import app;
|
|
|
|
import bindbc.sdl;
|
|
|
|
import bubel.ecs.attributes;
|
|
import bubel.ecs.core;
|
|
import bubel.ecs.entity;
|
|
import bubel.ecs.manager;
|
|
import bubel.ecs.std;
|
|
|
|
import cimgui.cimgui;
|
|
|
|
import ecs_utils.gfx.texture;
|
|
import ecs_utils.math.vector;
|
|
import ecs_utils.utils;
|
|
|
|
import game_core.basic;
|
|
import game_core.rendering;
|
|
|
|
extern(C):
|
|
|
|
enum float px = 1.0/512.0;
|
|
|
|
/**************************************************
|
|
All demos uses same patten. Every demo is self contained except systems and components which was splitted into different files to enable sharing them between demos.
|
|
Every demo has same functions:
|
|
* register - called on start for registering proces
|
|
* initialize - called after register to initialize demo data
|
|
* deinitiliaze - called when demo is switching. There data is deisposed
|
|
* loop - it's called every frame
|
|
|
|
Demos uses some non-ECS functions to register components, systems and templates into GUI. Then components are showing by GUI and can be added to entities.
|
|
*/
|
|
|
|
/*#######################################################################################################################
|
|
------------------------------------------------ Components ------------------------------------------------------------------
|
|
#######################################################################################################################*/
|
|
|
|
//CLocation component was moved to game_code.basic
|
|
/*struct CLocation
|
|
{
|
|
mixin ECS.Component;
|
|
|
|
alias location this;
|
|
|
|
vec2 location;
|
|
}*/
|
|
|
|
/*#######################################################################################################################
|
|
------------------------------------------------ Systems ------------------------------------------------------------------
|
|
#######################################################################################################################*/
|
|
//DrawSystem was moved to game_code.basic
|
|
/*
|
|
struct DrawSystem
|
|
{
|
|
mixin ECS.System!32;
|
|
|
|
struct EntitiesData
|
|
{
|
|
uint length;
|
|
//uint thread_id;
|
|
uint job_id;
|
|
@readonly CLocation[] locations;
|
|
}
|
|
|
|
void onUpdate(EntitiesData data)
|
|
{
|
|
if(launcher.renderer.prepared_items >= launcher.renderer.MaxObjects)return;//simple leave loop if max visible objects count was reached
|
|
import ecs_utils.gfx.renderer;
|
|
Renderer.DrawData draw_data;
|
|
draw_data.size = vec2(16,16);
|
|
draw_data.coords = vec4(0,0,1,1);
|
|
draw_data.color = 0x80808080;
|
|
draw_data.material_id = 0;
|
|
draw_data.thread_id = data.job_id;
|
|
draw_data.texture = simple.texture;
|
|
|
|
foreach(i; 0..data.length)
|
|
{
|
|
draw_data.position = data.locations[i];
|
|
draw_data.depth = cast(ushort)(data.locations[i].y);
|
|
launcher.renderer.draw(draw_data);
|
|
}
|
|
}
|
|
}*/
|
|
|
|
//simple system which moves entities
|
|
struct MoveSystem
|
|
{
|
|
//system will generate up to 64 jobs for multithreaded extecution
|
|
mixin ECS.System!64;
|
|
|
|
//structe contains components used by system
|
|
struct EntitiesData
|
|
{
|
|
uint length;
|
|
//system will use one component which is required. Only entities with CLocation component will be processed by this system
|
|
CLocation[] locations;
|
|
}
|
|
|
|
//onUpdate is called several times and covers all entities
|
|
void onUpdate(EntitiesData data)
|
|
{
|
|
//loop over entities in batch
|
|
foreach(i; 0..data.length)
|
|
{
|
|
//inscrease entity position in 'y' coordinate
|
|
data.locations[i].y = data.locations[i].y + 1;
|
|
//move entity to 0 if exceeded 300
|
|
if(data.locations[i].y > 300)data.locations[i].y = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*#######################################################################################################################
|
|
------------------------------------------------ Functions ------------------------------------------------------------------
|
|
#######################################################################################################################*/
|
|
|
|
struct Simple
|
|
{
|
|
//tips showed in GUI
|
|
__gshared const (char)* tips = "Use \"space\" to spwan entities.\n\nSystems can be enabled/disabled from \"Demo\" window.
|
|
\"Tools\" window exists of three tools which can be used to manipulate game.
|
|
Options:
|
|
* Show Tool - enable/disable rendering of blue circle around cursor
|
|
* Show Filtered - enable/disable higliting filtered entities. For \"Component manipulator\" tool it shows entities which has selected component.
|
|
* Add/Remove - select primary action. LMB - primary action, RMB - secondary action
|
|
* Tools size - size of tool
|
|
* Tool repeat - how many times in one second tool should take action (e.g. 1000 means every second \"Entity spawner\" will spawn 1000 enties)
|
|
* Override - enabled means that \"Component manipulator\" will override components data if entity already has that component
|
|
Tools:
|
|
* Entity spawner - used to spawn new entities
|
|
* Component manipulator - used to add/remove components to/from entities
|
|
* Selector - allow to select entity, show and modify his data. Only one entity can be selected, selector selects entity nearest co cursor.
|
|
|
|
ShortCuts:
|
|
* CRTL*1/2/3 - change tool
|
|
* Mouse wheel - change tool size
|
|
* SHIFT + Mouse wheel - change entity/component in tool list
|
|
* LBM - primary action (default: add entity / add component)
|
|
* RMB - secondary action (default: remove entity / remove component)
|
|
|
|
\"Statistic\" windows shows FPS and entities count.
|
|
|
|
From top menu bar (upper left corner) you can select different demos or change some options. Multihtreading is highly recommended, but it can not working on mobile phones or Firefox browser.
|
|
|
|
Demo is capable rendering of hundreds of thousands of entities. Playable area is heavily too small to show that count of entities, but you can try it :)";
|
|
|
|
EntityTemplate* tmpl;
|
|
Texture texture;
|
|
}
|
|
|
|
__gshared Simple* simple;
|
|
|
|
//called when demo starts
|
|
void simpleRegister()
|
|
{
|
|
simple = Mallocator.make!Simple;
|
|
|
|
//load texture (atlas)
|
|
simple.texture.create();
|
|
simple.texture.load("assets/textures/atlas.png");
|
|
|
|
//start registering process
|
|
gEntityManager.beginRegister();
|
|
|
|
//register basic components and systems
|
|
registerRenderingModule(gEntityManager);
|
|
|
|
//register location component. It also registered inside registerRenderingModule() function, but it's there for clarity
|
|
gEntityManager.registerComponent!CLocation;
|
|
|
|
gEntityManager.registerSystem!MoveSystem(0);
|
|
// DrawSystem is registered as RenderingModule
|
|
// gEntityManager.registerSystem!DrawSystem(1);
|
|
|
|
//end registering process
|
|
gEntityManager.endRegister();
|
|
}
|
|
|
|
//called after simpleRegister
|
|
void simpleStart()
|
|
{
|
|
//get DrawSystem instance and change some data
|
|
DrawSystem* draw_system = gEntityManager.getSystem!DrawSystem;
|
|
draw_system.default_data.color = 0x80808080;
|
|
draw_system.default_data.texture = simple.texture;
|
|
draw_system.default_data.size = vec2(16,16);
|
|
draw_system.default_data.coords = vec4(0,48,16,16)*px;//vec4(0,0,1,1);
|
|
|
|
//add systems to GUI. It's non ECS part
|
|
launcher.gui_manager.addSystem(becsID!MoveSystem,"Move Up System");
|
|
launcher.gui_manager.addSystem(becsID!DrawSystem,"Draw System");
|
|
|
|
//add components to GUI. It's non ECS part
|
|
launcher.gui_manager.addComponent(CLocation(), "Location");
|
|
launcher.gui_manager.addComponent(CDrawDefault(), "DrawDefault");
|
|
|
|
//allocate new template with two components
|
|
simple.tmpl = gEntityManager.allocateTemplate([becsID!CLocation, becsID!CDrawDefault].staticArray);
|
|
|
|
//add template to GUI. It's non ECS part
|
|
launcher.gui_manager.addTemplate(simple.tmpl, "Basic");
|
|
|
|
//add 100 entities
|
|
foreach(i; 0..10)
|
|
foreach(j; 0..10)
|
|
{
|
|
//add entities in grid locations. "ref_" return ComponentRef structure. I'm not sure if adding component inside array generation isn't undefined behaviour but it works on tested platforms
|
|
gEntityManager.addEntity(simple.tmpl,[CLocation(vec2(i*16+64,j*16+64)).ref_].staticArray);
|
|
}
|
|
}
|
|
|
|
//called when demo is switched to different one
|
|
void simpleEnd()
|
|
{
|
|
//disable systems used by this demo.
|
|
gEntityManager.getSystem(becsID!MoveSystem).disable();
|
|
gEntityManager.getSystem(becsID!DrawSystem).disable();
|
|
|
|
//free texture memory
|
|
simple.texture.destroy();
|
|
|
|
//GUI manager will free template
|
|
//gEntityManager.freeTemplate(simple.tmpl);
|
|
Mallocator.dispose(simple);
|
|
}
|
|
|
|
void simpleEvent(SDL_Event* event)
|
|
{
|
|
}
|
|
|
|
void spawnEntity()
|
|
{
|
|
//spawn entity in random location
|
|
gEntityManager.addEntity(simple.tmpl,[CLocation(vec2(randomf() * 400,0)).ref_].staticArray);
|
|
}
|
|
|
|
bool simpleLoop()
|
|
{
|
|
launcher.render_position = (vec2(launcher.window_size.x,launcher.window_size.y)*launcher.scalling - vec2(400,300)) * 0.5;
|
|
|
|
if(launcher.getKeyState(SDL_SCANCODE_SPACE))
|
|
{
|
|
foreach(i;0..20)spawnEntity();
|
|
}
|
|
|
|
//begin frame
|
|
gEntityManager.begin();
|
|
//if multithreading is enabled different path is used
|
|
if(launcher.multithreading)
|
|
{
|
|
//prepare data for multithreading. Clear previous jobs data.
|
|
launcher.job_updater.begin();
|
|
//generate jobs
|
|
gEntityManager.updateMT();
|
|
//call jobs in multithreaded fashion
|
|
launcher.job_updater.call();
|
|
}
|
|
else
|
|
{
|
|
//update call will call inUpdate for all systems
|
|
gEntityManager.update();
|
|
|
|
}
|
|
//end ECS frame
|
|
gEntityManager.end();
|
|
|
|
return true;
|
|
}
|
|
|
|
DemoCallbacks getSimpleDemo()
|
|
{
|
|
DemoCallbacks demo;
|
|
demo.register = &simpleRegister;
|
|
demo.initialize = &simpleStart;
|
|
demo.deinitialize = &simpleEnd;
|
|
demo.loop = &simpleLoop;
|
|
demo.tips = simple.tips;
|
|
return demo;
|
|
} |