1 module armos.app.runner;
2 import armos.app;
3 import armos.utils;
4 import armos.events;
5 import armos.graphics;
6 
7 /++
8 armosのアプリケーションの更新を行うclassです.
9 +/
10 class Runner {
11     public{
12         /++
13         +/
14         this(){
15             _fpsCounter = new FpsCounter;
16             _events = new CoreEvents;
17         }
18         
19         /++
20             イベントループに入ります.
21             Params:
22             app = 更新されるアプリケーションです.
23         +/
24         void run(WindowType)(BaseApp app, WindowConfig config){
25             _application = app;
26             addListener(events.setup, app, &app.setup);
27             addListener(events.update, app, &app.update);
28             addListener(events.draw, app, &app.draw);
29             addListener(events.exit, app, &app.exit);
30             
31             createWindow!(WindowType)(app, config);
32             
33             loop();
34         };
35 
36         /++
37             現在のFPS(Frame Per Second)の使用率を返します.
38         +/
39         double fpsUseRate(){
40             return _fpsCounter.fpsUseRate;
41         }
42 
43         /++
44             FPS(Frame Per Second)を指定します.
45         +/
46         void targetFps(in double fps){
47             _fpsCounter.targetFps = fps;
48         }
49         
50         ///
51         double targetFps()const{
52             return _fpsCounter.targetFps;
53         }
54         
55         ///
56         double currentFps()const{
57             return _fpsCounter.currentFps;
58         }
59         
60         ///
61         Renderer renderer(){return _renderer;}
62         
63         ///
64         CoreEvents events(){return _events;};
65 
66         ///
67         Window window(){return _window;}
68     }//public
69 
70     private{
71         BaseApp    _application;
72         CoreEvents _events;
73         Renderer   _renderer;
74         Window     _window;
75 
76         bool _isLoop = true;
77         FpsCounter _fpsCounter;
78 
79         void createWindow(WindowType)(BaseApp app, WindowConfig config){
80             _window = new WindowType(app, _events, config);
81             
82             static if(WindowType.hasRenderer){
83                 _renderer = new Renderer;
84             }
85             
86             assert(_window);
87             
88             if(_renderer){
89                 _renderer.setup();
90             }
91         };
92 
93         void loop(){
94             _application.initHeldKeys;
95             
96             _events.notifySetup();
97             while(_isLoop){
98                 loopOnce();
99                 _fpsCounter.adjust();
100                 _fpsCounter.newFrame();
101                 _isLoop = !_window.shouldClose&&!_application.shouldClose;
102             }
103             _events.notifyExit();
104             _window.close();
105         }
106 
107         void loopOnce(){
108             _events.notifyUpdate();
109             if(_renderer){
110                 _renderer.startRender();
111             }
112             _events.notifyDraw();
113             if(_renderer){
114                 _renderer.finishRender();
115             }
116             _application.updateKeys;
117             _window.pollEvents();
118             _window.update();
119         }
120 
121     }//private
122 }
123 private Runner mainLoop_;
124 Runner mainLoop() @property
125 {
126     return mainLoop_;
127     // static __gshared Runner instance;
128     // import std.concurrency : initOnce;
129     // return initOnce!instance(new Runner);
130 }
131 
132 /++
133     armosのアプリケーションを実行します.
134     Params:
135     WindowType = 立ち上げるWindowの型を指定します.省略可能です.
136     app = 立ち上げるアプリケーションを指定します.
137 +/
138 void run(WindowType = GLFWWindow)(BaseApp app, WindowConfig config = null){
139     mainLoop_ = new Runner;
140     if(!config){
141         config = new WindowConfig();
142         with(config){
143             glVersion = SemVer(3, 3, 0);
144             width = 640;
145             height = 480;
146         }
147     }
148     mainLoop.run!(WindowType)(app, config);
149 }
150 
151 /++
152     現在のFPS(Frame Per Second)の使用率を返します.
153 +/
154 double fpsUseRate(){
155     return mainLoop.fpsUseRate;
156 }
157 
158 /++
159     FPS(Frame Per Second)を指定します.
160 +/
161 void targetFps(in double fps){
162     mainLoop.targetFps(fps);
163 }
164 
165 double targetFps(){
166     return mainLoop.targetFps;
167 }
168 
169 CoreEvents currentEvents(){
170     return mainLoop.events;
171 }
172 
173 double currentFps(){
174     return mainLoop.currentFps;
175 }