[update] Tidied codes of elements.

This commit is contained in:
falsycat 2019-10-15 00:00:00 +00:00
parent a39c9f5001
commit f5500b0b98
11 changed files with 229 additions and 290 deletions

View File

@ -0,0 +1,31 @@
/// License: MIT
module sjplayer.AbstractShapeElement;
import gl4d;
import sjplayer.ElementInterface,
sjplayer.ShapeElementProgram;
///
abstract class AbstractShapeElement : ElementInterface {
public:
///
void Initialize() {
alive = false;
damage = 0;
nearness_coe = 0;
instance = instance.init;
}
abstract override DamageCalculationResult CalculateDamage(vec2 p1, vec2 p2) const;
///
bool alive;
///
float damage;
///
float nearness_coe;
///
ShapeElementProgramInstance instance;
alias instance this;
}

View File

@ -6,22 +6,16 @@ import std.algorithm,
import gl4d; import gl4d;
import sjplayer.ElementDrawer, import sjplayer.AbstractShapeElement,
sjplayer.ElementInterface, sjplayer.ElementInterface,
sjplayer.ShapeElementDrawer,
sjplayer.ShapeElementProgram, sjplayer.ShapeElementProgram,
sjplayer.ShapeElementScheduledController,
sjplayer.util.linalg; sjplayer.util.linalg;
/// ///
class CircleElement : ElementInterface { class CircleElement : AbstractShapeElement {
public: public:
///
void Initialize() {
alive = false;
damage = 0;
nearness_coe = 0;
instance = instance.init;
}
override DamageCalculationResult CalculateDamage(vec2 p1, vec2 p2) const { override DamageCalculationResult CalculateDamage(vec2 p1, vec2 p2) const {
if (!alive) return DamageCalculationResult(0, 0); if (!alive) return DamageCalculationResult(0, 0);
@ -35,22 +29,11 @@ class CircleElement : ElementInterface {
} }
return DamageCalculationResult(0, 1 - (d-1).clamp(0, 1)); return DamageCalculationResult(0, 1 - (d-1).clamp(0, 1));
} }
///
bool alive;
///
float damage;
///
float nearness_coe;
///
CircleElementProgram.Instance instance;
alias instance this;
} }
/// ///
alias CircleElementDrawer = ElementDrawer!( alias CircleElementDrawer = ShapeElementDrawer!(
CircleElementProgram, CircleElementProgram,
CircleElement,
[vec2(-1, 1), vec2(1, 1), vec2(1, -1), vec2(-1, -1)]); [vec2(-1, 1), vec2(1, 1), vec2(1, -1), vec2(-1, -1)]);
/// ///
@ -61,3 +44,9 @@ alias CircleElementProgram = ShapeElementProgram!(q{
smoothstep(w-smooth_, w, r) * smoothstep(w-smooth_, w, r) *
(1 - smoothstep(1-smooth_, 1, r)); (1 - smoothstep(1-smooth_, 1, r));
}); });
///
alias CircleElementScheduledControllerFactory =
ShapeElementScheduledControllerFactory!(
CircleElement,
CircleElementDrawer);

View File

@ -1,17 +0,0 @@
/// License: MIT
module sjplayer.CircleElementScheduledController;
import sjplayer.CircleElement,
sjplayer.ElementScheduledControllerFactory,
sjplayer.ScheduledController,
sjplayer.ShapeElementScheduledController;
///
alias CircleElementScheduledController =
ShapeElementScheduledController!CircleElement;
///
alias CircleElementScheduledControllerFactory =
ElementScheduledControllerFactory!(
CircleElementScheduledController,
CircleElementDrawer);

View File

