1 module d2d.toolkit.game;
2 
3 import d2d;
4 
5 import std.datetime.stopwatch;
6 
7 /// Class for easily creating a window
8 abstract class Game
9 {
10 private:
11 	int _width = 800, _height = 480;
12 	Bitmap _icon = null;
13 	Window _window = null;
14 	string _title = "Game";
15 	int _fps = 60;
16 	StopWatch _stopwatch;
17 	WindowFlags _flags = WindowFlags.Default;
18 	ShaderProgram _postShader = null;
19 
20 protected:
21 	/// Window start width, will not update afterwards
22 	@property ref int windowWidth()
23 	{
24 		return _width;
25 	}
26 
27 	/// Window start height, will not update afterwards
28 	@property ref int windowHeight()
29 	{
30 		return _height;
31 	}
32 
33 	/// Window icon, will not update afterwards
34 	@property ref Bitmap windowIcon()
35 	{
36 		return _icon;
37 	}
38 
39 	/// Window title, will not update afterwards
40 	@property ref string windowTitle()
41 	{
42 		return _title;
43 	}
44 
45 	/// Max FPS, will not update afterwards
46 	@property ref int maxFPS()
47 	{
48 		return _fps;
49 	}
50 
51 	/// Window start flags, will not update afterwards
52 	@property ref WindowFlags flags()
53 	{
54 		return _flags;
55 	}
56 
57 	/// Handle to the window.
58 	@property Window window()
59 	{
60 		return _window;
61 	}
62 
63 	/// Optional post processing shader.
64 	@property ref ShaderProgram postShader()
65 	{
66 		return _postShader;
67 	}
68 
69 	/// Start function will get called before window is created. Variables can be changed here.
70 	abstract void start();
71 
72 	/// Load function thats meant for loading content.
73 	abstract void load();
74 
75 	/// Will get called every frame before `draw`.
76 	abstract void update(float delta);
77 
78 	/// Draw code goes here, `window.display` is not needed.
79 	abstract void draw();
80 
81 	/// Happens when some window event gets called.
82 	void onEvent(Event event)
83 	{
84 		Keyboard.instance.handle(event);
85 		Mouse.instance.handle(event);
86 	}
87 
88 public:
89 	/// Starts the window and calls all functions
90 	void run()
91 	{
92 		start();
93 
94 		_window = new Window(_width, _height, _title, _flags);
95 
96 		if (_icon is null)
97 		{
98 			//dfmt off
99 			_icon = new Bitmap(
100 				[
101 					0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff,
102 					0x00ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00ffffff,
103 					0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffcccccc, 0xffcccccc, 0xffcccccc, 0xff9c9c9c, 0xff000000, 0xff000000, 0xff000000, 0xff383838, 0xffcccccc, 0xffffffff,
104 					0xffffffff, 0xff000000, 0xff303030, 0xff303030, 0xff303030, 0xff1c1c1c, 0xff000000, 0xff9c9c9c, 0xffcccccc, 0xff000000, 0xff292929, 0xff303030, 0xff292929, 0xff000000, 0xff6d6d6d, 0xffffffff,
105 					0xffffffff, 0xff000000, 0xffcccccc, 0xffcccccc, 0xffcccccc, 0xff707070, 0xff131313, 0xff000000, 0xffcccccc, 0xff303030, 0xffb7b7b7, 0xffcccccc, 0xffb7b7b7, 0xff131313, 0xff000000, 0xffffffff,
106 					0xffffffff, 0xff000000, 0xffcccccc, 0xffcccccc, 0xffcccccc, 0xffcccccc, 0xff555555, 0xff000000, 0xff9c9c9c, 0xffcccccc, 0xffcccccc, 0xffcccccc, 0xffcccccc, 0xff1e1e1e, 0xff000000, 0xffffffff,
107 					0xffffffff, 0xff000000, 0xffcccccc, 0xffcccccc, 0xffcccccc, 0xffcccccc, 0xffa7a7a7, 0xff000000, 0xff6d6d6d, 0xffcccccc, 0xffcccccc, 0xffcccccc, 0xffb0b0b0, 0xff000000, 0xff555555, 0xffffffff,
108 					0xffffffff, 0xff000000, 0xffcccccc, 0xffcccccc, 0xffcccccc, 0xffcccccc, 0xffb0b0b0, 0xff000000, 0xff727272, 0xffcccccc, 0xffcccccc, 0xffcccccc, 0xff333333, 0xff0d0d0d, 0xffa7a7a7, 0xffffffff,
109 					0xffffffff, 0xff000000, 0xffcccccc, 0xffcccccc, 0xffcccccc, 0xffcccccc, 0xff8b8b8b, 0xff000000, 0xff909090, 0xffcccccc, 0xffcccccc, 0xff545454, 0xff000000, 0xff5b5b5b, 0xffcccccc, 0xffffffff,
110 					0xffffffff, 0xff000000, 0xffcccccc, 0xffcccccc, 0xffcccccc, 0xffcccccc, 0xff444444, 0xff060606, 0xffb7b7b7, 0xffcccccc, 0xff545454, 0xff000000, 0xff454545, 0xffcccccc, 0xffcccccc, 0xffffffff,
111 					0xffffffff, 0xff000000, 0xffcccccc, 0xffcccccc, 0xffcccccc, 0xff545454, 0xff000000, 0xff343434, 0xffcccccc, 0xff545454, 0xff000000, 0xff303030, 0xffcccccc, 0xffcccccc, 0xffcccccc, 0xffffffff,
112 					0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff303030, 0xffa7a7a7, 0xffb0b0b0, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff,
113 					0xffffffff, 0xff303030, 0xff303030, 0xff303030, 0xff303030, 0xff454545, 0xffcccccc, 0xffcccccc, 0xffb7b7b7, 0xff303030, 0xff303030, 0xff303030, 0xff303030, 0xff303030, 0xff303030, 0xffffffff,
114 					0x00ffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00ffffff,
115 					0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff,
116 					0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff,
117 				], 16, 16, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
118 			//dfmt on
119 		}
120 
121 		_window.setIcon(_icon);
122 
123 		FPSLimiter limiter;
124 		if (_fps > 0)
125 			limiter = new FPSLimiter(_fps);
126 
127 		load();
128 
129 		Event event;
130 		Duration delta;
131 		while (_window.open)
132 		{
133 			_stopwatch.start();
134 			while (_window.pollEvent(event))
135 			{
136 				if (event.type == Event.Type.Quit)
137 					_window.close();
138 				else
139 					onEvent(event);
140 			}
141 
142 			update(delta.total!"hnsecs" / 10_000_000.0f);
143 
144 			draw();
145 
146 			if (_postShader !is null)
147 				_window.display(_postShader);
148 			else
149 				_window.display();
150 
151 			if (limiter !is null)
152 				limiter.wait();
153 
154 			_stopwatch.stop();
155 			delta = _stopwatch.peek();
156 			_stopwatch.reset();
157 		}
158 	}
159 }