|
|
@@ -188,15 +188,6 @@ namespace state_machine_internal
|
|
|
u32 speed_bytecode;
|
|
|
u32 loop;
|
|
|
|
|
|
- StateInfo()
|
|
|
- : animations(default_allocator())
|
|
|
- , transitions(default_allocator())
|
|
|
- , speed(default_allocator())
|
|
|
- , speed_bytecode(UINT32_MAX)
|
|
|
- , loop(0)
|
|
|
- {
|
|
|
- }
|
|
|
-
|
|
|
explicit StateInfo(Allocator& a)
|
|
|
: animations(a)
|
|
|
, transitions(a)
|
|
|
@@ -215,12 +206,6 @@ namespace state_machine_internal
|
|
|
StringId32 name;
|
|
|
float value;
|
|
|
|
|
|
- VariableInfo()
|
|
|
- : name_string(default_allocator())
|
|
|
- , value(0.0f)
|
|
|
- {
|
|
|
- }
|
|
|
-
|
|
|
explicit VariableInfo(Allocator& a)
|
|
|
: name_string(a)
|
|
|
, value(0.0f)
|
|
|
@@ -247,18 +232,67 @@ namespace state_machine_internal
|
|
|
{
|
|
|
}
|
|
|
|
|
|
- s32 parse(Buffer& buf)
|
|
|
+ s32 parse_animations(StateInfo& si, const JsonArray& animations)
|
|
|
{
|
|
|
- TempAllocator4096 ta;
|
|
|
- JsonObject obj(ta);
|
|
|
- JsonArray states(ta);
|
|
|
- JsonArray variables(ta);
|
|
|
+ for (u32 i = 0; i < array::size(animations); ++i)
|
|
|
+ {
|
|
|
+ TempAllocator4096 ta;
|
|
|
+ JsonObject animation(ta);
|
|
|
+ sjson::parse_object(animation, animations[i]);
|
|
|
|
|
|
- sjson::parse(obj, buf);
|
|
|
- sjson::parse_array(states, obj["states"]);
|
|
|
- sjson::parse_array(variables, obj["variables"]);
|
|
|
+ DynamicString animation_resource(ta);
|
|
|
+ sjson::parse_string(animation_resource, animation["name"]);
|
|
|
+ DATA_COMPILER_ASSERT_RESOURCE_EXISTS("sprite_animation"
|
|
|
+ , animation_resource.c_str()
|
|
|
+ , _opts
|
|
|
+ );
|
|
|
+ _opts.add_requirement("sprite_animation", animation_resource.c_str());
|
|
|
+
|
|
|
+ AnimationInfo ai(ta);
|
|
|
+ ai.name = sjson::parse_resource_name(animation["name"]);
|
|
|
+ sjson::parse_string(ai.weight, animation["weight"]);
|
|
|
+
|
|
|
+ vector::push_back(si.animations, ai);
|
|
|
+ }
|
|
|
+ DATA_COMPILER_ASSERT(vector::size(si.animations) > 0
|
|
|
+ , _opts
|
|
|
+ , "State must contain one animation at least"
|
|
|
+ );
|
|
|
+
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
|
|
|
- // Parse states
|
|
|
+ s32 parse_transitions(StateInfo& si, const JsonArray& transitions)
|
|
|
+ {
|
|
|
+ for (u32 i = 0; i < array::size(transitions); ++i)
|
|
|
+ {
|
|
|
+ TempAllocator4096 ta;
|
|
|
+ JsonObject transition(ta);
|
|
|
+ sjson::parse_object(transition, transitions[i]);
|
|
|
+
|
|
|
+ DynamicString mode_str(ta);
|
|
|
+ sjson::parse_string(mode_str, transition["mode"]);
|
|
|
+ const u32 mode = name_to_transition_mode(mode_str.c_str());
|
|
|
+ DATA_COMPILER_ASSERT(mode != TransitionMode::COUNT
|
|
|
+ , _opts
|
|
|
+ , "Unknown transition mode: '%s'"
|
|
|
+ , mode_str.c_str()
|
|
|
+ );
|
|
|
+
|
|
|
+ TransitionInfo ti;
|
|
|
+ ti.transition.event = sjson::parse_string_id(transition["event"]);
|
|
|
+ ti.transition.state_offset = UINT32_MAX;
|
|
|
+ ti.transition.mode = mode;
|
|
|
+ ti.state = sjson::parse_guid(transition["to"]);
|
|
|
+
|
|
|
+ vector::push_back(si.transitions, ti);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ s32 parse_states(const JsonArray& states)
|
|
|
+ {
|
|
|
for (u32 i = 0; i < array::size(states); ++i)
|
|
|
{
|
|
|
TempAllocator4096 ta;
|
|
|
@@ -269,63 +303,12 @@ namespace state_machine_internal
|
|
|
sjson::parse_array(animations, state["animations"]);
|
|
|
sjson::parse_array(transitions, state["transitions"]);
|
|
|
|
|
|
- StateInfo si;
|
|
|
-
|
|
|
+ StateInfo si(ta);
|
|
|
sjson::parse_string(si.speed, state["speed"]);
|
|
|
si.loop = sjson::parse_bool(state["loop"]);
|
|
|
|
|
|
- // Parse transitions
|
|
|
- {
|
|
|
- for (u32 i = 0; i < array::size(transitions); ++i)
|
|
|
- {
|
|
|
- JsonObject transition(ta);
|
|
|
- sjson::parse_object(transition, transitions[i]);
|
|
|
-
|
|
|
- DynamicString mode_str(ta);
|
|
|
- sjson::parse_string(mode_str, transition["mode"]);
|
|
|
- const u32 mode = name_to_transition_mode(mode_str.c_str());
|
|
|
- DATA_COMPILER_ASSERT(mode != TransitionMode::COUNT
|
|
|
- , _opts
|
|
|
- , "Unknown transition mode: '%s'"
|
|
|
- , mode_str.c_str()
|
|
|
- );
|
|
|
-
|
|
|
- TransitionInfo ti;
|
|
|
- ti.transition.event = sjson::parse_string_id(transition["event"]);
|
|
|
- ti.transition.state_offset = UINT32_MAX;
|
|
|
- ti.transition.mode = mode;
|
|
|
- ti.state = sjson::parse_guid(transition["to"]);
|
|
|
-
|
|
|
- vector::push_back(si.transitions, ti);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Parse animations
|
|
|
- {
|
|
|
- for (u32 i = 0; i < array::size(animations); ++i)
|
|
|
- {
|
|
|
- JsonObject animation(ta);
|
|
|
- sjson::parse_object(animation, animations[i]);
|
|
|
-
|
|
|
- DynamicString animation_resource(ta);
|
|
|
- sjson::parse_string(animation_resource, animation["name"]);
|
|
|
- DATA_COMPILER_ASSERT_RESOURCE_EXISTS("sprite_animation"
|
|
|
- , animation_resource.c_str()
|
|
|
- , _opts
|
|
|
- );
|
|
|
- _opts.add_requirement("sprite_animation", animation_resource.c_str());
|
|
|
-
|
|
|
- AnimationInfo ai(ta);
|
|
|
- ai.name = sjson::parse_resource_name(animation["name"]);
|
|
|
- sjson::parse_string(ai.weight, animation["weight"]);
|
|
|
-
|
|
|
- vector::push_back(si.animations, ai);
|
|
|
- }
|
|
|
- DATA_COMPILER_ASSERT(vector::size(si.animations) > 0
|
|
|
- , _opts
|
|
|
- , "State must contain one animation at least"
|
|
|
- );
|
|
|
- }
|
|
|
+ parse_transitions(si, transitions);
|
|
|
+ parse_animations(si, animations);
|
|
|
|
|
|
Guid guid = sjson::parse_guid(state["id"]);
|
|
|
DATA_COMPILER_ASSERT(!hash_map::has(_states, guid)
|
|
|
@@ -334,103 +317,132 @@ namespace state_machine_internal
|
|
|
);
|
|
|
hash_map::set(_states, guid, si);
|
|
|
}
|
|
|
- DATA_COMPILER_ASSERT(hash_map::size(_states) > 0
|
|
|
- , _opts
|
|
|
- , "State machine must contain one state at least"
|
|
|
- );
|
|
|
|
|
|
- _initial_state = sjson::parse_guid(obj["initial_state"]);
|
|
|
- DATA_COMPILER_ASSERT(hash_map::has(_states, _initial_state)
|
|
|
- , _opts
|
|
|
- , "Initial state references non-existing state"
|
|
|
- );
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
|
|
|
- // Parse variables
|
|
|
+ s32 parse_variables(const JsonArray& variables)
|
|
|
+ {
|
|
|
+ for (u32 i = 0; i < array::size(variables); ++i)
|
|
|
{
|
|
|
- for (u32 i = 0; i < array::size(variables); ++i)
|
|
|
- {
|
|
|
- JsonObject variable(ta);
|
|
|
- sjson::parse_object(variable, variables[i]);
|
|
|
+ TempAllocator4096 ta;
|
|
|
+ JsonObject variable(ta);
|
|
|
+ sjson::parse_object(variable, variables[i]);
|
|
|
|
|
|
- VariableInfo vi;
|
|
|
- vi.name = sjson::parse_string_id(variable["name"]);
|
|
|
- vi.value = sjson::parse_float(variable["value"]);
|
|
|
- sjson::parse_string(vi.name_string, variable["name"]);
|
|
|
+ VariableInfo vi(ta);
|
|
|
+ vi.name = sjson::parse_string_id(variable["name"]);
|
|
|
+ vi.value = sjson::parse_float(variable["value"]);
|
|
|
+ sjson::parse_string(vi.name_string, variable["name"]);
|
|
|
|
|
|
- vector::push_back(_variables, vi);
|
|
|
- }
|
|
|
+ vector::push_back(_variables, vi);
|
|
|
}
|
|
|
|
|
|
- // Compute state offsets
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ s32 compute_state_offsets()
|
|
|
+ {
|
|
|
+ // Limit byte code to 4K
|
|
|
+ array::resize(_byte_code, 1024);
|
|
|
+ u32 written = 0;
|
|
|
+
|
|
|
+ const u32 num_variables = vector::size(_variables);
|
|
|
+ const char** variables = (const char**)default_allocator().allocate(num_variables*sizeof(char*));
|
|
|
+
|
|
|
+ for (u32 i = 0; i < num_variables; ++i)
|
|
|
+ variables[i] = _variables[i].name_string.c_str();
|
|
|
+
|
|
|
+ const u32 num_constants = 1;
|
|
|
+ const char* constants[] =
|
|
|
+ {
|
|
|
+ "PI"
|
|
|
+ };
|
|
|
+ const f32 constant_values[] =
|
|
|
+ {
|
|
|
+ PI
|
|
|
+ };
|
|
|
+
|
|
|
+ auto cur = hash_map::begin(_states);
|
|
|
+ auto end = hash_map::end(_states);
|
|
|
+ for (; cur != end; ++cur)
|
|
|
{
|
|
|
- // Limit byte code to 4K
|
|
|
- array::resize(_byte_code, 1024);
|
|
|
- u32 written = 0;
|
|
|
+ HASH_MAP_SKIP_HOLE(_states, cur);
|
|
|
|
|
|
- const u32 num_variables = vector::size(_variables);
|
|
|
- const char** variables = (const char**)default_allocator().allocate(num_variables*sizeof(char*));
|
|
|
+ const Guid& guid = cur->first;
|
|
|
+ const StateInfo& si = cur->second;
|
|
|
|
|
|
- for (u32 i = 0; i < num_variables; ++i)
|
|
|
- variables[i] = _variables[i].name_string.c_str();
|
|
|
+ const u32 offset = _offset_accumulator.offset(vector::size(si.animations), vector::size(si.transitions));
|
|
|
+ hash_map::set(_offsets, guid, offset);
|
|
|
|
|
|
- const u32 num_constants = 1;
|
|
|
- const char* constants[] =
|
|
|
+ for (u32 i = 0; i < vector::size(si.animations); ++i)
|
|
|
{
|
|
|
- "PI"
|
|
|
- };
|
|
|
- const f32 constant_values[] =
|
|
|
- {
|
|
|
- PI
|
|
|
- };
|
|
|
+ const u32 num = skinny::expression_language::compile(si.animations[i].weight.c_str()
|
|
|
+ , num_variables
|
|
|
+ , variables
|
|
|
+ , num_constants
|
|
|
+ , constants
|
|
|
+ , constant_values
|
|
|
+ , array::begin(_byte_code) + written
|
|
|
+ , array::size(_byte_code)
|
|
|
+ );
|
|
|
|
|
|
- auto cur = hash_map::begin(_states);
|
|
|
- auto end = hash_map::end(_states);
|
|
|
- for (; cur != end; ++cur)
|
|
|
- {
|
|
|
- HASH_MAP_SKIP_HOLE(_states, cur);
|
|
|
-
|
|
|
- const Guid& guid = cur->first;
|
|
|
- const StateInfo& si = cur->second;
|
|
|
-
|
|
|
- const u32 offset = _offset_accumulator.offset(vector::size(si.animations), vector::size(si.transitions));
|
|
|
- hash_map::set(_offsets, guid, offset);
|
|
|
-
|
|
|
- for (u32 i = 0; i < vector::size(si.animations); ++i)
|
|
|
- {
|
|
|
- const u32 num = skinny::expression_language::compile(si.animations[i].weight.c_str()
|
|
|
- , num_variables
|
|
|
- , variables
|
|
|
- , num_constants
|
|
|
- , constants
|
|
|
- , constant_values
|
|
|
- , array::begin(_byte_code) + written
|
|
|
- , array::size(_byte_code)
|
|
|
- );
|
|
|
-
|
|
|
- const_cast<AnimationInfo&>(si.animations[i]).bytecode_entry = num > 0 ? written : UINT32_MAX;
|
|
|
- written += num;
|
|
|
- }
|
|
|
-
|
|
|
- const u32 num = skinny::expression_language::compile(si.speed.c_str()
|
|
|
- , num_variables
|
|
|
- , variables
|
|
|
- , num_constants
|
|
|
- , constants
|
|
|
- , constant_values
|
|
|
- , array::begin(_byte_code) + written
|
|
|
- , array::size(_byte_code)
|
|
|
- );
|
|
|
-
|
|
|
- const_cast<StateInfo&>(si).speed_bytecode = num > 0 ? written : UINT32_MAX;
|
|
|
+ const_cast<AnimationInfo&>(si.animations[i]).bytecode_entry = num > 0 ? written : UINT32_MAX;
|
|
|
written += num;
|
|
|
}
|
|
|
|
|
|
- // Resize to total amount of written bytecode
|
|
|
- array::resize(_byte_code, written);
|
|
|
+ const u32 num = skinny::expression_language::compile(si.speed.c_str()
|
|
|
+ , num_variables
|
|
|
+ , variables
|
|
|
+ , num_constants
|
|
|
+ , constants
|
|
|
+ , constant_values
|
|
|
+ , array::begin(_byte_code) + written
|
|
|
+ , array::size(_byte_code)
|
|
|
+ );
|
|
|
|
|
|
- default_allocator().deallocate(variables);
|
|
|
+ const_cast<StateInfo&>(si).speed_bytecode = num > 0 ? written : UINT32_MAX;
|
|
|
+ written += num;
|
|
|
}
|
|
|
|
|
|
+ // Resize to total amount of written bytecode
|
|
|
+ array::resize(_byte_code, written);
|
|
|
+
|
|
|
+ default_allocator().deallocate(variables);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ s32 parse(Buffer& buf)
|
|
|
+ {
|
|
|
+ TempAllocator4096 ta;
|
|
|
+ JsonObject obj(ta);
|
|
|
+ JsonArray states(ta);
|
|
|
+ JsonArray variables(ta);
|
|
|
+
|
|
|
+ sjson::parse(obj, buf);
|
|
|
+ sjson::parse_array(states, obj["states"]);
|
|
|
+ sjson::parse_array(variables, obj["variables"]);
|
|
|
+
|
|
|
+ s32 err = 0;
|
|
|
+ err = parse_states(states);
|
|
|
+ DATA_COMPILER_ENSURE(err == 0, _opts);
|
|
|
+ DATA_COMPILER_ASSERT(hash_map::size(_states) > 0
|
|
|
+ , _opts
|
|
|
+ , "State machine must contain one state at least"
|
|
|
+ );
|
|
|
+
|
|
|
+ _initial_state = sjson::parse_guid(obj["initial_state"]);
|
|
|
+ DATA_COMPILER_ASSERT(hash_map::has(_states, _initial_state)
|
|
|
+ , _opts
|
|
|
+ , "Initial state references non-existing state"
|
|
|
+ );
|
|
|
+
|
|
|
+ err = parse_variables(variables);
|
|
|
+ DATA_COMPILER_ENSURE(err == 0, _opts);
|
|
|
+
|
|
|
+ err = compute_state_offsets();
|
|
|
+ DATA_COMPILER_ENSURE(err == 0, _opts);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
@@ -517,8 +529,9 @@ namespace state_machine_internal
|
|
|
Buffer buf = opts.read();
|
|
|
|
|
|
StateMachineCompiler smc(opts);
|
|
|
- if (smc.parse(buf) != 0)
|
|
|
- return -1;
|
|
|
+ s32 err = 0;
|
|
|
+ err = smc.parse(buf);
|
|
|
+ DATA_COMPILER_ENSURE(err == 0, opts);
|
|
|
|
|
|
return smc.write();
|
|
|
}
|