@ -21,7 +21,6 @@ import sjplayer.Actor,
sjplayer.PostEffectControllerInterface, sjplayer.PostEffectControllerInterface,
sjplayer.ProgramSet, sjplayer.ProgramSet,
sjplayer.ScheduledControllerInterface, sjplayer.ScheduledControllerInterface,
sjplayer.SquareElementScheduledController,
sjplayer.VarStore, sjplayer.VarStore,
sjplayer.VarStoreScheduledController; sjplayer.VarStoreScheduledController;
@ -38,7 +37,8 @@ class Context {
auto varstore = new VarStore(actor_); auto varstore = new VarStore(actor_);
import sjplayer.BackgroundScheduledController, import sjplayer.BackgroundScheduledController,
sjplayer.CircleElementScheduledController; sjplayer.CircleElement,
sjplayer.SquareElement;
auto factories = tuple( auto factories = tuple(
tuple( tuple(
"actor", "actor",

View File

@ -1,98 +0,0 @@
/// 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_;
}

View File

@ -1,15 +1,13 @@
/// License: MIT /// License: MIT
module sjplayer.ScheduledController; module sjplayer.ScheduledController;
import std.traits, import std.typecons;
std.typecons;
import gl4d; import gl4d;
import sjscript; import sjscript;
import sjplayer.AbstractScheduledController, import sjplayer.AbstractScheduledController,
sjplayer.ScheduledControllerInterface,
sjplayer.VarStoreInterface, sjplayer.VarStoreInterface,
sjplayer.util.Parameter; sjplayer.util.Parameter;
@ -17,18 +15,6 @@ import sjplayer.AbstractScheduledController,
class ScheduledController( class ScheduledController(
Target, string[string] ParameterNameMap) : AbstractScheduledController { Target, string[string] ParameterNameMap) : AbstractScheduledController {
public: public:
///
enum AliveManagementAvailable =
is(typeof((Target x) => x.alive)) &&
is(ReturnType!((Target x) => x.alive) == bool);
///
enum MatrixModificationAvailable =
is(typeof((Target x) => x.matrix)) &&
is(ReturnType!((Target x) => x.matrix) == mat3);
///
enum AutoInitializationAvailable =
is(typeof((Target x) => x.Initialize()));
/// ///
this( this(
Target target, Target target,
@ -39,30 +25,6 @@ class ScheduledController(
} }
protected: protected:
override void PrepareOperation(ref in ParametersBlock params) {
static if (AutoInitializationAvailable) {
target_.Initialize();
}
static if (AliveManagementAvailable) {
target_.alive = true;
}
static if (MatrixModificationAvailable) {
matrix_factory_ = matrix_factory_.init;
}
super.PrepareOperation(params);
}
override void ProcessOperation(float time, ref in ParametersBlock params) {
super.ProcessOperation(time, params);
static if (MatrixModificationAvailable) {
target_.matrix = matrix_factory_.Create();
}
}
override void FinalizeOperation(ref in ParametersBlock params) {
static if (AliveManagementAvailable) {
target_.alive = false;
}
}
override Nullable!float GetVariable(string name) const { override Nullable!float GetVariable(string name) const {
switch (name) { switch (name) {
static foreach (map_name, code; ParameterNameMap) { static foreach (map_name, code; ParameterNameMap) {
@ -71,10 +33,6 @@ class ScheduledController(
} }
default: default:
} }
static if (MatrixModificationAvailable) {
const value = matrix_factory_.GetModelMatrixParameterValueByName(name);
if (!value.isNull) return value;
}
return super.GetVariable(name); return super.GetVariable(name);
} }
override void SetParameter(ref in Parameter param, ref in VarStore vars) { override void SetParameter(ref in Parameter param, ref in VarStore vars) {
@ -86,15 +44,8 @@ class ScheduledController(
} }
default: default:
} }
static if (MatrixModificationAvailable) {
if (param.CalculateModelMatrixParameter(matrix_factory_, vars)) return;
}
super.SetParameter(param, vars); super.SetParameter(param, vars);
} }
Target target_; Target target_;
static if (MatrixModificationAvailable) {
ModelMatrixFactory!3 matrix_factory_;
}
} }

View File

@ -1,26 +1,28 @@
/// License: MIT /// License: MIT
module sjplayer.ElementDrawer; module sjplayer.ShapeElementDrawer;
import std.algorithm, import std.algorithm,
std.conv; std.conv,
std.exception;
import gl4d; import gl4d;
import sjplayer.ElementDrawerInterface; import sjplayer.AbstractShapeElement,
sjplayer.ElementDrawerInterface,
sjplayer.ShapeElementProgram;
/// ///
class ElementDrawer(Program, Element, vec2[] vertices) : class ShapeElementDrawer(Program, vec2[] vertices) : ElementDrawerInterface {
ElementDrawerInterface {
public: public:
/// ///
alias Instance = typeof(Element.instance); enum MaxInstanceCount = 512;
/// ///
this(Program program, in Element[] elements) this(Program program, in AbstractShapeElement[] shapes)
in (program) in (program)
in (elements.length > 0) { in (shapes.length > 0) {
program_ = program; program_ = program;
elements_ = elements; shapes_ = shapes;
vao_ = VertexArray.Create(); vao_ = VertexArray.Create();
verts_ = ArrayBuffer.Create(); verts_ = ArrayBuffer.Create();
@ -41,7 +43,7 @@ class ElementDrawer(Program, Element, vec2[] vertices) :
instances_.Bind(); instances_.Bind();
with (ArrayBufferAllocator()) { with (ArrayBufferAllocator()) {
size = Instance.sizeof * elements.length; size = ShapeElementProgramInstance.sizeof * MaxInstanceCount;
usage = GL_DYNAMIC_DRAW; usage = GL_DYNAMIC_DRAW;
Allocate(instances_); Allocate(instances_);
} }
@ -52,9 +54,10 @@ class ElementDrawer(Program, Element, vec2[] vertices) :
instances_.Bind(); instances_.Bind();
{ {
auto ptr = instances_.MapToWrite!Instance(); auto ptr = instances_.MapToWrite!ShapeElementProgramInstance();
foreach (const element; elements_.filter!"a.alive") { foreach (const shape; shapes_.filter!"a.alive") {
ptr[alive_count++] = element.instance; enforce(alive_count <= MaxInstanceCount);
ptr[alive_count++] = shape.instance;
} }
} }
@ -69,7 +72,7 @@ class ElementDrawer(Program, Element, vec2[] vertices) :
private: private:
Program program_; Program program_;
const Element[] elements_; const AbstractShapeElement[] shapes_;
ArrayBufferRef verts_; ArrayBufferRef verts_;
ArrayBufferRef instances_; ArrayBufferRef instances_;

View File

@ -8,18 +8,6 @@ import gl4d;
/// ///
class ShapeElementProgram(string ShaderSrc) { class ShapeElementProgram(string ShaderSrc) {
public: public:
///
static struct Instance {
///
align(1) mat3 matrix = mat3.identity;
///
align(1) float weight = 1;
///
align(1) float smooth = 0.001;
///
align(1) vec4 color = vec4(0, 0, 0, 0);
}
/// ///
enum ShaderHeader = "#version 330 core enum ShaderHeader = "#version 330 core
#extension GL_ARB_explicit_uniform_location : enable"; #extension GL_ARB_explicit_uniform_location : enable";
@ -91,7 +79,7 @@ class ShapeElementProgram(string ShaderSrc) {
type = GL_FLOAT; type = GL_FLOAT;
divisor = 1; divisor = 1;
stride = Instance.sizeof; stride = ShapeElementProgramInstance.sizeof;
offset = 0; offset = 0;
// matrix // matrix
@ -134,3 +122,16 @@ class ShapeElementProgram(string ShaderSrc) {
private: private:
ProgramRef program_; ProgramRef program_;
} }
///
struct ShapeElementProgramInstance {
public:
///
align(1) mat3 matrix = mat3.identity;
///
align(1) float weight = 1;
///
align(1) float smooth = 0.001;
///
align(1) vec4 color = vec4(0, 0, 0, 0);
}

View File

@ -1,28 +1,147 @@
/// License: MIT /// License: MIT
module sjplayer.ShapeElementScheduledController; module sjplayer.ShapeElementScheduledController;
import sjplayer.CircleElement, import std.algorithm,
sjplayer.ElementInterface, std.array,
sjplayer.ElementScheduledControllerFactory, std.conv,
sjplayer.ScheduledController; std.range.primitives,
std.traits,
std.typecons;
import gl4d;
import sjscript;
import sjplayer.AbstractShapeElement,
sjplayer.ContextBuilderInterface,
sjplayer.ProgramSet,
sjplayer.ScheduledController,
sjplayer.ShapeElementScheduledController,
sjplayer.VarStoreInterface,
sjplayer.util.Parameter,
sjplayer.util.Period;
private enum NameMap = [
"damage": "damage",
"nearness_coe": "nearness_coe",
"weight": "weight",
"smooth": "smooth",
"color_r": "color.r",
"color_g": "color.g",
"color_b": "color.b",
"color_a": "color.a",
];
/// ///
template ShapeElementScheduledController(Element) class ShapeElementScheduledController :
if (is(Element : ElementInterface)) { ScheduledController!(AbstractShapeElement, NameMap) {
alias ShapeElementScheduledController = ScheduledController!( public:
Element, ///
[ this(
"damage": "damage", AbstractShapeElement shape,
"nearness_coe": "nearness_coe", in VarStoreInterface varstore,
"weight": "weight", in ParametersBlock[] operations) {
"smooth": "smooth", super(shape, varstore, operations);
"color_r": "color.r", shape_ = shape;
"color_g": "color.g", }
"color_b": "color.b",
"color_a": "color.a", protected:
] override void PrepareOperation(ref in ParametersBlock params) {
); shape_.Initialize();
static assert(ShapeElementScheduledController.AliveManagementAvailable); shape_.alive = true;
static assert(ShapeElementScheduledController.MatrixModificationAvailable);
static assert(ShapeElementScheduledController.AutoInitializationAvailable); matrix_factory_ = matrix_factory_.init;
super.PrepareOperation(params);
}
override void ProcessOperation(float time, ref in ParametersBlock params) {
super.ProcessOperation(time, params);
shape_.matrix = matrix_factory_.Create();
}
override void FinalizeOperation(ref in ParametersBlock params) {
shape_.alive = false;
}
override Nullable!float GetVariable(string name) const {
const value = matrix_factory_.
GetModelMatrixParameterValueByName(name);
if (!value.isNull) return value;
return super.GetVariable(name);
}
override void SetParameter(ref in Parameter param, ref in VarStore vars) {
if (param.CalculateModelMatrixParameter(matrix_factory_, vars)) return;
super.SetParameter(param, vars);
}
private:
AbstractShapeElement shape_;
ModelMatrixFactory!3 matrix_factory_;
}
///
struct ShapeElementScheduledControllerFactory(ShapeElement, ShapeElementDrawer)
if (is(ShapeElement : AbstractShapeElement)) {
public:
///
alias ShapeElementProgram =
Parameters!(__traits(getOverloads, ShapeElementDrawer, "__ctor")[0])[0];
///
this(ProgramSet programs, VarStoreInterface varstore) {
program_ = programs.Get!ShapeElementProgram;
varstore_ = varstore;
}
///
void Create(R)(R params, ContextBuilderInterface builder)
if (isInputRange!R && is(ElementType!R == ParametersBlock)) {
auto parallelized = ParallelizeParams(params);
auto elements = appender!(ShapeElement[]);
foreach (ref serial; parallelized) {
auto element = new ShapeElement;
elements ~= element;
builder.AddElement(element);
builder.AddScheduledController(
new ShapeElementScheduledController(element, varstore_, serial));
}
if (elements[].length > 0) {
builder.AddElementDrawer(new ShapeElementDrawer(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;
}
ShapeElementProgram program_;
VarStoreInterface varstore_;
} }

View File

@ -6,34 +6,16 @@ import std.algorithm,
import gl4d; import gl4d;
import sjplayer.ElementDrawer, import sjplayer.AbstractShapeElement,
sjplayer.ElementInterface, sjplayer.ElementInterface,
sjplayer.ShapeElementDrawer,
sjplayer.ShapeElementScheduledController,
sjplayer.ShapeElementProgram, sjplayer.ShapeElementProgram,
sjplayer.util.linalg; sjplayer.util.linalg;
/// ///
class SquareElement : ElementInterface { class SquareElement : AbstractShapeElement {
public: public:
///
static struct Instance {
///
align(1) mat3 matrix = mat3.identity;
///
align(1) float weight = 1;
///
align(1) float smooth = 0.001;
///
align(1) vec4 color = vec4(0, 0, 0, 0);
}
///
void Initialize() {
alive = false;
damage = 0;
nearness_coe = 0;
instance = instance.init;
}
override DamageCalculationResult CalculateDamage(vec2 p1, vec2 p2) const { override DamageCalculationResult CalculateDamage(vec2 p1, vec2 p2) const {
if (!alive) return DamageCalculationResult(0, 0); if (!alive) return DamageCalculationResult(0, 0);
@ -63,22 +45,11 @@ class SquareElement : ElementInterface {
} }
return DamageCalculationResult(0, 1-(min_distance-1).clamp(0f, 1f)); return DamageCalculationResult(0, 1-(min_distance-1).clamp(0f, 1f));
} }
///
bool alive;
///
float damage;
///
float nearness_coe;
///
Instance instance;
alias instance this;
} }
/// ///
alias SquareElementDrawer = ElementDrawer!( alias SquareElementDrawer = ShapeElementDrawer!(
SquareElementProgram, SquareElementProgram,
SquareElement,
[vec2(-1, 1), vec2(1, 1), vec2(1, -1), vec2(-1, -1)]); [vec2(-1, 1), vec2(1, 1), vec2(1, -1), vec2(-1, -1)]);
/// ///
@ -89,3 +60,9 @@ alias SquareElementProgram = ShapeElementProgram!(q{
smoothstep(w-s, w, abs(uv_.x)) + smoothstep(w-s, w, abs(uv_.x)) +
smoothstep(w-s, w, abs(uv_.y)), 0, 1); smoothstep(w-s, w, abs(uv_.y)), 0, 1);
}); });
///
alias SquareElementScheduledControllerFactory =
ShapeElementScheduledControllerFactory!(
SquareElement,
SquareElementDrawer);

View File

@ -1,17 +0,0 @@
/// License: MIT
module sjplayer.SquareElementScheduledController;
import sjplayer.ElementScheduledControllerFactory,
sjplayer.ScheduledController,
sjplayer.ShapeElementScheduledController,
sjplayer.SquareElement;
///
alias SquareElementScheduledController =
ShapeElementScheduledController!SquareElement;
///
alias SquareElementScheduledControllerFactory =
ElementScheduledControllerFactory!(
SquareElementScheduledController,
SquareElementDrawer);