1// SuperTux
2// Copyright (C) 2006 Matthias Braun <matze@braunis.de>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17#include "video/video_system.hpp"
18
19#include <assert.h>
20#include <boost/optional.hpp>
21#include <config.h>
22#include <iomanip>
23#include <physfs.h>
24#include <sstream>
25
26#include "util/file_system.hpp"
27#include "util/log.hpp"
28#include "video/null/null_video_system.hpp"
29#include "video/sdl/sdl_video_system.hpp"
30#include "video/sdl_surface.hpp"
31#include "video/sdl_surface_ptr.hpp"
32
33#ifdef HAVE_OPENGL
34# include "video/gl/gl_video_system.hpp"
35#endif
36
37std::unique_ptr<VideoSystem>
38VideoSystem::create(VideoSystem::Enum video_system)
39{
40 switch (video_system)
41 {
42 case VIDEO_AUTO:
43#ifdef HAVE_OPENGL
44 try
45 {
46 return std::make_unique<GLVideoSystem>(true);
47 }
48 catch(std::exception& err)
49 {
50 try
51 {
52 log_warning << "Error creating GLVideoSystem-330core, using GLVideoSystem-20 fallback: " << err.what() << std::endl;
53 return std::make_unique<GLVideoSystem>(false);
54 }
55 catch(std::exception& err2)
56 {
57 log_warning << "Error creating GLVideoSystem-20, using SDL fallback: " << err2.what() << std::endl;
58 return std::make_unique<SDLVideoSystem>();
59 }
60 }
61#else
62 log_info << "new SDL renderer\n";
63 return std::make_unique<SDLVideoSystem>();
64#endif
65
66#ifdef HAVE_OPENGL
67 case VIDEO_OPENGL33CORE:
68 return std::make_unique<GLVideoSystem>(true);
69
70 case VIDEO_OPENGL20:
71 return std::make_unique<GLVideoSystem>(false);
72#else
73 case VIDEO_OPENGL33CORE:
74 case VIDEO_OPENGL20:
75 log_warning << "OpenGL requested, but missing using SDL fallback" << std::endl;
76 return std::make_unique<SDLVideoSystem>();
77#endif
78
79 case VIDEO_SDL:
80 log_info << "new SDL renderer\n";
81 return std::make_unique<SDLVideoSystem>();
82
83 case VIDEO_NULL:
84 return std::make_unique<NullVideoSystem>();
85
86 default:
87 log_fatal << "invalid video system in config" << std::endl;
88 assert(false);
89 return {};
90 }
91}
92
93VideoSystem::Enum
94VideoSystem::get_video_system(const std::string &video)
95{
96 if (video == "auto")
97 {
98 return VIDEO_AUTO;
99 }
100#ifdef HAVE_OPENGL
101 else if (video == "opengl" || video == "opengl33" || video == "opengl33core")
102 {
103 return VIDEO_OPENGL33CORE;
104 }
105 else if (video == "opengl20")
106 {
107 return VIDEO_OPENGL20;
108 }
109#endif
110 else if (video == "sdl")
111 {
112 return VIDEO_SDL;
113 }
114 else if (video == "null")
115 {
116 return VIDEO_NULL;
117 }
118 else
119 {
120#ifdef HAVE_OPENGL
121 throw std::runtime_error("invalid VideoSystem::Enum, valid values are 'auto', 'sdl', 'opengl', 'opengl20' and 'null'");
122#else
123 throw std::runtime_error("invalid VideoSystem::Enum, valid values are 'auto' and 'sdl'");
124#endif
125 }
126}
127
128std::string
129VideoSystem::get_video_string(VideoSystem::Enum video)
130{
131 switch (video)
132 {
133 case VIDEO_AUTO:
134 return "auto";
135 case VIDEO_OPENGL33CORE:
136 return "opengl";
137 case VIDEO_OPENGL20:
138 return "opengl20";
139 case VIDEO_SDL:
140 return "sdl";
141 case VIDEO_NULL:
142 return "null";
143 default:
144 log_fatal << "invalid video system in config" << std::endl;
145 assert(false);
146 return "auto";
147 }
148}
149
150void
151VideoSystem::do_take_screenshot()
152{
153 SDLSurfacePtr surface = make_screenshot();
154 if (!surface) {
155 log_warning << "Creating the screenshot has failed" << std::endl;
156 return;
157 }
158
159 const std::string screenshots_dir = "/screenshots";
160 if (!PHYSFS_exists(screenshots_dir.c_str())) {
161 if (!PHYSFS_mkdir(screenshots_dir.c_str())) {
162 log_warning << "Creating '" << screenshots_dir << "' failed" << std::endl;
163 return;
164 }
165 }
166
167 auto find_filename = [&]() -> boost::optional<std::string>
168 {
169 for (int num = 0; num < 1000000; ++num)
170 {
171 std::ostringstream oss;
172 oss << "screenshot" << std::setw(6) << std::setfill('0') << num << ".png";
173 const std::string screenshot_filename = FileSystem::join(screenshots_dir, oss.str());
174 if (!PHYSFS_exists(screenshot_filename.c_str())) {
175 return screenshot_filename;
176 }
177 }
178 return boost::none;
179 };
180
181 auto filename = find_filename();
182 if (!filename)
183 {
184 log_info << "Failed to find filename to save screenshot" << std::endl;
185 }
186 else
187 {
188 if (SDLSurface::save_png(*surface, *filename)) {
189 log_info << "Wrote screenshot to \"" << *filename << "\"" << std::endl;
190 }
191 }
192}
193
194/* EOF */
195