]> git.tdb.fi Git - libs/demoscene.git/blob - source/launcher.cpp
Add a vignette postprocessor
[libs/demoscene.git] / source / launcher.cpp
1 #include <cmath>
2 #include <msp/core/getopt.h>
3 #include <msp/gl/pipelinetemplate.h>
4 #include <msp/input/keys.h>
5 #include <msp/io/console.h>
6 #include <msp/io/file.h>
7 #include <msp/strings/regex.h>
8 #include <msp/time/utils.h>
9 #include "demo.h"
10 #include "launcher.h"
11 #include "launchscreen.h"
12 #include "vignette.h"
13
14 using namespace std;
15
16 namespace Msp {
17 namespace DemoScene {
18
19 LauncherBase::Options::Options(Graphics::Display &dpy, int argc, char **argv):
20         start_fullscreen(-1),
21         framerate(0),
22         no_music(false),
23         no_vsync(false)
24 {
25         unsigned fullscreen = 0;
26         string fullscreen_size;
27         unsigned windowed = 0;
28         string windowed_size;
29         float seek_seconds = 0.0f;
30
31         GetOpt getopt;
32         getopt.add_option('f', "fullscreen", fullscreen_size, GetOpt::OPTIONAL_ARG).bind_seen_count(fullscreen).set_help("Start in fullscreen mode", "SIZE");
33         getopt.add_option('w', "windowed", windowed_size, GetOpt::OPTIONAL_ARG).bind_seen_count(windowed).set_help("Start in windowed mode without delay", "SIZE");
34 #ifdef WITH_DEVELOPER
35         getopt.add_option('s', "seek", seek_seconds, GetOpt::REQUIRED_ARG).set_help("Start at TIME seconds", "TIME");
36         getopt.add_option("record-frames", frame_dump_fn, GetOpt::REQUIRED_ARG).set_help("Record raw frame data to FILE", "FILE");
37 #endif
38         getopt.add_option("no-music", no_music, GetOpt::NO_ARG).set_help("Disable music playback");
39         getopt.add_option("fps", framerate, GetOpt::REQUIRED_ARG).set_help("Run at NUM fps", "NUM");
40         getopt.add_option("no-vsync", no_vsync, GetOpt::NO_ARG).set_help("Disable vertical sync");
41         getopt(argc, argv);
42
43         if(fullscreen && windowed)
44                 throw usage_error("--fullscreen and --windowed are exclusive");
45
46         if(fullscreen)
47                 start_fullscreen = 1;
48         else if(windowed)
49                 start_fullscreen = 0;
50
51         const Graphics::VideoMode &desktop_mode = dpy.get_desktop_mode();
52         if(!windowed_size.empty())
53                 parse_size(windowed_size, win_opts);
54         else if(desktop_mode.width>1920 && desktop_mode.height>1080)
55         {
56                 win_opts.width = 1920;
57                 win_opts.height = 1080;
58         }
59         else
60         {
61                 win_opts.width = 1280;
62                 win_opts.height = 720;
63         }
64
65         if(!fullscreen_size.empty())
66                 parse_size(fullscreen_size, fullscreen_opts);
67         else
68         {
69                 fullscreen_opts.width = desktop_mode.width;
70                 fullscreen_opts.height = desktop_mode.height;
71         }
72         fullscreen_opts.fullscreen = true;
73         fullscreen_opts.fullscreen_monitor = desktop_mode.monitor;
74         fullscreen_opts.fullscreen_exclusive = false;
75
76         seek = seek_seconds*Time::sec;
77 }
78
79 void LauncherBase::Options::parse_size(const string &size, Graphics::WindowOptions &win_opts)
80 {
81         static Regex r_size("^([0-9]+)x([0-9]+)$");
82         RegMatch m = r_size.match(size);
83         if(!m)
84                 throw invalid_argument("Options::parse_size");
85
86         win_opts.width = lexical_cast<unsigned>(m[1].str);
87         win_opts.height = lexical_cast<unsigned>(m[2].str);
88 }
89
90
91 LauncherBase::LauncherBase(int argc, char **argv):
92         options(display, argc, argv),
93         window(display, options.start_fullscreen>0 ? options.fullscreen_opts : options.win_opts),
94         gl_context(window),
95         keyboard(window),
96         al_device(options.no_music ? 0 : new AL::Device),
97         al_context(options.no_music ? 0 : new AL::Context(*al_device)),
98         launch_screen(0),
99         demo(0),
100         frame_dump(0),
101         frame_size(0),
102         frame_dump_buffer(0)
103 {
104         gl_context.set_swap_interval(options.no_vsync ? 0 : 1);
105         window.signal_close.connect(sigc::bind(sigc::mem_fun(this, &LauncherBase::exit), 0));
106         keyboard.signal_button_press.connect(sigc::bind_return(sigc::mem_fun(this, &LauncherBase::key_press), false));
107
108         GL::PipelineTemplate::register_postprocessor<Vignette>("vignette");
109 }
110
111 LauncherBase::~LauncherBase()
112 {
113         delete launch_screen;
114         delete demo;
115         delete[] frame_dump_buffer;
116         delete al_context;
117         delete al_device;
118 }
119
120 void LauncherBase::start()
121 {
122         window.show();
123         if(options.start_fullscreen>=0)
124                 start_demo(options.start_fullscreen);
125         else
126         {
127                 launch_screen = new LaunchScreen(get_resources());
128                 timeout = Time::now()+5*Time::sec;
129         }
130 }
131
132 void LauncherBase::tick()
133 {
134         if(demo)
135                 tick_demo();
136         else if(launch_screen)
137                 tick_launch_screen();
138 }
139
140 void LauncherBase::tick_demo()
141 {
142         Time::TimeStamp t = Time::now();
143         if(timeout)
144         {
145                 if(t<timeout)
146                         return;
147                 timeout = Time::TimeStamp();
148         }
149
150         if(!options.no_vsync && t<demo->get_next_frame_time())
151                 return;
152
153         display.tick();
154         demo->tick();
155
156 #ifdef WITH_DEVELOPER
157         if(frame_dump)
158         {
159                 glReadPixels(0, 0, window.get_width(), window.get_height(), GL_RGB, GL_UNSIGNED_BYTE, frame_dump_buffer);
160                 frame_dump->write(frame_dump_buffer, frame_size);
161         }
162 #endif
163 }
164
165 void LauncherBase::tick_launch_screen()
166 {
167         Time::TimeStamp t = Time::now();
168         Time::TimeDelta time_left = timeout-t;
169         if(time_left>Time::zero)
170                 launch_screen->set_countdown(ceil(time_left/Time::sec));
171         else
172                 start_demo(true);
173
174         display.tick();
175         launch_screen->render();
176         gl_context.swap_buffers();
177
178         if(demo)
179         {
180                 delete launch_screen;
181                 launch_screen = 0;
182         }
183 }
184
185 void LauncherBase::start_demo(bool fullscreen)
186 {
187         if(fullscreen)
188         {
189                 window.reconfigure(options.fullscreen_opts);
190                 window.show_cursor(false);
191                 timeout = Time::now()+Time::sec;
192         }
193         else
194                 timeout = Time::TimeStamp();
195
196         demo = create_demo();
197         if(!options.no_music)
198                 demo->enable_music();
199         if(options.framerate)
200                 demo->set_fixed_framerate(options.framerate);
201         if(options.seek)
202                 demo->seek(options.seek);
203         demo->signal_finished.connect(sigc::bind(sigc::mem_fun(this, &LauncherBase::exit), 0));
204
205         if(!options.frame_dump_fn.empty())
206         {
207                 if(options.frame_dump_fn=="-")
208                         frame_dump = &IO::cout;
209                 else
210                         frame_dump = new IO::File(options.frame_dump_fn, IO::M_WRITE);
211                 frame_size = window.get_width()*window.get_height()*3;
212                 frame_dump_buffer = new char[frame_size];
213         }
214 }
215
216 void LauncherBase::key_press(unsigned key)
217 {
218         if(key==Input::KEY_ENTER && !demo)
219                 start_demo(false);
220         else if(key==Input::KEY_ESC)
221                 exit(0);
222 }
223
224 } // namespace DemoScene
225 } // namespace Msp