LumixEngine/src/animation/condition.h
2018-08-19 17:35:37 +02:00

263 lines
No EOL
4.1 KiB
C++

#pragma once
#include "engine/array.h"
#include "engine/hash_map.h"
#include "engine/lumix.h"
#include <cstring>
namespace Lumix
{
class Animation;
struct IAllocator;
class OutputBlob;
namespace Anim
{
typedef HashMap<u32, Animation*> AnimSet;
struct RunningContext
{
float time_delta;
u8* input;
IAllocator* allocator;
struct ComponentInstance* current;
struct Edge* edge;
AnimSet* anim_set;
OutputBlob* event_stream;
EntityRef controller;
};
struct InputDecl
{
enum Type : int
{
// don't change order
FLOAT,
INT,
BOOL,
EMPTY
};
struct Constant
{
Type type = EMPTY;
union
{
float f_value;
int i_value;
bool b_value;
};
StaticString<32> name;
};
struct Input
{
Type type = EMPTY;
int offset;
StaticString<32> name;
};
Input inputs[32];
int inputs_count = 0;
Constant constants[32];
int constants_count = 0;
int inputFromLinearIdx(int idx) const
{
for (int i = 0; i < lengthOf(inputs); ++i)
{
if (inputs[i].type == EMPTY) continue;
if (idx == 0) return i;
--idx;
}
return -1;
}
int inputToLinearIdx(int idx) const
{
int linear = 0;
for (int i = 0; i < lengthOf(inputs); ++i)
{
if (i == idx) return inputs[i].type == EMPTY ? -1 : linear;
if (inputs[i].type == EMPTY) continue;
++linear;
}
return -1;
}
void removeInput(int index)
{
inputs[index].type = EMPTY;
--inputs_count;
}
void removeConstant(int index)
{
constants[index].type = EMPTY;
--constants_count;
}
void moveConstant(int old_idx, int new_idx)
{
if (old_idx == new_idx) return;
ASSERT(constants[new_idx].type == EMPTY);
constants[new_idx] = constants[old_idx];
constants[old_idx].type = EMPTY;
}
void moveInput(int old_idx, int new_idx)
{
if (old_idx == new_idx) return;
ASSERT(inputs[new_idx].type == EMPTY);
inputs[new_idx] = inputs[old_idx];
inputs[old_idx].type = EMPTY;
recalculateOffsets();
}
int addInput()
{
ASSERT(inputs_count < lengthOf(inputs));
for (int i = 0; i < lengthOf(inputs); ++i)
{
if (inputs[i].type == EMPTY)
{
inputs[i].name = "";
inputs[i].type = BOOL;
++inputs_count;
recalculateOffsets();
return i;
}
}
return -1;
}
int addConstant()
{
ASSERT(constants_count < lengthOf(constants));
for (int i = 0; i < lengthOf(constants); ++i)
{
if (constants[i].type == EMPTY)
{
constants[i].name = "";
constants[i].type = BOOL;
++constants_count;
return i;
}
}
return -1;
}
int getInputsCount() const
{
return inputs_count;
}
int getSize() const
{
if (inputs_count == 0) return 0;
int size = 0;
for (const auto& input : inputs)
{
if(input.type != EMPTY) size = Math::maximum(size, input.offset + getSize(input.type));
}
return size;
}
static int getSize(Type type)
{
switch (type)
{
case FLOAT: return sizeof(float);
case INT: return sizeof(int);
case BOOL: return sizeof(bool);
default: ASSERT(false); return 1;
}
}
void recalculateOffsets()
{
if (inputs_count == 0) return;
int last_offset = 0;
for(auto& input : inputs)
{
if (input.type == EMPTY) continue;
input.offset = last_offset;
last_offset += getSize(input.type);
}
}
int getInputIdx(const char* name, int size) const
{
for (int i = 0; i < lengthOf(inputs); ++i)
{
if (inputs[i].type == Type::EMPTY) continue;
if (strncmp(inputs[i].name, name, size) == 0) return i;
}
return -1;
}
int getConstantIdx(const char* name, int size) const
{
for (int i = 0; i < lengthOf(constants); ++i)
{
if (constants[i].type != Type::EMPTY && strncmp(constants[i].name, name, size) == 0) return i;
}
return -1;
}
};
struct Condition
{
enum class Error
{
NONE,
UNKNOWN_IDENTIFIER,
MISSING_LEFT_PARENTHESIS,
MISSING_RIGHT_PARENTHESIS,
UNEXPECTED_CHAR,
OUT_OF_MEMORY,
MISSING_BINARY_OPERAND,
NOT_ENOUGH_PARAMETERS,
INCORRECT_TYPE_ARGS,
NO_RETURN_VALUE
};
static const char* errorToString(Error error);
explicit Condition(IAllocator& allocator);
bool operator()(RunningContext& rc);
Error compile(const char* expression, InputDecl& decl);
Array<u8> bytecode;
};
} // namespace Anim
} // namespace Lumix