diff --git a/dub.json b/dub.json index e13ce0f..6cf5d5b 100644 --- a/dub.json +++ b/dub.json @@ -3,6 +3,8 @@ "targetPath": ".bin", + "stringImportPaths": ["res"], + "dependencies": { "sjplayer": {"path": "sjplayer"}, diff --git a/res/images/title.png b/res/images/title.png new file mode 100644 index 0000000..e9ab1c3 Binary files /dev/null and b/res/images/title.png differ diff --git a/src/sj/Game.d b/src/sj/Game.d index dcaf3b8..def121e 100644 --- a/src/sj/Game.d +++ b/src/sj/Game.d @@ -17,7 +17,7 @@ class Game : AbstractGame { lobby_ = new LobbyWorld(programs_); - title_ = new TitleScene(lobby_); + title_ = new TitleScene(lobby_, programs_); title_.SetupSceneDependency(title_); // TODO: specify proper next scene super(title_); @@ -29,6 +29,7 @@ class Game : AbstractGame { lobby_.destroy(); programs_.destroy(); + fonts_.destroy(); } private: diff --git a/src/sj/TitleScene.d b/src/sj/TitleScene.d index 675a24d..ebf1f86 100644 --- a/src/sj/TitleScene.d +++ b/src/sj/TitleScene.d @@ -8,15 +8,27 @@ import gl4d; import sj.AbstractScene, sj.KeyInput, sj.LobbyWorld, - sj.SceneInterface; + sj.ProgramSet, + sj.SceneInterface, + sj.TitleTextProgram; /// class TitleScene : AbstractScene { public: /// - this(LobbyWorld lobby) { + enum TitleMatrix = { + auto m = mat4.identity; + m.scale(0.8, 0.1, 0.1); + m.translate(0, -0.3, 0); + return m; + }(); + + /// + this(LobbyWorld lobby, ProgramSet program) { lobby_ = lobby; SetupLobby(lobby); + + title_ = program.Get!TitleTextProgram; } /// @@ -25,29 +37,35 @@ class TitleScene : AbstractScene { } override void Update(KeyInput input) { - lobby_.cube_matrix.rotation += vec3(PI/300, PI/300, PI/300); + lobby_.cube_matrix.rotation += vec3(PI/600, PI/600, PI/600); } override void Draw() { lobby_.Draw(); + title_.Draw(lobby_.Projection, lobby_.view.Create(), TitleMatrix, frame_++); } private: static void SetupLobby(LobbyWorld lobby) { - lobby.view.pos = vec3(0, 0, -1); - lobby.view.target = vec3(0, -0.2, 0); + lobby.view.pos = vec3(0, -0.15, -1); + lobby.view.target = vec3(0, -0.15, 0); + lobby.view.up = vec3(0, 1, 0); lobby.background.inner_color = vec4(0.9, 0.9, 0.9, 1); - lobby.background.outer_color = vec4(0.2, 0.2, 0.2, 1); + lobby.background.outer_color = vec4(-0.1, -0.1, -0.1, 1); - lobby.light_pos = vec3(0, 10, 0); + lobby.light_pos = vec3(0, 9, -1); lobby.cube_material.diffuse_color = vec3(0.1, 0.1, 0.1); lobby.cube_material.light_color = vec3(1, 0.8, 0.8); lobby.cube_material.light_power = vec3(100, 100, 100); - lobby.cube_material.ambient_color = vec3(0.1, 0.1, 0.1); + lobby.cube_material.ambient_color = vec3(0.2, 0.2, 0.2); lobby.cube_material.specular_color = vec3(0.5, 0.2, 0.2); } SceneInterface next_scene_; LobbyWorld lobby_; + + TitleTextProgram title_; + + int frame_; } diff --git a/src/sj/TitleTextProgram.d b/src/sj/TitleTextProgram.d index 880885e..55e9fa5 100644 --- a/src/sj/TitleTextProgram.d +++ b/src/sj/TitleTextProgram.d @@ -3,6 +3,8 @@ module sj.TitleTextProgram; import gl4d; +import sj.util.image; + /// class TitleTextProgram { public: @@ -38,16 +40,54 @@ class TitleTextProgram { /// enum FragmentShaderSrc = ShaderHeader ~ q{ layout(location = 3) uniform sampler2D tex; + layout(location = 4) uniform int frame; in vec2 uv_; out vec4 pixel_; + float stepstep(float a, float b, float x) { + return step(a, x) * (1-step(b, x)); + } + void main() { - pixel_ = texture(tex, uv_); + vec2 uv = uv_; + + uv.x += stepstep(0.1, 0.2, uv.y) * + step(51.0, float(frame%61)) * 0.03; + uv.x += stepstep(0.3, 0.35, uv.y) * + step(85.0, float(frame%103)) * -0.05; + uv.x += stepstep(0.3, 0.4, uv.y) * + step(294.0, float(frame%303)) * 0.07; + uv.x += stepstep(0.35, 0.45, uv.y) * + step(475.0, float(frame%829)) * -0.01; + uv.x += stepstep(0.5, 0.6, uv.y) * + step(22.0, float(frame%78)) * 0.002; + uv.x += stepstep(0.55, 0.65, uv.y) * + step(32.0, float(frame%37)) * -0.007; + uv.x += stepstep(0.85, 0.95, uv.y) * + step(82.0, float(frame%273)) * 0.004; + uv.x += stepstep(0.7, 0.9, uv.y) * + step(152.0, float(frame%203)) * -0.005; + + vec4 texel = texture(tex, clamp(uv, 0, 1)); + pixel_.r = texel.a; + pixel_.g = texel.b; + pixel_.b = texel.g; + pixel_.a = texel.r; + + pixel_.r += stepstep(0.2, 0.25, uv.y) * + step(20.0, float(frame%30)) * 0.2; + pixel_.r += stepstep(0.5, 0.55, uv.y) * + step(83.0, float(frame%127)) * 0.2; + pixel_.r += stepstep(0.6, 0.75, uv.y) * + step(18, float(frame%21)) * 0.2; } }; + /// + enum ImgBuf = cast(ubyte[]) import("images/title.png"); + /// this() { ProgramLinker linker; @@ -55,11 +95,21 @@ class TitleTextProgram { linker.fragment = FragmentShader.Compile(FragmentShaderSrc); program_ = linker.Link(); program_.Validate(); - } - /// - void SetupVertexArray(ref VertexArrayRef vao, ref ArrayBufferRef vertices) { - vao.Bind(); + tex_ = CreateTextureFromBuffer(ImgBuf); + sampler_ = Sampler.Create(); + + SamplerConfigurer configurer; + with (configurer) { + filterMin = GL_LINEAR; + filterMag = GL_LINEAR; + Configure(sampler_); + } + + vao_ = VertexArray.Create(); + vertices_ = ArrayBuffer.Create(); + + vao_.Bind(); VertexArrayAttacher attacher; with (attacher) { index = 0; @@ -67,31 +117,56 @@ class TitleTextProgram { offset = 0; stride = Vertex.sizeof; dimension = 3; - Attach(vao, vertices); + Attach(vao_, vertices_); index = 1; type = GL_FLOAT; offset = vec3.sizeof; stride = Vertex.sizeof; dimension = 2; - Attach(vao, vertices); + Attach(vao_, vertices_); + } + + vertices_.Bind(); + ArrayBufferAllocator allocator; + with (allocator) { + const v = [ + -1f, 1f, 0f, 1f, 0f, + -1f, -1f, 0f, 1f, 1f, + 1f, -1f, 0f, 0f, 1f, + 1f, 1f, 0f, 0f, 0f, + ]; + data = v.ptr; + size = v.length * v[0].sizeof; + usage = GL_STATIC_DRAW; + Allocate(vertices_); } } /// - void Use( - mat4 proj, mat4 view, mat4 model, - ref Texture2DRef tex, ref SamplerRef sampler) { - tex.BindToUnit(GL_TEXTURE0); - sampler.Bind(0); + void Draw(mat4 proj, mat4 view, mat4 model, int frame) { + tex_.BindToUnit(GL_TEXTURE0); + sampler_.Bind(0); program_.Use(); program_.uniform!0 = proj; program_.uniform!1 = view; program_.uniform!2 = model; program_.uniform!3 = 0; + program_.uniform!4 = frame; + + vao_.Bind(); + gl.DrawArrays(GL_TRIANGLE_FAN, 0, 4); } private: ProgramRef program_; + + Texture2DRef tex_; + + SamplerRef sampler_; + + VertexArrayRef vao_; + + ArrayBufferRef vertices_; } diff --git a/src/sj/util/image.d b/src/sj/util/image.d new file mode 100644 index 0000000..70ba1b5 --- /dev/null +++ b/src/sj/util/image.d @@ -0,0 +1,37 @@ +/// License: MIT +module sj.util.image; + +import std.exception, + std.math, + std.string; + +import derelict.sfml2.graphics; + +import gl4d; + +/// +Texture2DRef CreateTextureFromBuffer(in ubyte[] buf) { + auto img = sfImage_createFromMemory(buf.ptr, buf.length); + scope(exit) sfImage_destroy(img); + return img.CreateTextureFromImage(); +} + +/// +Texture2DRef CreateTextureFromImage(sfImage* img) { + const sz = sfImage_getSize(img); + sz.x.isPowerOf2.enforce(); + sz.y.isPowerOf2.enforce(); + + auto tex = Texture2D.Create(); + Texture2DAllocator allocator; + with (allocator) { + level = 0; + internalFormat = GL_RGBA8; + data = sfImage_getPixelsPtr(img); + size = vec2i(sz.x, sz.y); + format = GL_RGBA; + type = GL_UNSIGNED_INT_8_8_8_8; + Allocate(tex); + } + return tex; +}