[update] Splitted the large source files.
This commit is contained in:
parent
aa44c004af
commit
c760bd6b9b
105
sjplayer/src/sjplayer/AbstractScheduledController.d
Normal file
105
sjplayer/src/sjplayer/AbstractScheduledController.d
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/// License: MIT
|
||||||
|
module sjplayer.AbstractScheduledController;
|
||||||
|
|
||||||
|
import std.algorithm,
|
||||||
|
std.exception,
|
||||||
|
std.typecons;
|
||||||
|
|
||||||
|
import sjscript;
|
||||||
|
|
||||||
|
import sjplayer.ScheduledControllerInterface,
|
||||||
|
sjplayer.VarStoreInterface,
|
||||||
|
sjplayer.util.Parameter,
|
||||||
|
sjplayer.util.Period;
|
||||||
|
|
||||||
|
///
|
||||||
|
abstract class AbstractScheduledController : ScheduledControllerInterface {
|
||||||
|
public:
|
||||||
|
///
|
||||||
|
this(in VarStoreInterface varstore, in ParametersBlock[] operations) {
|
||||||
|
varstore_ = varstore;
|
||||||
|
operations_ = operations;
|
||||||
|
}
|
||||||
|
|
||||||
|
override void Operate(float time) {
|
||||||
|
FinalizeCurrentOperationIfEnded(time);
|
||||||
|
PrepareNextOperationIfStarted(time);
|
||||||
|
ProcessCurrentOperationIfAvailable(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static struct VarStore {
|
||||||
|
public:
|
||||||
|
float opIndex(string name) const {
|
||||||
|
if (!time_.isNull && name == "time") return time_.get;
|
||||||
|
return this_.GetVariable(name);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
AbstractScheduledController this_;
|
||||||
|
Nullable!float time_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrepareOperation(ref in ParametersBlock params) {
|
||||||
|
user_vars_.clear();
|
||||||
|
|
||||||
|
auto vars = VarStore(this);
|
||||||
|
params.parameters.
|
||||||
|
filter!(x => x.type == ParameterType.OnceAssign).
|
||||||
|
each !(x => SetParameter(x, vars));
|
||||||
|
}
|
||||||
|
void ProcessOperation(float time, ref in ParametersBlock params) {
|
||||||
|
auto vars = VarStore(this, time.nullable);
|
||||||
|
params.parameters.
|
||||||
|
filter!(x => x.type != ParameterType.OnceAssign).
|
||||||
|
each !(x => SetParameter(x, vars));
|
||||||
|
}
|
||||||
|
void FinalizeOperation(ref in ParametersBlock params) {
|
||||||
|
}
|
||||||
|
|
||||||
|
float GetVariable(string name) const {
|
||||||
|
if (name in user_vars_) return user_vars_[name];
|
||||||
|
return varstore_[name];
|
||||||
|
}
|
||||||
|
void SetParameter(ref in Parameter param, ref in VarStore vars) {
|
||||||
|
(param.name.length >= 2 && param.name[0..2] == "__").
|
||||||
|
enforce("user defined variables must be prefixed '__'");
|
||||||
|
user_vars_[param.name] = 0;
|
||||||
|
param.CalculateParameter(user_vars_[param.name], vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void FinalizeCurrentOperationIfEnded(float time) {
|
||||||
|
if (next_operation_index_ < 1) return;
|
||||||
|
|
||||||
|
const current = &operations_[next_operation_index_-1];
|
||||||
|
if (current.period.end > time) return;
|
||||||
|
|
||||||
|
FinalizeOperation(*current);
|
||||||
|
}
|
||||||
|
void PrepareNextOperationIfStarted(float time) {
|
||||||
|
if (next_operation_index_ >= operations_.length) return;
|
||||||
|
|
||||||
|
const next = &operations_[next_operation_index_];
|
||||||
|
if (next.period.start > time) return;
|
||||||
|
|
||||||
|
++next_operation_index_;
|
||||||
|
PrepareOperation(*next);
|
||||||
|
}
|
||||||
|
void ProcessCurrentOperationIfAvailable(float time) {
|
||||||
|
if (next_operation_index_ < 1) return;
|
||||||
|
|
||||||
|
const current = &operations_[next_operation_index_-1];
|
||||||
|
if (current.period.end <= time) return;
|
||||||
|
|
||||||
|
ProcessOperation(
|
||||||
|
current.period.ConvertToRelativeTime(time), *current);
|
||||||
|
}
|
||||||
|
|
||||||
|
const VarStoreInterface varstore_;
|
||||||
|
|
||||||
|
const ParametersBlock[] operations_;
|
||||||
|
|
||||||
|
size_t next_operation_index_;
|
||||||
|
|
||||||
|
float[string] user_vars_;
|
||||||
|
}
|
@ -7,7 +7,8 @@ import std.algorithm,
|
|||||||
|
|
||||||
import gl4d;
|
import gl4d;
|
||||||
|
|
||||||
import sjplayer.ElementInterface;
|
import sjplayer.ElementDrawerInterface,
|
||||||
|
sjplayer.ElementInterface;
|
||||||
|
|
||||||
///
|
///
|
||||||
class CircleElement : ElementInterface {
|
class CircleElement : ElementInterface {
|
||||||
@ -24,7 +25,8 @@ class CircleElement : ElementInterface {
|
|||||||
align(1) vec4 color = vec4(0, 0, 0, 0);
|
align(1) vec4 color = vec4(0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
override void Initialize() {
|
///
|
||||||
|
void Initialize() {
|
||||||
alive = false;
|
alive = false;
|
||||||
damage = 0;
|
damage = 0;
|
||||||
nearness_coe = 0;
|
nearness_coe = 0;
|
||||||
|
@ -4,6 +4,7 @@ module sjplayer.CircleElementScheduledController;
|
|||||||
import std.typecons;
|
import std.typecons;
|
||||||
|
|
||||||
import sjplayer.CircleElement,
|
import sjplayer.CircleElement,
|
||||||
|
sjplayer.ElementScheduledControllerFactory,
|
||||||
sjplayer.ScheduledController;
|
sjplayer.ScheduledController;
|
||||||
|
|
||||||
///
|
///
|
||||||
|
@ -9,6 +9,7 @@ import sjscript;
|
|||||||
|
|
||||||
import sjplayer.Background,
|
import sjplayer.Background,
|
||||||
sjplayer.ContextBuilderInterface,
|
sjplayer.ContextBuilderInterface,
|
||||||
|
sjplayer.ElementDrawerInterface,
|
||||||
sjplayer.ElementInterface,
|
sjplayer.ElementInterface,
|
||||||
sjplayer.ProgramSet,
|
sjplayer.ProgramSet,
|
||||||
sjplayer.ScheduledControllerInterface,
|
sjplayer.ScheduledControllerInterface,
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
/// License: MIT
|
/// License: MIT
|
||||||
module sjplayer.ContextBuilderInterface;
|
module sjplayer.ContextBuilderInterface;
|
||||||
|
|
||||||
import sjplayer.ElementInterface,
|
import sjplayer.ElementDrawerInterface,
|
||||||
|
sjplayer.ElementInterface,
|
||||||
sjplayer.ScheduledControllerInterface;
|
sjplayer.ScheduledControllerInterface;
|
||||||
|
|
||||||
///
|
///
|
||||||
|
9
sjplayer/src/sjplayer/ElementDrawerInterface.d
Normal file
9
sjplayer/src/sjplayer/ElementDrawerInterface.d
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
/// License: MIT
|
||||||
|
module sjplayer.ElementDrawerInterface;
|
||||||
|
|
||||||
|
///
|
||||||
|
interface ElementDrawerInterface {
|
||||||
|
public:
|
||||||
|
///
|
||||||
|
void Draw();
|
||||||
|
}
|
@ -14,16 +14,6 @@ interface ElementInterface {
|
|||||||
float nearness;
|
float nearness;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
|
||||||
void Initialize();
|
|
||||||
|
|
||||||
///
|
///
|
||||||
DamageCalculationResult CalculateDamage(vec2 p1, vec2 p2) const;
|
DamageCalculationResult CalculateDamage(vec2 p1, vec2 p2) const;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
|
||||||
interface ElementDrawerInterface {
|
|
||||||
public:
|
|
||||||
///
|
|
||||||
void Draw();
|
|
||||||
}
|
|
||||||
|
98
sjplayer/src/sjplayer/ElementScheduledControllerFactory.d
Normal file
98
sjplayer/src/sjplayer/ElementScheduledControllerFactory.d
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
/// License: MIT
|
||||||
|
module sjplayer.ElementScheduledControllerFactory;
|
||||||
|
|
||||||
|
import sjscript;
|
||||||
|
|
||||||
|
import std.algorithm,
|
||||||
|
std.array,
|
||||||
|
std.conv,
|
||||||
|
std.meta,
|
||||||
|
std.range.primitives,
|
||||||
|
std.traits;
|
||||||
|
|
||||||
|
import sjplayer.ContextBuilderInterface,
|
||||||
|
sjplayer.ElementDrawerInterface,
|
||||||
|
sjplayer.ElementInterface,
|
||||||
|
sjplayer.ProgramSet,
|
||||||
|
sjplayer.ScheduledControllerInterface,
|
||||||
|
sjplayer.VarStoreInterface,
|
||||||
|
sjplayer.util.Period;
|
||||||
|
|
||||||
|
///
|
||||||
|
struct ElementScheduledControllerFactory(ScheduledController, ElementDrawer)
|
||||||
|
if (is(ScheduledController : ScheduledControllerInterface) &&
|
||||||
|
is(ElementDrawer : ElementDrawerInterface)) {
|
||||||
|
public:
|
||||||
|
/// ScheduledController's first constructor's first argument type.
|
||||||
|
alias Element =
|
||||||
|
Parameters!(__traits(getOverloads, ScheduledController, "__ctor")[0])[0];
|
||||||
|
|
||||||
|
static assert(is(Element : ElementInterface));
|
||||||
|
|
||||||
|
/// ElementDrawer's first constructor's first argument type.
|
||||||
|
alias ElementProgram =
|
||||||
|
Parameters!(__traits(getOverloads, ElementDrawer, "__ctor")[0])[0];
|
||||||
|
|
||||||
|
static assert(staticIndexOf!(
|
||||||
|
ElementProgram, ProgramSet.Programs.Types) >= 0);
|
||||||
|
static assert(is(Element[] :
|
||||||
|
Parameters!(__traits(getOverloads, ElementDrawer, "__ctor")[0])[1]));
|
||||||
|
|
||||||
|
///
|
||||||
|
this(ProgramSet programs, VarStoreInterface varstore) {
|
||||||
|
program_ = programs.Get!ElementProgram;
|
||||||
|
varstore_ = varstore;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
void Create(R)(R params, ContextBuilderInterface builder)
|
||||||
|
if (isInputRange!R && is(ElementType!R == ParametersBlock)) {
|
||||||
|
auto parallelized = ParallelizeParams(params);
|
||||||
|
auto elements = appender!(Element[]);
|
||||||
|
|
||||||
|
foreach (ref serial; parallelized) {
|
||||||
|
auto element = new Element;
|
||||||
|
elements ~= element;
|
||||||
|
builder.AddElement(element);
|
||||||
|
builder.AddScheduledController(
|
||||||
|
new ScheduledController(element, varstore_, serial));
|
||||||
|
}
|
||||||
|
if (elements[].length > 0) {
|
||||||
|
builder.AddElementDrawer(new ElementDrawer(program_, elements[]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static ParametersBlock[][] ParallelizeParams(R)(R params)
|
||||||
|
if (isInputRange!R && is(ElementType!R == ParametersBlock)) {
|
||||||
|
ParametersBlock[][] parallelized;
|
||||||
|
foreach (ref param; params) {
|
||||||
|
auto inserted = false;
|
||||||
|
foreach (ref serial; parallelized) {
|
||||||
|
const found_index = serial.
|
||||||
|
countUntil!(x => x.period.start > param.period.start);
|
||||||
|
const insert_index =
|
||||||
|
found_index >= 0? found_index.to!size_t: serial.length;
|
||||||
|
|
||||||
|
const intersect_prev = insert_index >= 1 &&
|
||||||
|
IsPeriodIntersectedToPeriod(serial[insert_index-1].period, param.period);
|
||||||
|
const intersect_next = insert_index < serial.length &&
|
||||||
|
IsPeriodIntersectedToPeriod(serial[insert_index].period, param.period);
|
||||||
|
|
||||||
|
if (!intersect_prev && !intersect_next) {
|
||||||
|
serial = serial[0..insert_index]~ param ~serial[insert_index..$];
|
||||||
|
inserted = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!inserted) {
|
||||||
|
parallelized ~= [param];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return parallelized;
|
||||||
|
}
|
||||||
|
|
||||||
|
ElementProgram program_;
|
||||||
|
|
||||||
|
VarStoreInterface varstore_;
|
||||||
|
}
|
@ -1,60 +1,51 @@
|
|||||||
/// License: MIT
|
/// License: MIT
|
||||||
module sjplayer.ScheduledController;
|
module sjplayer.ScheduledController;
|
||||||
|
|
||||||
import std.algorithm,
|
import std.traits,
|
||||||
std.array,
|
|
||||||
std.conv,
|
|
||||||
std.meta,
|
|
||||||
std.range.primitives,
|
|
||||||
std.traits,
|
|
||||||
std.typecons;
|
std.typecons;
|
||||||
|
|
||||||
import gl4d;
|
import gl4d;
|
||||||
|
|
||||||
import sjscript;
|
import sjscript;
|
||||||
|
|
||||||
import sjplayer.ContextBuilderInterface,
|
import sjplayer.AbstractScheduledController,
|
||||||
sjplayer.ElementInterface,
|
|
||||||
sjplayer.ProgramSet,
|
|
||||||
sjplayer.ScheduledControllerInterface,
|
sjplayer.ScheduledControllerInterface,
|
||||||
sjplayer.VarStoreInterface,
|
sjplayer.VarStoreInterface,
|
||||||
sjplayer.util.MatrixFactory,
|
sjplayer.util.MatrixFactory,
|
||||||
sjplayer.util.Parameter,
|
sjplayer.util.Parameter;
|
||||||
sjplayer.util.Period;
|
|
||||||
|
|
||||||
///
|
///
|
||||||
class ScheduledController(
|
class ScheduledController(
|
||||||
Element, string[string] ParameterNameMap) :
|
Target, string[string] ParameterNameMap) : AbstractScheduledController {
|
||||||
AbstractScheduledControllerWithOperationImpl {
|
|
||||||
public:
|
public:
|
||||||
///
|
///
|
||||||
enum AliveManagementAvailable =
|
enum AliveManagementAvailable =
|
||||||
is(typeof((Element e) => e.alive)) &&
|
is(typeof((Target x) => x.alive)) &&
|
||||||
is(ReturnType!((Element e) => e.alive) == bool);
|
is(ReturnType!((Target x) => x.alive) == bool);
|
||||||
///
|
///
|
||||||
enum MatrixModificationAvailable =
|
enum MatrixModificationAvailable =
|
||||||
is(typeof((Element e) => e.matrix)) &&
|
is(typeof((Target x) => x.matrix)) &&
|
||||||
is(ReturnType!((Element e) => e.matrix) == mat3);
|
is(ReturnType!((Target x) => x.matrix) == mat3);
|
||||||
///
|
///
|
||||||
enum AutoInitializationAvailable =
|
enum AutoInitializationAvailable =
|
||||||
is(typeof((Element e) => e.Initialize()));
|
is(typeof((Target x) => x.Initialize()));
|
||||||
|
|
||||||
///
|
///
|
||||||
this(
|
this(
|
||||||
Element element,
|
Target target,
|
||||||
in VarStoreInterface varstore,
|
in VarStoreInterface varstore,
|
||||||
in ParametersBlock[] operations) {
|
in ParametersBlock[] operations) {
|
||||||
super(varstore, operations);
|
super(varstore, operations);
|
||||||
element_ = element;
|
target_ = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
override void PrepareOperation(ref in ParametersBlock params) {
|
override void PrepareOperation(ref in ParametersBlock params) {
|
||||||
static if (AutoInitializationAvailable) {
|
static if (AutoInitializationAvailable) {
|
||||||
element_.Initialize();
|
target_.Initialize();
|
||||||
}
|
}
|
||||||
static if (AliveManagementAvailable) {
|
static if (AliveManagementAvailable) {
|
||||||
element_.alive = true;
|
target_.alive = true;
|
||||||
}
|
}
|
||||||
static if (MatrixModificationAvailable) {
|
static if (MatrixModificationAvailable) {
|
||||||
matrix_factory_ = matrix_factory_.init;
|
matrix_factory_ = matrix_factory_.init;
|
||||||
@ -64,12 +55,12 @@ class ScheduledController(
|
|||||||
override void ProcessOperation(float time, ref in ParametersBlock params) {
|
override void ProcessOperation(float time, ref in ParametersBlock params) {
|
||||||
super.ProcessOperation(time, params);
|
super.ProcessOperation(time, params);
|
||||||
static if (MatrixModificationAvailable) {
|
static if (MatrixModificationAvailable) {
|
||||||
element_.matrix = matrix_factory_.Create().transposed;
|
target_.matrix = matrix_factory_.Create().transposed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
override void FinalizeOperation(ref in ParametersBlock params) {
|
override void FinalizeOperation(ref in ParametersBlock params) {
|
||||||
static if (AliveManagementAvailable) {
|
static if (AliveManagementAvailable) {
|
||||||
element_.alive = false;
|
target_.alive = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,17 +68,16 @@ class ScheduledController(
|
|||||||
switch (name) {
|
switch (name) {
|
||||||
static foreach (map_name, code; ParameterNameMap) {
|
static foreach (map_name, code; ParameterNameMap) {
|
||||||
case map_name:
|
case map_name:
|
||||||
return mixin("element_."~code);
|
return mixin("target_."~code);
|
||||||
}
|
}
|
||||||
default: return super.GetVariable(name);
|
default: return super.GetVariable(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
override void SetParameter(Nullable!float time, ref in Parameter param) {
|
override void SetParameter(ref in Parameter param, ref in VarStore vars) {
|
||||||
auto vars = VarStore(this, time);
|
|
||||||
switch (param.name) {
|
switch (param.name) {
|
||||||
static foreach (map_name, code; ParameterNameMap) {
|
static foreach (map_name, code; ParameterNameMap) {
|
||||||
case map_name:
|
case map_name:
|
||||||
param.CalculateParameter(mixin("element_."~code), vars);
|
param.CalculateParameter(mixin("target_."~code), vars);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -95,90 +85,12 @@ class ScheduledController(
|
|||||||
static if (MatrixModificationAvailable) {
|
static if (MatrixModificationAvailable) {
|
||||||
if (param.CalculateMatrixParameter(matrix_factory_, vars)) return;
|
if (param.CalculateMatrixParameter(matrix_factory_, vars)) return;
|
||||||
}
|
}
|
||||||
super.SetParameter(time, param);
|
super.SetParameter(param, vars);
|
||||||
}
|
}
|
||||||
|
|
||||||
Element element_;
|
Target target_;
|
||||||
|
|
||||||
static if (MatrixModificationAvailable) {
|
static if (MatrixModificationAvailable) {
|
||||||
MatrixFactory matrix_factory_;
|
MatrixFactory matrix_factory_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
|
||||||
struct ElementScheduledControllerFactory(ScheduledController, ElementDrawer)
|
|
||||||
if (is(ScheduledController : ScheduledControllerInterface) &&
|
|
||||||
is(ElementDrawer : ElementDrawerInterface)) {
|
|
||||||
public:
|
|
||||||
/// ScheduledController's first constructor's first argument type.
|
|
||||||
alias Element =
|
|
||||||
Parameters!(__traits(getOverloads, ScheduledController, "__ctor")[0])[0];
|
|
||||||
|
|
||||||
static assert(is(Element : ElementInterface));
|
|
||||||
|
|
||||||
/// ElementDrawer's first constructor's first argument type.
|
|
||||||
alias ElementProgram =
|
|
||||||
Parameters!(__traits(getOverloads, ElementDrawer, "__ctor")[0])[0];
|
|
||||||
|
|
||||||
static assert(staticIndexOf!(
|
|
||||||
ElementProgram, ProgramSet.Programs.Types) >= 0);
|
|
||||||
static assert(is(Element[] :
|
|
||||||
Parameters!(__traits(getOverloads, ElementDrawer, "__ctor")[0])[1]));
|
|
||||||
|
|
||||||
///
|
|
||||||
this(ProgramSet programs, VarStoreInterface varstore) {
|
|
||||||
program_ = programs.Get!ElementProgram;
|
|
||||||
varstore_ = varstore;
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
void Create(R)(R params, ContextBuilderInterface builder)
|
|
||||||
if (isInputRange!R && is(ElementType!R == ParametersBlock)) {
|
|
||||||
auto parallelized = params.ParallelizeParams();
|
|
||||||
auto elements = appender!(Element[]);
|
|
||||||
|
|
||||||
foreach (ref serial; parallelized) {
|
|
||||||
auto element = new Element;
|
|
||||||
elements ~= element;
|
|
||||||
builder.AddElement(element);
|
|
||||||
builder.AddScheduledController(
|
|
||||||
new ScheduledController(element, varstore_, serial));
|
|
||||||
}
|
|
||||||
if (elements[].length > 0) {
|
|
||||||
builder.AddElementDrawer(new ElementDrawer(program_, elements[]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
ElementProgram program_;
|
|
||||||
VarStoreInterface varstore_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ParametersBlock[][] ParallelizeParams(R)(R params)
|
|
||||||
if (isInputRange!R && is(ElementType!R == ParametersBlock)) {
|
|
||||||
ParametersBlock[][] parallelized;
|
|
||||||
foreach (ref param; params) {
|
|
||||||
auto inserted = false;
|
|
||||||
foreach (ref serial; parallelized) {
|
|
||||||
const found_index = serial.
|
|
||||||
countUntil!(x => x.period.start > param.period.start);
|
|
||||||
const insert_index =
|
|
||||||
found_index >= 0? found_index.to!size_t: serial.length;
|
|
||||||
|
|
||||||
const intersect_prev = insert_index >= 1 &&
|
|
||||||
IsPeriodIntersectedToPeriod(serial[insert_index-1].period, param.period);
|
|
||||||
const intersect_next = insert_index < serial.length &&
|
|
||||||
IsPeriodIntersectedToPeriod(serial[insert_index].period, param.period);
|
|
||||||
|
|
||||||
if (!intersect_prev && !intersect_next) {
|
|
||||||
serial = serial[0..insert_index]~ param ~serial[insert_index..$];
|
|
||||||
inserted = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!inserted) {
|
|
||||||
parallelized ~= [param];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return parallelized;
|
|
||||||
}
|
|
||||||
|
@ -1,121 +1,9 @@
|
|||||||
/// License: MIT
|
/// License: MIT
|
||||||
module sjplayer.ScheduledControllerInterface;
|
module sjplayer.ScheduledControllerInterface;
|
||||||
|
|
||||||
import std.algorithm,
|
|
||||||
std.array,
|
|
||||||
std.exception,
|
|
||||||
std.format,
|
|
||||||
std.typecons;
|
|
||||||
|
|
||||||
import sjscript;
|
|
||||||
|
|
||||||
import sjplayer.VarStoreInterface,
|
|
||||||
sjplayer.util.Parameter,
|
|
||||||
sjplayer.util.Period;
|
|
||||||
|
|
||||||
///
|
///
|
||||||
interface ScheduledControllerInterface {
|
interface ScheduledControllerInterface {
|
||||||
public:
|
public:
|
||||||
///
|
///
|
||||||
void Operate(float time);
|
void Operate(float time);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
|
||||||
abstract class AbstractScheduledController : ScheduledControllerInterface {
|
|
||||||
public:
|
|
||||||
/// The operations must be sorted.
|
|
||||||
this(in ParametersBlock[] operations) {
|
|
||||||
operations_ = operations;
|
|
||||||
}
|
|
||||||
|
|
||||||
override void Operate(float time) {
|
|
||||||
scope(exit) last_operation_time_ = time;
|
|
||||||
|
|
||||||
if (next_operation_index_ >= 1) {
|
|
||||||
assert(next_operation_index_ <= operations_.length);
|
|
||||||
|
|
||||||
const last_operation = &operations_[next_operation_index_-1];
|
|
||||||
const period = last_operation.period;
|
|
||||||
if (IsTimeInPeriod(time, period)) {
|
|
||||||
ProcessOperation(period.ConvertToRelativeTime(time), *last_operation);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
FinalizeOperation(*last_operation);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (next_operation_index_ >= operations_.length) return;
|
|
||||||
|
|
||||||
const next_operation = &operations_[next_operation_index_];
|
|
||||||
if (IsTimeInPeriod(time, next_operation.period)) {
|
|
||||||
PrepareOperation(*next_operation);
|
|
||||||
ProcessOperation(
|
|
||||||
next_operation.period.ConvertToRelativeTime(time), *next_operation);
|
|
||||||
++next_operation_index_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
abstract void PrepareOperation(ref in ParametersBlock params);
|
|
||||||
|
|
||||||
abstract void ProcessOperation(float time, ref in ParametersBlock params);
|
|
||||||
|
|
||||||
abstract void FinalizeOperation(ref in ParametersBlock params);
|
|
||||||
|
|
||||||
private:
|
|
||||||
const ParametersBlock[] operations_;
|
|
||||||
|
|
||||||
float last_operation_time_ = -1;
|
|
||||||
|
|
||||||
size_t next_operation_index_;
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
abstract class AbstractScheduledControllerWithOperationImpl :
|
|
||||||
AbstractScheduledController {
|
|
||||||
public:
|
|
||||||
///
|
|
||||||
this(in VarStoreInterface varstore, in ParametersBlock[] operations) {
|
|
||||||
super(operations);
|
|
||||||
varstore_ = varstore;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
static struct VarStore {
|
|
||||||
public:
|
|
||||||
float opIndex(string name) {
|
|
||||||
if (!time_.isNull && name == "time") return time_.get;
|
|
||||||
return this_.GetVariable(name);
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
AbstractScheduledControllerWithOperationImpl this_;
|
|
||||||
Nullable!float time_;
|
|
||||||
}
|
|
||||||
|
|
||||||
override void PrepareOperation(ref in ParametersBlock params) {
|
|
||||||
user_vars_.clear();
|
|
||||||
params.parameters.
|
|
||||||
filter!(x => x.type == ParameterType.OnceAssign).
|
|
||||||
each !(x => SetParameter(Nullable!float.init, x));
|
|
||||||
}
|
|
||||||
override void ProcessOperation(float time, ref in ParametersBlock params) {
|
|
||||||
params.parameters.
|
|
||||||
filter!(x => x.type != ParameterType.OnceAssign).
|
|
||||||
each !(x => SetParameter(time.nullable, x));
|
|
||||||
}
|
|
||||||
|
|
||||||
float GetVariable(string name) const {
|
|
||||||
if (name in user_vars_) return user_vars_[name];
|
|
||||||
return varstore_[name];
|
|
||||||
}
|
|
||||||
void SetParameter(Nullable!float time, ref in Parameter param) {
|
|
||||||
(param.name.length >= 2 && param.name[0..2] == "__").
|
|
||||||
enforce("user defined variables must be prefixed '__'");
|
|
||||||
user_vars_[param.name] = 0;
|
|
||||||
param.CalculateParameter(user_vars_[param.name], VarStore(this, time));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const VarStoreInterface varstore_;
|
|
||||||
|
|
||||||
float[string] user_vars_;
|
|
||||||
}
|
|
||||||
|
@ -4,7 +4,7 @@ module sjplayer.util.Period;
|
|||||||
import sjscript;
|
import sjscript;
|
||||||
|
|
||||||
///
|
///
|
||||||
bool IsTimeInPeriod(float time, in Period period) {
|
bool IsTimeInPeriod(in Period period, float time) {
|
||||||
return period.start <= time && time < period.end;
|
return period.start <= time && time < period.end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user