[add] Implemented CircleElement.
This commit is contained in:
parent
84b0033790
commit
375dabf2ea
229
sjplayer/src/sjplayer/CircleElement.d
Normal file
229
sjplayer/src/sjplayer/CircleElement.d
Normal 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_;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user