diff --git a/sjplayer/src/sjplayer/Context.d b/sjplayer/src/sjplayer/Context.d index e845600..016cd2c 100644 --- a/sjplayer/src/sjplayer/Context.d +++ b/sjplayer/src/sjplayer/Context.d @@ -38,7 +38,8 @@ class Context { import sjplayer.BackgroundScheduledController, sjplayer.CircleElement, - sjplayer.SquareElement; + sjplayer.SquareElement, + sjplayer.TriangleElement; auto factories = tuple( tuple( "actor", @@ -61,6 +62,10 @@ class Context { "square", SquareElementScheduledControllerFactory(programs, varstore), ), + tuple( + "triangle", + TriangleElementScheduledControllerFactory(programs, varstore), + ), tuple( "variable", VarStoreScheduledControllerFactory(varstore), diff --git a/sjplayer/src/sjplayer/ProgramSet.d b/sjplayer/src/sjplayer/ProgramSet.d index 938c7b3..59ee795 100644 --- a/sjplayer/src/sjplayer/ProgramSet.d +++ b/sjplayer/src/sjplayer/ProgramSet.d @@ -8,7 +8,8 @@ import sjplayer.Actor, sjplayer.Background, sjplayer.CircleElement, sjplayer.PostEffect, - sjplayer.SquareElement; + sjplayer.SquareElement, + sjplayer.TriangleElement; /// class ProgramSet { @@ -20,6 +21,7 @@ class ProgramSet { CircleElementProgram, PostEffectProgram, SquareElementProgram, + TriangleElementProgram, ); /// diff --git a/sjplayer/src/sjplayer/TriangleElement.d b/sjplayer/src/sjplayer/TriangleElement.d new file mode 100644 index 0000000..2fa0016 --- /dev/null +++ b/sjplayer/src/sjplayer/TriangleElement.d @@ -0,0 +1,83 @@ +/// License: MIT +module sjplayer.TriangleElement; + +import std.algorithm, + std.math, + std.typecons; + +import gl4d; + +import sjplayer.AbstractShapeElement, + sjplayer.ElementInterface, + sjplayer.ShapeElementDrawer, + sjplayer.ShapeElementProgram, + sjplayer.ShapeElementScheduledController, + sjplayer.util.linalg; + +/// +class TriangleElement : AbstractShapeElement { + public: + override DamageCalculationResult CalculateDamage(vec2 p1, vec2 p2) const { + if (!alive) return DamageCalculationResult(0, 0); + + const m = matrix.inverse; + const a = (m * vec3(p1, 1)).xy; + const b = (m * vec3(p2, 1)).xy; + + enum A = vec2( 0, sqrt(3f)*2f/3f); + enum B = vec2(-1, -sqrt(3f) /3f); + enum C = vec2( 1, -sqrt(3f) /3f); + + bool CheckInside(vec2 pt) { + return + cross2(B-A, pt-A) >= 0 && cross2(pt-A, C-A) >= 0 && cross2(C-B, pt-B) >= 0; + } + if (CheckInside(a) || CheckInside(b)) { + return DamageCalculationResult(damage, 0); + } + + enum edges = [ + tuple(A, B), + tuple(A, C), + tuple(B, C), + ]; + float[3] distances; + static foreach (i, edge; edges) { + distances[i] = CalculateDistance2LineSegment(edge[0], edge[1], a, b); + } + const min_distance = distances[].minElement; + + if (min_distance == 0) { + return DamageCalculationResult(damage, 0); + } + return DamageCalculationResult(0, 1-(min_distance-1).clamp(0f, 1f)); + } +} + +/// +alias TriangleElementDrawer = ShapeElementDrawer!( + TriangleElementProgram, + [vec2(-1, 1.2), vec2(-1, -1), vec2(1, -1), vec2(1, 1.2)]); + +/// +alias TriangleElementProgram = ShapeElementProgram!(q{ + vec2 A = vec2( 0, sqrt(3)*2/3); + vec2 B = vec2(-1, -sqrt(3) /3); + vec2 C = vec2( 1, -sqrt(3) /3); + + vec2 AB = B - A; + vec2 AC = C - A; + vec2 BC = C - B; + + float cross_AB = AB.x * (uv_.y - A.y) - AB.y * (uv_.x - A.x); + float cross_AC = (uv_.x - A.x) * AC.y - (uv_.y - A.y) * AC.x; + float cross_BC = BC.x * (uv_.y - B.y) - BC.y * (uv_.x - B.x); + + return step(0, cross_AB) * step(0, cross_AC) * step(0, cross_BC); + }); + +/// +alias TriangleElementScheduledControllerFactory = + ShapeElementScheduledControllerFactory!( + TriangleElement, + TriangleElementDrawer); diff --git a/sjplayer/src/sjplayer/util/linalg.d b/sjplayer/src/sjplayer/util/linalg.d index dad0398..2f7c929 100644 --- a/sjplayer/src/sjplayer/util/linalg.d +++ b/sjplayer/src/sjplayer/util/linalg.d @@ -33,10 +33,6 @@ unittest { /// float CalculateDistance2LineSegment(vec2 a1, vec2 b1, vec2 a2, vec2 b2) { - float cross2(vec2 v1, vec2 v2) { - return v1.x * v2.y - v1.y * v2.x; - } - if (a1 == b1) return CalculateDistanceOriginAndLineSegment(a2 - a1, b2 - a1); if (a2 == b2) return CalculateDistanceOriginAndLineSegment(a1 - a2, b1 - a2); @@ -77,3 +73,8 @@ unittest { assert(CalculateDistance2LineSegment( vec2(-1, 0), vec2(1, 0), vec2(2, 1), vec2(2, -1)).approxEqual(1f)); } + +/// +float cross2(vec2 v1, vec2 v2) { + return v1.x * v2.y - v1.y * v2.x; +}