diff --git a/sjplayer/src/sjplayer/Background.d b/sjplayer/src/sjplayer/Background.d new file mode 100644 index 0000000..99f5560 --- /dev/null +++ b/sjplayer/src/sjplayer/Background.d @@ -0,0 +1,112 @@ +/// License: MIT +module sjplayer.Background; + +import gl4d; + +/// +class Background { + public: + /// + this(BackgroundProgram program) { + program_ = program; + } + + /// + void Initialize() { + inner_color = vec4(0, 0, 0, 0); + outer_color = vec4(0, 0, 0, 0); + } + /// + void Draw() { + program_.Draw(inner_color, outer_color); + } + + /// + vec4 inner_color; + /// + vec4 outer_color; + + private: + BackgroundProgram program_; +} + +/// +class BackgroundProgram { + public: + /// + enum ShaderHeader = "#version 330 core +#extension GL_ARB_explicit_uniform_location : enable"; + + /// + enum VertexShaderSrc = ShaderHeader ~ q{ + layout(location = 0) in vec2 vert; + + out vec2 uv_; + + void main() { + uv_ = vert; + gl_Position = vec4(vert, 0, 1); + } + }; + /// + enum FragmentShaderSrc = ShaderHeader ~ q{ + layout(location = 0) uniform vec4 inner_color; + layout(location = 1) uniform vec4 outer_color; + + in vec2 uv_; + + out vec4 pixel_; + + void main() { + pixel_ = (outer_color - inner_color)*length(uv_)/sqrt(2) + outer_color; + } + }; + + /// + this() { + ProgramLinker linker; + linker.vertex = VertexShader.Compile(VertexShaderSrc); + linker.fragment = FragmentShader.Compile(FragmentShaderSrc); + program_ = linker.Link(); + program_.Validate(); + + vao_ = VertexArray.Create(); + verts_ = ArrayBuffer.Create(); + + vao_.Bind(); + VertexArrayAttacher attacher; + with (attacher) { + index = 0; + type = GL_FLOAT; + dimension = 2; + Attach(vao_, verts_); + } + + verts_.Bind(); + ArrayBufferAllocator verts_allocator; + with (verts_allocator) { + const v = [vec2(-1, 1), vec2(1, 1), vec2(1, -1), vec2(-1, -1),]; + data = v.ptr; + size = typeof(v[0]).sizeof * v.length; + usage = GL_STATIC_DRAW; + Allocate(verts_); + } + } + + /// + void Draw(vec4 inner, vec4 outer) { + program_.Use(); + program_.uniform!0 = inner; + program_.uniform!1 = outer; + + vao_.Bind(); + gl.DrawArrays(GL_TRIANGLE_FAN, 0, 4); + } + + private: + ProgramRef program_; + + ArrayBufferRef verts_; + + VertexArrayRef vao_; +} diff --git a/sjplayer/src/sjplayer/BackgroundScheduledController.d b/sjplayer/src/sjplayer/BackgroundScheduledController.d new file mode 100644 index 0000000..5cdc616 --- /dev/null +++ b/sjplayer/src/sjplayer/BackgroundScheduledController.d @@ -0,0 +1,65 @@ +/// License: MIT +module sjplayer.BackgroundScheduledController; + +import std.algorithm, + std.array, + std.exception, + std.range.primitives; + +import sjscript; + +import sjplayer.Background, + sjplayer.ContextBuilderInterface, + sjplayer.ElementScheduledController, + sjplayer.VarStoreInterface, + sjplayer.util.Period; + +/// +alias BackgroundScheduledController = ElementScheduledController!( + Background, + [ + "inner_r": "inner_color.r", + "inner_g": "inner_color.g", + "inner_b": "inner_color.b", + "inner_a": "inner_color.a", + "outer_r": "outer_color.r", + "outer_g": "outer_color.g", + "outer_b": "outer_color.b", + "outer_a": "outer_color.a", + ] + ); + +/// +struct BackgroundScheduledControllerFactory { + public: + @disable this(); + + /// + this( + in VarStoreInterface varstore, + Background background) { + varstore_ = varstore; + background_ = background; + } + + /// + void Create(R)(R params, ContextBuilderInterface builder) + if (isInputRange!R && is(ElementType!R == ParametersBlock)) { + auto params_array = params.array; + params_array.sort!"a.period.start < b.period.start"; + + auto before = Period(-1, 0); + foreach (param; params_array) { + (!param.period.IsPeriodIntersectedToPeriod(before)).enforce(); + } + + auto ctrl = new BackgroundScheduledController( + background_, varstore_, params_array); + builder.AddScheduledController(ctrl); + } + + private: + const VarStoreInterface varstore_; + + Background background_; +} diff --git a/sjplayer/src/sjplayer/Context.d b/sjplayer/src/sjplayer/Context.d index 86b5f51..f2e1217 100644 --- a/sjplayer/src/sjplayer/Context.d +++ b/sjplayer/src/sjplayer/Context.d @@ -7,7 +7,8 @@ import std.algorithm, import sjscript; -import sjplayer.ContextBuilderInterface, +import sjplayer.Background, + sjplayer.ContextBuilderInterface, sjplayer.ElementInterface, sjplayer.ProgramSet, sjplayer.ScheduledControllerInterface, @@ -21,8 +22,15 @@ class Context { auto builder = new Builder; auto varstore = new BlackHole!VarStoreInterface; - import sjplayer.CircleElementScheduledController; + background_ = new Background(programs.Get!BackgroundProgram); + + import sjplayer.BackgroundScheduledController, + sjplayer.CircleElementScheduledController; auto factories = tuple( + tuple( + "background", + BackgroundScheduledControllerFactory(varstore, background_), + ), tuple( "circle", CircleElementScheduledControllerFactory(programs, varstore), @@ -42,6 +50,8 @@ class Context { controllers_.each!destroy; drawers_.each!destroy; elements_.each!destroy; + + background_.destroy(); } /// @@ -49,6 +59,10 @@ class Context { assert(false); // TODO: } /// + void DrawBackground() { + background_.Draw(); + } + /// void DrawElements() { drawers_.each!(x => x.Draw()); } @@ -74,6 +88,8 @@ class Context { Appender!(ScheduledControllerInterface[]) controllers; } + Background background_; + ElementInterface[] elements_; ElementDrawerInterface[] drawers_; diff --git a/sjplayer/src/sjplayer/ElementScheduledController.d b/sjplayer/src/sjplayer/ElementScheduledController.d index 707f4af..aeadbd5 100644 --- a/sjplayer/src/sjplayer/ElementScheduledController.d +++ b/sjplayer/src/sjplayer/ElementScheduledController.d @@ -17,8 +17,7 @@ import sjplayer.ElementInterface, /// class ElementScheduledController( Element, string[string] ParameterNameMap) : - AbstractScheduledControllerWithOperationImpl - if (is(Element : ElementInterface)) { + AbstractScheduledControllerWithOperationImpl { public: /// enum AliveManagementAvailable = diff --git a/sjplayer/src/sjplayer/ProgramSet.d b/sjplayer/src/sjplayer/ProgramSet.d index e9be3fa..2392fa5 100644 --- a/sjplayer/src/sjplayer/ProgramSet.d +++ b/sjplayer/src/sjplayer/ProgramSet.d @@ -4,13 +4,17 @@ module sjplayer.ProgramSet; import std.meta, std.typecons; -import sjplayer.CircleElement; +import sjplayer.Background, + sjplayer.CircleElement; /// class ProgramSet { public: /// - alias Programs = Tuple!(CircleElementProgram); + alias Programs = Tuple!( + BackgroundProgram, + CircleElementProgram + ); /// this() { diff --git a/sjplayer/standalone/main.d b/sjplayer/standalone/main.d index d95b1b2..afae262 100644 --- a/sjplayer/standalone/main.d +++ b/sjplayer/standalone/main.d @@ -39,6 +39,7 @@ int main(string[] args) { context.OperateScheduledControllers(beat); gl.Clear(GL_COLOR_BUFFER_BIT); + context.DrawBackground(); context.DrawElements(); sfWindow_display(win); }