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