From 375dabf2eaa7b904c1cc91dbb48ecb0586b04c5f Mon Sep 17 00:00:00 2001 From: falsycat Date: Sat, 5 Oct 2019 00:00:00 +0000 Subject: [PATCH] [add] Implemented CircleElement. --- sjplayer/src/sjplayer/CircleElement.d | 229 ++++++++++++++++++++++++++ sjplayer/standalone/main.d | 25 +++ 2 files changed, 254 insertions(+) create mode 100644 sjplayer/src/sjplayer/CircleElement.d diff --git a/sjplayer/src/sjplayer/CircleElement.d b/sjplayer/src/sjplayer/CircleElement.d new file mode 100644 index 0000000..6dda0da --- /dev/null +++ b/sjplayer/src/sjplayer/CircleElement.d @@ -0,0 +1,229 @@ +/// License: MIT +module sjplayer.CircleElement; + +import std.algorithm, + std.conv, + std.exception; + +import gl4d; + +import sjplayer.ElementInterface; + +/// +class CircleElement : ElementInterface { + public: + /// + static struct Instance { + /// this should be transposed + align(1) mat3 matrix; + /// + align(1) float weight; + /// + align(1) float smooth; + /// + align(1) vec4 color; + } + + override DamageCalculationResult CalculateDamage(vec2 p1, vec2 p2) const { + // TODO: + return DamageCalculationResult(0, 0); + } + + /// + bool alive; + /// + float damage; + /// + float nearness_coe; + /// + Instance instance; + alias instance this; +} + +/// +class CircleElementDrawer : ElementDrawerInterface { + public: + /// + this(CircleElementProgram program, in CircleElement[] elements) + in (program) + in (elements.length > 0) { + program_ = program; + elements_ = elements; + + vao_ = VertexArray.Create(); + verts_ = ArrayBuffer.Create(); + instances_ = ArrayBuffer.Create(); + + vao_.Bind(); + program_.SetupVertexArray(vao_, verts_, instances_); + + 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_); + } + + instances_.Bind(); + ArrayBufferAllocator instance_allocator; + with (instance_allocator) { + size = CircleElement.Instance.sizeof * elements.length; + usage = GL_DYNAMIC_DRAW; + Allocate(instances_); + } + } + + override void Draw() { + size_t alive_count; + + instances_.Bind(); + ArrayBufferOverwriter instance_writer; + foreach (const element; elements_.filter!"a.alive") with (instance_writer) { + data = &element.instance; + offset = alive_count++ * CircleElement.Instance.sizeof; + size = CircleElement.Instance.sizeof; + Overwrite(instances_); + } + + program_.Use(); + vao_.Bind(); + + if (alive_count == 0) return; + gl.DrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, alive_count.to!int); + } + + private: + CircleElementProgram program_; + + const CircleElement[] elements_; + + ArrayBufferRef verts_; + ArrayBufferRef instances_; + VertexArrayRef vao_; +} + +/// +class CircleElementProgram { + public: + /// + enum ShaderHeader = "#version 330 core +#extension GL_ARB_explicit_uniform_location : enable"; + + /// + enum VertexShaderSrc = ShaderHeader ~ q{ + layout(location = 0) in vec2 vert; + + layout(location = 1) in vec3 m1; + layout(location = 2) in vec3 m2; + layout(location = 3) in vec3 m3; + layout(location = 4) in float weight; + layout(location = 5) in float smoooth; // expected wrong spell + layout(location = 6) in vec4 color; + + out vec2 uv_; + out float weight_; + out float smooth_; + out vec4 color_; + + void main() { + mat3 m = mat3(m1, m2, m3); + vec2 pos = (m * vec3(vert, 1)).xy; + + uv_ = vert; + weight_ = weight; + smooth_ = smoooth; + color_ = color; + gl_Position = vec4(pos, 0, 1); + } + }; + /// + enum FragmentShaderSrc = ShaderHeader ~ q{ + in vec2 uv_; + in float weight_; + in float smooth_; + in vec4 color_; + + out vec4 pixel_; + + float circle() { + float r = length(uv_); + float w = 1 - weight_; + return + smoothstep(w, w+smooth_, r) * + (1 - smoothstep(1-smooth_, 1, r)); + } + + void main() { + pixel_ = color_; + pixel_.a *= circle(); + } + }; + + /// + this() { + ProgramLinker linker; + linker.vertex = VertexShader.Compile(VertexShaderSrc); + linker.fragment = FragmentShader.Compile(FragmentShaderSrc); + program_ = linker.Link(); + program_.Validate(); + } + + /// + void SetupVertexArray(ref VertexArrayRef vao, + ref ArrayBufferRef verts, ref ArrayBufferRef instances) { + VertexArrayAttacher attacher; + with (attacher) { + // verts + type = GL_FLOAT; + dimension = 2; + Attach(vao, verts); + ++index; + + type = GL_FLOAT; + divisor = 1; + stride = CircleElement.Instance.sizeof; + offset = 0; + + // matrix + dimension = 3; + Attach(vao, instances); + offset += float.sizeof*3; + ++index; + Attach(vao, instances); + offset += float.sizeof*3; + ++index; + Attach(vao, instances); + offset += float.sizeof*3; + ++index; + + // weight + dimension = 1; + Attach(vao, instances); + offset += float.sizeof*1; + ++index; + + // smooth + dimension = 1; + Attach(vao, instances); + offset += float.sizeof*1; + ++index; + + // color + dimension = 4; + Attach(vao, instances); + offset += float.sizeof*4; + ++index; + } + } + + /// + void Use() { + program_.Use(); + } + + private: + ProgramRef program_; +} diff --git a/sjplayer/standalone/main.d b/sjplayer/standalone/main.d index c829f81..4abc669 100644 --- a/sjplayer/standalone/main.d +++ b/sjplayer/standalone/main.d @@ -20,6 +20,27 @@ int main(string[] args) { scope(exit) sfMusic_destroy(music); sfMusic_play(music); + import sjplayer.CircleElement; + auto program = new CircleElementProgram; + scope(exit) program.destroy(); + auto element = new CircleElement; + scope(exit) element.destroy(); + auto drawer = new CircleElementDrawer(program, [element]); + scope(exit) drawer.destroy(); + + with (element) { + alive = true; + + matrix = mat3.identity; + matrix.scale(0.5, 0.5, 0.5); + matrix.translate(0.1, 0, 0); + matrix.transpose(); + + weight = 1; + smooth = 0.01; + color = vec4(1, 1, 1, 1); + } + while (true) { sfEvent e; sfWindow_pollEvent(win, &e); @@ -27,6 +48,7 @@ int main(string[] args) { const msecs = sfMusic_getPlayingOffset(music).microseconds * 1e-6f; const beat = msecs/60f * bpm; + drawer.Draw(); sfWindow_display(win); } @@ -51,7 +73,10 @@ sfWindow* Initialize() { sfWindow_setVerticalSyncEnabled(win, true); sfWindow_setActive(win, true).enforce; + gl.ApplyContext(); + gl.Enable(GL_BLEND); + gl.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); return win; }