FlightGear next
WindowBuilder.cxx
Go to the documentation of this file.
1// Copyright (C) 2008 Tim Moore
2//
3// This program is free software; you can redistribute it and/or
4// modify it under the terms of the GNU General Public License as
5// published by the Free Software Foundation; either version 2 of the
6// License, or (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful, but
9// WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11// General Public License for more details.
12//
13// You should have received a copy of the GNU General Public License
14// along with this program; if not, write to the Free Software
15// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16
17#include "config.h"
18
19#include "WindowBuilder.hxx"
21#include <Main/fg_props.hxx>
22
23#include <GUI/MessageBox.hxx>
24
25#if defined(SG_MAC)
26 #include <osgViewer/api/Cocoa/GraphicsWindowCocoa>
27#endif
28
29using namespace std;
30using namespace osg;
31
32// forwarding proxy from QtLauncher.cxx to avoid weird double-gl.h include
33// errors from MSVC
38
39namespace {
40
43template <typename T>
44inline int setFromProperty(T& place, const SGPropertyNode* node, const std::string& name)
45{
46 const SGPropertyNode* prop = node->getNode(name);
47 if (prop) {
48 place = prop->getValue<T>();
49 return 1;
50 }
51 return 0;
52}
53
55GraphicsContext* attemptToCreateGraphicsContext(const GraphicsContext::Traits* traits,
56 const std::string& contextVersion,
57 unsigned int profileMask)
58{
59 // We copy the traits object locally here because it gets deleted if
60 // context creation is unsuccessful.
61 ref_ptr<GraphicsContext::Traits> copy =
62 new GraphicsContext::Traits(*traits);
63 copy->glContextVersion = contextVersion;
64 copy->glContextProfileMask = profileMask;
65 return GraphicsContext::createGraphicsContext(copy);
66}
67
68} // anonymous namespace
69
70namespace flightgear {
71
72ref_ptr<WindowBuilder> WindowBuilder::windowBuilder;
73
74// default to true (historical behaviour), we will clear the flag if
75// we run another GUI.
77
82
87
89{
90 GraphicsContext::WindowingSystemInterface* wsi
91 = osg::GraphicsContext::getWindowingSystemInterface();
92#if defined(HAVE_QT)
94 // use the correct WSI for OpenSceneGraph >= 3.6
95 wsi = osg::GraphicsContext::getWindowingSystemInterface("FlightGearQt5");
96 }
97#endif
98
99 defaultTraits = new osg::GraphicsContext::Traits;
100
101 auto traits = defaultTraits.get();
102 traits->readDISPLAY();
103 traits->setUndefinedScreenDetailsToDefaultScreen();
104 traits->vsync = fgGetBool("/sim/rendering/vsync-enable", traits->vsync);
105 traits->doubleBuffer = true;
106 traits->mipMapGeneration = true;
107 // Request a stencil buffer because paths on the Canvas desktop require it
108 traits->stencil = 8;
109
110 // TODO: Should be configurable by the Compositor on a per-window basis
111 // traits->red = traits->green = traits->blue = cbits;
112 // traits->depth = zbits;
113 // traits->sampleBuffers = fgGetInt("/sim/rendering/multi-sample-buffers", traits->sampleBuffers);
114 // traits->samples = fgGetInt("/sim/rendering/multi-samples", traits->samples);
115
116 const bool wantFullscreen = fgGetBool("/sim/startup/fullscreen");
117 unsigned screenwidth = 0;
118 unsigned screenheight = 0;
119 // this is a deprecated method, should be screen-aware.
120 wsi->getScreenResolution(*traits, screenwidth, screenheight);
121
122 // handle fullscreen manually
123 traits->windowDecoration = !wantFullscreen;
124 if (!traits->windowDecoration) {
125 // fullscreen
126 traits->supportsResize = false;
127 traits->width = screenwidth;
128 traits->height = screenheight;
129 SG_LOG(SG_VIEW,SG_DEBUG,"Using full screen size for window: " << screenwidth << " x " << screenheight);
130 } else {
131 // window
132 int w = fgGetInt("/sim/startup/xsize");
133 int h = fgGetInt("/sim/startup/ysize");
134 traits->supportsResize = true;
135 traits->width = w;
136 traits->height = h;
137 if ((w>0)&&(h>0))
138 {
139 traits->x = ((unsigned)w>screenwidth) ? 0 : (screenwidth-w)/3;
140 traits->y = ((unsigned)h>screenheight) ? 0 : (screenheight-h)/3;
141 }
142 SG_LOG(SG_VIEW,SG_DEBUG,"Using initial window size: " << w << " x " << h);
143 }
144}
145
146void WindowBuilder::setFullscreenTraits(const SGPropertyNode* winNode, GraphicsContext::Traits* traits)
147{
148 const SGPropertyNode* orrNode = winNode->getNode("overrideRedirect");
149 bool overrideRedirect = orrNode && orrNode->getBoolValue();
150 traits->overrideRedirect = overrideRedirect;
151
152 traits->windowDecoration = false;
153
154 unsigned int width = 0;
155 unsigned int height = 0;
156 auto wsi = osg::GraphicsContext::getWindowingSystemInterface();
157 wsi->getScreenResolution(*traits, width, height);
158 traits->width = width;
159 traits->height = height;
160 traits->supportsResize = false;
161 traits->x = 0;
162 traits->y = 0;
163}
164
165bool WindowBuilder::setWindowedTraits(const SGPropertyNode* winNode, GraphicsContext::Traits* traits)
166{
167 bool customTraits = false;
168 int resizable = 0;
169 const SGPropertyNode* fullscreenNode = winNode->getNode("fullscreen");
170 if (fullscreenNode && !fullscreenNode->getBoolValue())
171 {
172 traits->windowDecoration = true;
173 resizable = 1;
174 }
175 resizable |= setFromProperty(traits->windowDecoration, winNode, "decoration");
176 resizable |= setFromProperty(traits->width, winNode, "width");
177 resizable |= setFromProperty(traits->height, winNode, "height");
178 if (resizable) {
179 traits->supportsResize = true;
180 customTraits = true;
181 }
182
183 return customTraits;
184}
185
186void WindowBuilder::setMacPoseAsStandaloneApp(GraphicsContext::Traits* traits) const
187{
188#if defined(SG_MAC)
189 // this logic is unecessary if using a Qt window, since everything
190 // plays together nicely
191 int flags = osgViewer::GraphicsWindowCocoa::WindowData::CheckForEvents;
192
193 // avoid both QApplication and OSG::CocoaViewer doing single-application
194 // init (Apple menu, making front process, etc)
196 flags |= osgViewer::GraphicsWindowCocoa::WindowData::PoseAsStandaloneApp;
197 }
198 traits->inheritedWindowData = new osgViewer::GraphicsWindowCocoa::WindowData(flags);
199#endif
200}
201
202GraphicsWindow* WindowBuilder::buildWindow(const SGPropertyNode* winNode)
203{
205
206 string windowName;
207 if (winNode->hasChild("window-name")) {
208 windowName = winNode->getStringValue("window-name");
209 } else if (winNode->hasChild("name")) {
210 windowName = winNode->getStringValue("name");
211 } else {
212 SG_LOG(SG_VIEW, SG_WARN, "WindowBuilder::buildWindow: Window needs a name");
213 return nullptr;
214 }
215
216 // look for an existing window and return that
217 GraphicsWindow* result = wsa->findWindow(windowName);
218 if (result) {
219 return result;
220 }
221
222 // There is no existing window with this name, so create it from scratch.
223 // Copy the default traits and modify them according to the window props.
224 ref_ptr<GraphicsContext::Traits> traits =
225 new GraphicsContext::Traits(*defaultTraits);
226
227 // Attempt to share context with the window that was created first
228 if (!wsa->windows.empty())
229 traits->sharedContext = wsa->windows.front()->gc;
230
231 [[maybe_unused]] int traitsSet = 0;
232 traitsSet |= setFromProperty(traits->hostName, winNode, "host-name");
233 traitsSet |= setFromProperty(traits->displayNum, winNode, "display");
234 traitsSet |= setFromProperty(traits->screenNum, winNode, "screen");
235
236 const SGPropertyNode* fullscreenNode = winNode->getNode("fullscreen");
237 if (fullscreenNode && fullscreenNode->getBoolValue()) {
238 setFullscreenTraits(winNode, traits);
239 traitsSet = 1;
240 } else {
241 traitsSet |= setWindowedTraits(winNode, traits);
242 }
243 traitsSet |= setFromProperty(traits->x, winNode, "x");
244 traitsSet |= setFromProperty(traits->y, winNode, "y");
245
246 // The window title matches the internal window name by default
247 traits->windowName = windowName;
248 traitsSet |= setFromProperty(traits->windowName, winNode, "title");
249
251
252 // Create a graphics context for this window.
253 // This is where we choose which OpenGL version to use.
254 // We also set the #version string for shaders in the display settings based
255 // on the chosen OpenGL version.
256 auto display_settings = osg::DisplaySettings::instance();
257 GraphicsContext* gc = nullptr;
258
259#if !defined(SG_MAC)
260 // Attempt to create an OpenGL 4.3 core profile context first if we are not
261 // on MacOS (max version there is 4.1). We can optionally take advantage of
262 // 4.3 features like compute shaders.
263 display_settings->setValue("FG_GLSL_VERSION", "#version 430 core");
264 gc = attemptToCreateGraphicsContext(traits, "4.3", 0x1);
265#endif
266
267 if (!gc) {
268 // 4.3 is unsupported, so try with 4.1. This version is required, i.e.
269 // we crash if we can't successfully create an OpenGL context.
270 display_settings->setValue("FG_GLSL_VERSION", "#version 410 core");
271 gc = attemptToCreateGraphicsContext(traits, "4.1", 0x1);
272 if (!gc) {
274 "Unable to create OpenGL 4.1 core profile context",
275 "FlightGear was unable to create a window supporting 3D rendering. "
276 "This is normally due to outdated graphics drivers, please check if updates are available. ",
277 "Depending on your OS and graphics chipset, updates might come from AMD, nVidia or Intel.");
278 return nullptr; // unreachable anyway
279 }
280 }
281
282 // Cache the newly created window using the internal name
283 // (because traits->windowName can be custom).
284 result = WindowSystemAdapter::getWSA()->registerWindow(gc, windowName);
285
286 return result;
287}
288
293
294} // of namespace flightgear
void fgqt_setPoseAsStandaloneApp(bool b)
A window with a graphics context and an integer ID.
bool setWindowedTraits(const SGPropertyNode *winNode, osg::GraphicsContext::Traits *traits)
osg::ref_ptr< osg::GraphicsContext::Traits > defaultTraits
GraphicsWindow * buildWindow(const SGPropertyNode *winNode)
Create a window from its property node description.
void setMacPoseAsStandaloneApp(osg::GraphicsContext::Traits *traits) const
void setFullscreenTraits(const SGPropertyNode *winNode, osg::GraphicsContext::Traits *traits)
static osg::ref_ptr< WindowBuilder > windowBuilder
static void initWindowBuilder()
Initialize the singleton window builder.
static void setPoseAsStandaloneApp(bool b)
Adapter from windows system / graphics context management API to functions used by flightgear.
GraphicsWindow * findWindow(const std::string &name) const
Find a window by name.
WindowVector windows
Vector of all the registered windows.
static WindowSystemAdapter * getWSA()
Get the global WindowSystemAdapter.
GraphicsWindow * registerWindow(osg::GraphicsContext *gc, const std::string &windowName)
Register a window, assigning it an ID.
const char * name
int fgGetInt(const char *name, int defaultValue)
Get an int value for a property.
Definition fg_props.cxx:532
FlightPlan.hxx - defines a full flight-plan object, including departure, cruise, arrival information ...
Definition Addon.cxx:53
void fatalMessageBoxThenExit(const std::string &caption, const std::string &msg, const std::string &moreText, int exitStatus, bool reportToSentry)
Definition AIBase.hxx:25
bool fgGetBool(char const *name, bool def)
Get a bool value for a property.
Definition proptest.cpp:25