Huge demos update

-moved C stdlib function definitions to ecs_utils.utils
-added function to calculate mix(linear interpolation) and rsqrt(fast inverse sqrt)
-added some math to vec2 (length, normalize...)
-improved renderer with possibility to use multiple materials (one per block, not perfect solution for parallel compute, but works with some requirements)
-added blending support for material (opaque, additive, mixed)
-added Android support
-added gprahical representation for mouse tools (tool_circle.d)
-added initial support for editing template components variables
-better Component and Templates listing
-added possibility to add/removes components using mouse
-move CLocation to game_core.basic and reuse in every test
-moved tools code from demos to App (now code is fully separated from demos!)
-some improvement and fixes in Snake demo, with additional systems to handle adding and removing entities
-added new demo: Particles. By now demo has several particles to spawn and support for attractors and vortexes (calculation is made as every attractor with every entity)
-fixed bug with window hover and tools
-improved tool behaviour
-added new material
-now window is always opened as maximized windowed mode
-some minor fixes and improvements
This commit is contained in:
Mergul 2020-06-06 22:46:29 +02:00
parent 13e6ed8fd5
commit e76c5ccdb2
20 changed files with 1804 additions and 288 deletions

View file

@ -0,0 +1,20 @@
module gui.attributes;
enum GUIColor = "GUIColor";
struct GUIRange
{
union
{
struct
{
int min;
int max;
}
struct
{
float minf;
float maxf;
}
}
}

View file

@ -1,6 +1,61 @@
module gui.components;
module gui.component;
import ecs_utils.utils;
struct ComponentGUI
{
}
const (char)* name;
void* data;
ushort component_id;
}
struct ComponentEditGUI
{
const (char)* name;
VariableGUI[] variables;
uint used;
}
struct VariableGUI
{
struct Int
{
int min;
int max;
}
struct Float
{
float min;
float max;
}
struct Enum
{
const (char)[][] strings;
}
enum Type
{
byte_,
ubyte_,
short_,
ushort_,
int_,
uint_,
float_,
enum_,
color,
vec2,
ivec2
}
Type type;
const (char)* name;
ushort offset;
union
{
Int int_;
Float float_;
Enum enum_;
}
}

View file

