diff --git a/src/main.d b/src/main.d index 28ec290..2f8126f 100644 --- a/src/main.d +++ b/src/main.d @@ -1,5 +1,106 @@ /// License: MIT +import std; -int main(string[] args) { +import derelict.sfml2.audio, + derelict.sfml2.system, + derelict.sfml2.window; + +import gl4d; + +import sj.Args, + sj.Game, + sj.KeyInput; + +enum WindowTitle = "shapes-juke"; + +int main(string[] unparsed_args) { + Args args; + if (!ParseArgs(unparsed_args, args)) return 1; + + auto win = CreateWindow(args); + auto game = new Game; + scope(exit) game.destroy(); + + while (true) { + sfEvent e; + sfWindow_pollEvent(win, &e); + if (e.type == sfEvtClosed) break; + + game.Update(GetKeyInput()); + game.Draw(); + win.Flush(); + } return 0; } + +private bool ParseArgs(string[] unparsed_args, out Args args) { + auto helpinfo = unparsed_args.getopt( + "window-size", &args.window_size + ); + + auto valid = true; + if (args.window_size <= 100) { + "invalid window size (it should be 100 or more)".writeln; + valid = false; + } + + if (!valid || helpinfo.helpWanted) { + defaultGetoptPrinter(WindowTitle, helpinfo.options); + return false; + } + return true; +} + +private KeyInput GetKeyInput() { + KeyInput result; + result.left = !!sfKeyboard_isKeyPressed(sfKeyLeft); + result.right = !!sfKeyboard_isKeyPressed(sfKeyRight); + result.up = !!sfKeyboard_isKeyPressed(sfKeyUp); + result.down = !!sfKeyboard_isKeyPressed(sfKeyDown); + return result; +} + +private auto CreateWindow(ref in Args args) { + DerelictSFML2System.load(); + DerelictSFML2Window.load(); + DerelictSFML2Audio .load(); + + sfContextSettings specs; + specs.depthBits = 24; + specs.stencilBits = 8; + specs.antialiasingLevel = 1; + specs.majorVersion = 3; + specs.minorVersion = 3; + specs.attributeFlags = sfContextCore; + + auto win = sfWindow_create( + sfVideoMode(args.window_size, args.window_size), + WindowTitle.toStringz, + sfClose | sfTitlebar, + &specs). + enforce; + + 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); + + static struct Window { + public: + ~this() { + sfWindow_destroy(window_); + } + void Flush() { + sfWindow_display(window_); + } + + @property auto ptr() { return window_; } + alias ptr this; + + private: + ReturnType!sfWindow_create window_; + } + return Window(win); +} diff --git a/src/sj/AbstractGame.d b/src/sj/AbstractGame.d new file mode 100644 index 0000000..eec5ff1 --- /dev/null +++ b/src/sj/AbstractGame.d @@ -0,0 +1,32 @@ +/// License: MIT +module sj.AbstractGame; + +import gl4d; + +import sj.KeyInput, + sj.SceneInterface; + +/// +class AbstractGame { + public: + /// + this(SceneInterface first_scene) in (first_scene) { + scene_ = first_scene; + } + + /// + void Update(KeyInput input) { + if (auto next = scene_.TakeNextScene()) { + scene_ = next; + } + scene_.Update(input); + } + /// + void Draw() { + gl.Clear(GL_COLOR_BUFFER_BIT); + scene_.Draw(); + } + + private: + SceneInterface scene_; +} diff --git a/src/sj/AbstractScene.d b/src/sj/AbstractScene.d new file mode 100644 index 0000000..3586922 --- /dev/null +++ b/src/sj/AbstractScene.d @@ -0,0 +1,30 @@ +/// License: MIT +module sj.AbstractScene; + +import sj.KeyInput, + sj.SceneInterface; + +/// +class AbstractScene : SceneInterface { + public: + /// + this() { + } + + abstract override { + void Update(KeyInput input); + void Draw(); + } + + override SceneInterface TakeNextScene() { + return next_; + } + + protected: + void GoNextScene(SceneInterface next) in (next) { + next_ = next; + } + + private: + SceneInterface next_; +} diff --git a/src/sj/Args.d b/src/sj/Args.d new file mode 100644 index 0000000..c838f8a --- /dev/null +++ b/src/sj/Args.d @@ -0,0 +1,9 @@ +/// License: MIT +module sj.Args; + +/// +struct Args { + public: + /// + int window_size = 600; +} diff --git a/src/sj/Game.d b/src/sj/Game.d new file mode 100644 index 0000000..b084246 --- /dev/null +++ b/src/sj/Game.d @@ -0,0 +1,20 @@ +/// License: MIT +module sj.Game; + +import sj.AbstractGame, + sj.TitleScene; + +/// +class Game : AbstractGame { + public: + /// + this() { + title_ = new TitleScene; + title_.Initialize(title_); // TODO: specify proper next scene + + super(title_); + } + + private: + TitleScene title_; +} diff --git a/src/sj/KeyInput.d b/src/sj/KeyInput.d new file mode 100644 index 0000000..da78b1f --- /dev/null +++ b/src/sj/KeyInput.d @@ -0,0 +1,14 @@ +/// License: MIT +module sj.KeyInput; + +import std.typecons; + +/// +alias KeyInput = BitFlags!KeyInputType; + +private enum KeyInputType { + left = 1 << 0, + right = 1 << 1, + up = 1 << 2, + down = 1 << 3, +} diff --git a/src/sj/SceneInterface.d b/src/sj/SceneInterface.d new file mode 100644 index 0000000..b20c42f --- /dev/null +++ b/src/sj/SceneInterface.d @@ -0,0 +1,16 @@ +/// License: MIT +module sj.SceneInterface; + +import sj.KeyInput; + +/// +interface SceneInterface { + public: + /// + void Update(KeyInput input); + /// + void Draw(); + + /// + SceneInterface TakeNextScene(); +} diff --git a/src/sj/TitleScene.d b/src/sj/TitleScene.d new file mode 100644 index 0000000..e6b4223 --- /dev/null +++ b/src/sj/TitleScene.d @@ -0,0 +1,27 @@ +/// License: MIT +module sj.TitleScene; + +import sj.AbstractScene, + sj.KeyInput, + sj.SceneInterface; + +/// +class TitleScene : AbstractScene { + public: + /// + this() { + } + + /// + void Initialize(SceneInterface next_scene) { + next_scene_ = next_scene; + } + + override void Update(KeyInput input) { + } + override void Draw() { + } + + private: + SceneInterface next_scene_; +}