[add] Implemented CircleElement.

This commit is contained in:
falsycat 2019-10-05 00:00:00 +00:00
parent 84b0033790
commit 375dabf2ea
2 changed files with 254 additions and 0 deletions

View File

@ -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_;
}

View File

@ -20,6 +20,27 @@ int main(string[] args) {
scope(exit) sfMusic_destroy(music); scope(exit) sfMusic_destroy(music);
sfMusic_play(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) { while (true) {
sfEvent e; sfEvent e;
sfWindow_pollEvent(win, &e); sfWindow_pollEvent(win, &e);
@ -27,6 +48,7 @@ int main(string[] args) {
const msecs = sfMusic_getPlayingOffset(music).microseconds * 1e-6f; const msecs = sfMusic_getPlayingOffset(music).microseconds * 1e-6f;
const beat = msecs/60f * bpm; const beat = msecs/60f * bpm;
drawer.Draw();
sfWindow_display(win); sfWindow_display(win);
} }
@ -51,7 +73,10 @@ sfWindow* Initialize() {
sfWindow_setVerticalSyncEnabled(win, true); sfWindow_setVerticalSyncEnabled(win, true);
sfWindow_setActive(win, true).enforce; sfWindow_setActive(win, true).enforce;
gl.ApplyContext(); gl.ApplyContext();
gl.Enable(GL_BLEND);
gl.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
return win; return win;
} }