@ -4,22 +4,32 @@ import app;
import cimgui.cimgui;
import bubel.ecs.entity;
import bubel.ecs.manager;
import bubel.ecs.std;
import bubel.ecs.system;
import bubel.ecs.vector;
import bubel.ecs.entity;
import ecs_utils.math.vector;
import gui.attributes;
import gui.component;
import gui.system;
import gui.template_;
import std.traits;
extern(C):
struct GUIManager
{
Vector!SystemGUI systems;
Vector!ComponentGUI components;
Vector!TemplateGUI templates;
Vector!ComponentEditGUI edit_components;
uint selected_tempalte = 0;
uint selected_component = 0;
void clear()
{
@ -27,10 +37,22 @@ struct GUIManager
{
launcher.manager.freeTemplate(tmpl.tmpl);
}
foreach(comp; components)
{
free(comp.data);
}
foreach(ref comp; edit_components)
{
if(comp.variables)Mallocator.dispose(comp.variables);
comp.variables = null;
comp.used = 0;
}
systems.clear();
templates.clear();
components.clear();
selected_tempalte = 0;
selected_component = 0;
}
EntityTemplate* getSelectedTemplate()
@ -39,6 +61,12 @@ struct GUIManager
else return null;
}
ComponentRef getSelectedComponent()
{
if(components.length > selected_component)return ComponentRef(components[selected_component].data, components[selected_component].component_id);
else return ComponentRef(null, ushort.max);
}
void addSystem(ushort id, const (char)* name, bool enabled = true)
{
System* system = launcher.manager.getSystem(id);
@ -56,9 +84,112 @@ struct GUIManager
templates.add(TemplateGUI(name, tmpl));
}
// void addComponent(ComponentRef comp, const (char)* name)
// {
// uint size = EntityManager.instance.components[comp.component_id].size;
// void* data = malloc(size);
// memcpy(data, comp.ptr, size);
// components.add(ComponentGUI(name, data, comp.component_id));
// }
void addComponent(T)(T comp, const (char)* name)
{
static assert(hasStaticMember!(T,"component_id"));
uint size = EntityManager.instance.components[comp.component_id].size;
void* data = malloc(size);
memcpy(data, &comp, size);
components.add(ComponentGUI(name, data, comp.component_id));
if(edit_components.length <= comp.component_id)
{
edit_components.length = comp.component_id+1;//.extend(comp.component_id + 1);
}
//edit_components[comp.component_id] = ComponentEditGUI(name);
ComponentEditGUI comp_edit;
comp_edit.name = T.stringof;
//enum fields = __traits(allMembers, T);
alias fields = FieldNameTuple!T;
//pragma(msg,fields);
comp_edit.variables = Mallocator.makeArray!VariableGUI(fields.length);
foreach(member_str; fields)
{
alias member = __traits(getMember, T, member_str);
alias member_type = typeof(member);
//pragma(msg,member);
//pragma(msg,member_type);
//pragma(msg,__traits(getMember, T, member).offsetof);
ushort offset = member.offsetof;//cast(ushort)__traits(getMember, T, member).offsetof;
static if(__traits(isIntegral,member_type))
{
static if(__traits(isUnsigned, member_type))
{
static if(hasUDA!(member,GUIColor))
{
comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.color,member_str,offset);
}
else switch(member_type.sizeof)
{
case 1: comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.ubyte_,member_str,offset);break;
case 2: comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.ushort_,member_str,offset);break;
case 4: comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.uint_,member_str,offset);break;
default:break;
}
static if(hasUDA!(member,GUIRange))
{
comp_edit.variables[comp_edit.used-1].int_.min = getUDAs!(member,GUIRange)[0].min;
comp_edit.variables[comp_edit.used-1].int_.max = getUDAs!(member,GUIRange)[0].max;
}
else
{
comp_edit.variables[comp_edit.used-1].int_.min = 0;
comp_edit.variables[comp_edit.used-1].int_.max = int.max;
}
}
else
{
switch(member_type.sizeof)
{
case 1: comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.byte_,member_str,offset);break;
case 2: comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.short_,member_str,offset);break;
case 4: comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.int_,member_str,offset);break;
default:break;
}
static if(hasUDA!(member,GUIRange))
{
comp_edit.variables[comp_edit.used-1].int_.min = getUDAs!(member,GUIRange)[0].min;
comp_edit.variables[comp_edit.used-1].int_.max = getUDAs!(member,GUIRange)[1].max;
}
{
comp_edit.variables[comp_edit.used-1].int_.min = int.min;
comp_edit.variables[comp_edit.used-1].int_.max = int.max;
}
}
}
else static if(__traits(isScalar,member_type))
{
switch(member_type.sizeof)
{
case 4:comp_edit.variables[comp_edit.used++] = VariableGUI(VariableGUI.Type.float_,member_str,offset);break;
case 8:
default:break;
}
static if(hasUDA!(member,GUIRange))
{
comp_edit.variables[comp_edit.used-1].float_.min = getUDAs!(member,GUIRange)[0].minf;
comp_edit.variables[comp_edit.used-1].float_.max = getUDAs!(member,GUIRange)[1].maxf;
}
{
comp_edit.variables[comp_edit.used-1].float_.min = -float.max;
comp_edit.variables[comp_edit.used-1].float_.max = float.max;
}
}
}
edit_components[comp.component_id] = comp_edit;
}
void gui()
{
if(igCollapsingHeader("Systems", ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_FramePadding))
if(igCollapsingHeader("Systems", ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_DefaultOpen))
{
bool true_ = true;
igIndent(8);
@ -74,25 +205,177 @@ struct GUIManager
}
}
void toolGui()
static vec4 colorUintToVec4(uint color)
{
if(templates.length)
// color = *cast(uint*)(comp_ptr+var.offset);
return vec4(cast(float)(color & 0xFF) / 255,
cast(float)(color >> 8 & 0xFF) / 255,
cast(float)(color >> 16 & 0xFF) / 255,
cast(float)(color >> 24 & 0xFF) / 255);
}
static uint colorVec4ToUint(vec4 color)
{
return cast(uint)(color.x * 255) |
cast(uint)(color.y * 255) << 8 |
cast(uint)(color.z * 255) << 16 |
cast(uint)(color.w * 255) << 24;
}
static bool igDragScalarClamp(const(char)* label, ImGuiDataType data_type, void* v, float v_speed, const(void)* v_min, const(void)* v_max, const(char)* format, float power)
{
ubyte[8] v_backup;// = *v;
final switch(data_type)
{
if(igBeginCombo("Template",templates[selected_tempalte].name,0))
{
foreach(i, tmpl; templates)
{
if(igSelectable(tmpl.name,false,0,ImVec2(0,0)))
{
selected_tempalte = cast(uint)i;
}
}
igEndCombo();
}
case ImGuiDataType_S8:memcpy(v_backup.ptr, v, 1);break;
case ImGuiDataType_S16:memcpy(v_backup.ptr, v, 2);break;
case ImGuiDataType_S32:memcpy(v_backup.ptr, v, 4);break;
case ImGuiDataType_U8:memcpy(v_backup.ptr, v, 1);break;
case ImGuiDataType_U16:memcpy(v_backup.ptr, v, 2);break;
case ImGuiDataType_U32:memcpy(v_backup.ptr, v, 4);break;
case ImGuiDataType_Float:memcpy(v_backup.ptr, v, 4);break;
}
else
if (!igDragScalar(label, data_type, v, v_speed, v_min, v_max, format, power))
return false;
final switch(data_type)
{
if(igBeginCombo("Template",null,0))igEndCombo();
case ImGuiDataType_S8:
if(*cast(byte*)v < *cast(byte*)v_min)*cast(byte*)v = *cast(byte*)v_min;
else if(*cast(byte*)v > *cast(byte*)v_max)*cast(byte*)v = *cast(byte*)v_max;
return *cast(byte*)v != *cast(byte*)v_backup.ptr;
case ImGuiDataType_S16:
if(*cast(short*)v < *cast(short*)v_min)*cast(short*)v = *cast(short*)v_min;
else if(*cast(short*)v > *cast(short*)v_max)*cast(short*)v = *cast(short*)v_max;
return *cast(short*)v != *cast(short*)v_backup.ptr;
case ImGuiDataType_S32:
if(*cast(int*)v < *cast(int*)v_min)*cast(int*)v = *cast(int*)v_min;
else if(*cast(int*)v > *cast(int*)v_max)*cast(int*)v = *cast(int*)v_max;
return *cast(int*)v != *cast(int*)v_backup.ptr;
case ImGuiDataType_U8:
if(*cast(ubyte*)v < *cast(ubyte*)v_min)*cast(ubyte*)v = *cast(ubyte*)v_min;
else if(*cast(ubyte*)v > *cast(ubyte*)v_max)*cast(ubyte*)v = *cast(ubyte*)v_max;
return *cast(ubyte*)v != *cast(ubyte*)v_backup.ptr;
case ImGuiDataType_U16:
if(*cast(ushort*)v < *cast(ushort*)v_min)*cast(ushort*)v = *cast(ushort*)v_min;
else if(*cast(ushort*)v > *cast(ushort*)v_max)*cast(ushort*)v = *cast(ushort*)v_max;
return *cast(ushort*)v != *cast(ushort*)v_backup.ptr;
case ImGuiDataType_U32:
if(*cast(uint*)v < *cast(uint*)v_min)*cast(uint*)v = *cast(uint*)v_min;
else if(*cast(uint*)v > *cast(uint*)v_max)*cast(uint*)v = *cast(uint*)v_max;
return *cast(uint*)v != *cast(uint*)v_backup.ptr;
case ImGuiDataType_Float:
if(*cast(float*)v < *cast(float*)v_min)*cast(float*)v = *cast(float*)v_min;
else if(*cast(float*)v > *cast(float*)v_max)*cast(float*)v = *cast(float*)v_max;
return *cast(float*)v != *cast(float*)v_backup.ptr;
}
}
void entityComponentsGUI()
{
EntityTemplate* tmpl = templates[selected_tempalte].tmpl;
EntityManager.EntityInfo* info = tmpl.info;
void* data_ptr = tmpl.entity_data.ptr;
vec4 color;
foreach(comp_id; info.components)
{
if(comp_id >= edit_components.length)break;
void* comp_ptr = data_ptr + info.tmpl_deltas[comp_id];
if(edit_components[comp_id].used)
{
if(igCollapsingHeader(edit_components[comp_id].name, ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_DefaultOpen))
{
igIndent(8);
foreach(ref VariableGUI var;edit_components[comp_id].variables[0 .. edit_components[comp_id].used])
{
switch(var.type)
{
case VariableGUI.Type.byte_:
igDragScalarClamp(var.name, ImGuiDataType_S8, comp_ptr+var.offset, 1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1);
break;
case VariableGUI.Type.ubyte_:
igDragScalarClamp(var.name, ImGuiDataType_U8, comp_ptr+var.offset, 1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1);
break;
case VariableGUI.Type.short_:
igDragScalarClamp(var.name, ImGuiDataType_S16, comp_ptr+var.offset, 1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1);
break;
case VariableGUI.Type.ushort_:
igDragScalarClamp(var.name, ImGuiDataType_U16, comp_ptr+var.offset, 1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1);
break;
case VariableGUI.Type.int_:
igDragScalarClamp(var.name, ImGuiDataType_S32, comp_ptr+var.offset, 1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1);
break;
case VariableGUI.Type.uint_:
igDragScalarClamp(var.name, ImGuiDataType_U32, comp_ptr+var.offset, 1, cast(void*)&var.int_.min, cast(void*)&var.int_.max, null, 1);
break;
case VariableGUI.Type.float_:
igDragScalarClamp(var.name, ImGuiDataType_Float, comp_ptr+var.offset, 1, cast(void*)&var.float_.min, cast(void*)&var.float_.max, null, 1);
break;
case VariableGUI.Type.color:
color = colorUintToVec4(*cast(uint*)(comp_ptr+var.offset));
if(igColorEdit4(var.name, color.data, ImGuiColorEditFlags_None))
*cast(uint*)(comp_ptr+var.offset) = colorVec4ToUint(color);
break;
default:break;
}
}
igUnindent(8);
}
}
}
}
void toolGui()
{
ImGuiStyle * style = igGetStyle();
ImVec4 col = style.Colors[ImGuiCol_Header];
style.Colors[ImGuiCol_Header] = style.Colors[ImGuiCol_TextSelectedBg];
//style.
//ImDrawList* draw_list = igGetWindowDrawList();
final switch(launcher.used_tool)
{
case Tool.entity_spawner:
if(templates.length)
{
{
if(igListBoxHeaderInt("Template",cast(int)templates.length,cast(int)templates.length))
{
foreach(i, tmpl; templates)
{
if(igSelectable(tmpl.name,selected_tempalte == i,ImGuiSelectableFlags_AllowDoubleClick,ImVec2(0,0)))
{
selected_tempalte = cast(uint)i;
}
}
igListBoxFooter();
}
}
}
style.Colors[ImGuiCol_Header] = col;
entityComponentsGUI();
break;
case Tool.component_manipulator:
if(components.length)
{
if(igListBoxHeaderInt("Components",cast(int)components.length,cast(int)components.length))
{
{
foreach(i, comp; components)
{
if(igSelectable(comp.name,selected_component == i,0,ImVec2(0,0)))
{
selected_component = cast(uint)i;
}
}
igListBoxFooter();
}
}
}
break;
case Tool.selector:
break;
}
style.Colors[ImGuiCol_Header] = col;
}
}

