1 module armos.app.runner;
2 
3 import armos.app;
4 import armos.utils;
5 import armos.events;
6 import armos.graphics;
7 
8 import std.algorithm;
9 import std.array;
10 
11 /++
12 armosのアプリケーションの更新を行うclassです.
13 +/
14 
15 
16 class Runner {
17     public{
18         /++
19         +/
20         this(){
21             _fpsCounter = new FpsCounter;
22         }
23         
24         /++
25             イベントループに入ります.
26             Params:
27             app = 更新されるアプリケーションです.
28         +/
29         Runner register(Application app, Window window){
30             window.initEvents(app);
31             _appsCollection.add(app, window);
32             return this;
33         };
34 
35         /++
36             現在のFPS(Frame Per Second)の使用率を返します.
37         +/
38         double fpsUseRate(){
39             return _fpsCounter.fpsUseRate;
40         }
41 
42         /++
43             FPS(Frame Per Second)を指定します.
44         +/
45         void targetFps(in double fps){
46             _fpsCounter.targetFps = fps;
47         }
48         
49         ///
50         double targetFps()const{
51             return _fpsCounter.targetFps;
52         }
53         
54         ///
55         double currentFps()const{
56             return _fpsCounter.currentFps;
57         }
58         
59         ///
60         Renderer renderer()out(renderer){
61             assert(renderer);
62         }body{
63             return currentWindow.renderer;
64         }
65         
66         ///
67         Window currentWindow()out(window){
68             assert(window);
69         }body{
70             return _currentWindow;
71         }
72 
73         CoreObservables currentObservables(){
74             return currentWindow.observables;
75         }
76 
77         ///
78         Runner loop(){
79             foreach (winapp; _appsCollection.byPair) {
80                 auto window = winapp[0];
81                 auto app    = winapp[1];
82                 select(window);
83                 window.setup;
84             }
85 
86             bool isLoop = true;
87             while(isLoop){
88                 loopOnce();
89                 _fpsCounter.adjust();
90                 _fpsCounter.newFrame();
91                 import std.functional;
92                 isLoop = _appsCollection.keys.length > 0;
93             }
94 
95             foreach (winapp; _appsCollection.byPair) {
96                 auto window = winapp[0];
97                 auto app    = winapp[1];
98                 select(window);
99             }
100             return this;
101         }
102 
103         void select(Window window){
104             window.select;
105             _currentWindow = window;
106         }
107     }//public
108 
109     private{
110         AppCollection _appsCollection;
111         Window _currentWindow;
112 
113         FpsCounter _fpsCounter;
114 
115 
116 
117         void loopOnce(){
118             foreach (winapp; _appsCollection.byPair) {
119                 auto window = winapp[0];
120                 auto app    = winapp[1];
121                 select(window);
122                 window.update();
123                 window.draw();
124             }
125             _appsCollection.keys.each!(w => w.pollEvents());
126             
127             Window[] shouldRemoves;
128             foreach (winapp; _appsCollection.byPair) {
129                 auto window = winapp[0];
130                 auto app    = winapp[1];
131 
132                 if(window.shouldClose||app.shouldClose){
133                     window.close;
134                     shouldRemoves ~= window;
135                 }
136             }
137             shouldRemoves.each!(w => _appsCollection.remove(w));
138         }
139 
140     }//private
141 }
142 
143 Runner mainLoop() @property {
144     static __gshared Runner instance;
145     import std.concurrency : initOnce;
146     return initOnce!instance(new Runner);
147 }
148 
149 /++
150     armosのアプリケーションを実行します.
151     Params:
152     WindowType = 立ち上げるWindowの型を指定します.省略可能です.
153     app = 立ち上げるアプリケーションを指定します.
154 +/
155 void run(WindowType = GLFWWindow)(Application app, WindowConfig config = null){
156     // mainLoop_ = new Runner;
157     if(!config){
158         config = new WindowConfig();
159         with(config){
160             glVersion = SemVer(3, 3, 0);
161             width = 640;
162             height = 480;
163         }
164     }
165 
166     Window window = new WindowType(config);
167     mainLoop.register(app, window);
168     mainLoop.loop;
169 }
170 
171 /++
172     現在のFPS(Frame Per Second)の使用率を返します.
173 +/
174 double fpsUseRate(){
175     return mainLoop.fpsUseRate;
176 }
177 
178 /++
179     FPS(Frame Per Second)を指定します.
180 +/
181 void targetFps(in double fps){
182     mainLoop.targetFps(fps);
183 }
184 
185 double targetFps(){
186     return mainLoop.targetFps;
187 }
188 
189 CoreObservables currentObservables(){
190     return mainLoop.currentObservables;
191 }
192 
193 double currentFps(){
194     return mainLoop.currentFps;
195 }
196 
197 ulong currentFrames(){
198     return mainLoop._fpsCounter.currentFrames();
199 }