1 module caLib_util.Controller;
2 
3 import caLib_abstract.lattice : isLattice;
4 import caLib_abstract.rule : isRule, isReversibleRule;
5 import caLib_abstract.renderer : isRenderer;
6 import caLib_util.structs : Simulation;
7 import derelict.sdl2.sdl;
8 import std.stdio: writeln;
9 import std.exception : Exception;
10 
11 
12 
13 auto create_Controller(Lt, Rt, REt)(Simulation!(Lt, Rt, REt) simulation)
14 {
15     return create_Controller(simulation.lattice, simulation.rule, simulation.renderer);
16 }
17 
18 
19 
20 auto create_Controller(Lt, Rt, REt)(Lt* lattice, Rt* rule, REt* renderer)
21 {
22     return new Controller!(Lt, Rt, REt)(lattice, rule, renderer);
23 }
24 
25 
26 
27 class Controller(Lt, Rt, REt)
28 {
29 
30 private:
31 
32     Lt* lattice;
33     Rt* rule;
34     REt* renderer;
35 
36     void delegate() task;
37     bool running;
38     bool recording;
39 
40     static if(isReversibleRule!Rt)
41     {
42         bool reverse;
43     }
44 
45 public:
46 
47     this(Lt* lattice, Rt* rule, REt* renderer)
48     {
49         this.lattice = lattice;
50         this.rule = rule;
51         this.renderer = renderer;
52 
53         this.task = null;
54         this.running = false;
55         this.recording = false;
56 
57         static if(isReversibleRule!Rt)
58         {
59             bool reverse = false;
60         }
61     }
62 
63     void start()
64     {
65         renderer.render();
66 
67         task = &this.pause;
68 
69         while(true)
70         {
71             SDL_Event events;
72             while(SDL_PollEvent(&events))
73             {
74                 if(events.type == SDL_QUIT)
75                 {
76                     return;
77                 }
78                 else if(events.type == SDL_KEYDOWN)
79                 {
80                     if(events.key.keysym.sym == SDLK_SPACE)
81                     {
82                         if(running)
83                         {
84                             task = &this.pause;
85                             running = false;
86                         }
87                         else
88                         {
89                             task = &this.run;
90                             running = true;
91                         }
92                     }
93                     else if(events.key.keysym.sym == SDLK_d)
94                     {
95                         run();
96                         task = &this.pause;
97                         running = false;
98                     }
99                     else if(events.key.keysym.sym == SDLK_s)
100                     {
101                         screenshot();
102                     }
103                     else if(events.key.keysym.sym == SDLK_r)
104                     {
105                         record();
106                     }
107                     static if(isReversibleRule!Rt)
108                     {
109                         if(events.key.keysym.sym == SDLK_a)
110                         {
111                             reverse = !reverse;
112                             writeln("running reverse");
113                         }
114                     }
115                 }
116             }
117 
118             task();
119         }
120     }
121 
122     void pause() {}
123 
124     void run()
125     {
126         static if(isReversibleRule!Rt)
127         {
128             if(!reverse)
129                 rule.applyRule();
130             else
131                 rule.applyRuleReverse();
132         }
133         else
134         {
135             rule.applyRule();
136         }
137         renderer.render();
138     }
139 
140     void screenshot()
141     {
142         writeln("screenshoting. The programm might seem unresponsive");
143         try
144         {
145             renderer.screenshot("screenshot.png");
146             writeln("done screenshoting");
147         }
148         catch(Exception e)
149         {
150             writeln("could not screenshot. Error message:\n    ", e.msg);
151         }
152     }
153 
154     void record()
155     {
156         if(recording)
157         {
158             scope(exit) recording = false;
159             try
160             {
161                 renderer.stopRecording();
162                 writeln("done recording");
163             }
164             catch(Exception e)
165             {
166                 writeln("could not complete recording. Error message:\n    ",
167                     e.msg);
168             }
169         }
170         else
171         {
172             try
173             {
174                 renderer.startRecording("recording.mp4", 10);
175                 writeln("recording.. Press r to stop recording");
176                 recording = true;
177             }
178             catch(Exception e)
179             {
180                 writeln("could not start recording. Error message:\n    ",
181                     e.msg);
182 
183                 recording = false;
184             }
185         }
186     }
187 }