View file

@ -0,0 +1,52 @@
module gui.tool_circle;
import ecs_utils.gfx.buffer;
import ecs_utils.gfx.shader;
import ecs_utils.gfx.config;
import ecs_utils.gfx.renderer;
import ecs_utils.math.vector;
version(WebAssembly)import glad.gl.gles2;
else version(Android)import glad.gl.gles2;
else import glad.gl.gl;
struct ToolCircle
{
//Buffer vbo;
//Buffer ibo;
uint material_id = 1;
uint mesh_id = 0;
/*/void generate()
{
ushort[]
}*/
void draw(Renderer* renderer, vec2 position, float size, float edge = 1)
{
position = position * renderer.view_size + renderer.view_pos;
vec2 sizes = renderer.view_size * size;
vec2 sizes2 = vec2(edge,0);
import core.stdc.string;
ubyte[32] uniform_block;
void* ptr = uniform_block.ptr;
*cast(float*)(ptr) = sizes.x;
*cast(float*)(ptr+4) = 0;
*cast(float*)(ptr+8) = 0;
*cast(float*)(ptr+12) = sizes.y;
memcpy(ptr+16,position.data.ptr,8);
memcpy(ptr+24,sizes2.data.ptr,8);
glEnableVertexAttribArray(0);
GfxConfig.meshes[mesh_id].bind();
GfxConfig.materials[material_id].bind();
GfxConfig.materials[material_id].pushBindings();
GfxConfig.materials[material_id].pushUniforms(uniform_block.ptr);
//glDisable(GL_DEPTH_TEST);
glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_SHORT,null);
}
}