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