1 /*
2  * Stellarium
3  * Copyright (C) 2007 Fabien Chereau
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335, USA.
18  */
19 
20 #ifndef STELMAINVIEW_HPP
21 #define STELMAINVIEW_HPP
22 
23 #include <QCoreApplication>
24 #include <QGraphicsView>
25 #include <QEventLoop>
26 #include <QOpenGLContext>
27 #include <QTimer>
28 #ifdef OPENGL_DEBUG_LOGGING
29 #include <QOpenGLDebugMessage>
30 #endif
31 #include "StelUtils.hpp"
32 
33 class StelGLWidget;
34 class StelGraphicsScene;
35 class QMoveEvent;
36 class QResizeEvent;
37 class StelGuiBase;
38 class QMoveEvent;
39 class QSettings;
40 
41 //! @class StelMainView
42 //! Reimplement a QGraphicsView for Stellarium.
43 //! It is the class creating the singleton GL Widget, the main StelApp instance as well as the main GUI.
44 class StelMainView : public QGraphicsView
45 {
46 	friend class StelGuiItem;
47 	friend class StelRootItem;
48 	friend class StelGraphicsScene;
49 	friend class NightModeGraphicsEffect;
50 	Q_OBJECT
51 	Q_PROPERTY(bool fullScreen                 READ isFullScreen                  WRITE setFullScreen                 NOTIFY fullScreenChanged)
52 	Q_PROPERTY(bool flagInvertScreenShotColors READ getFlagInvertScreenShotColors WRITE setFlagInvertScreenShotColors NOTIFY flagInvertScreenShotColorsChanged)
53 	Q_PROPERTY(bool flagOverwriteScreenshots   READ getFlagOverwriteScreenShots   WRITE setFlagOverwriteScreenShots   NOTIFY flagOverwriteScreenshotsChanged)
54 	Q_PROPERTY(bool flagUseCustomScreenshotSize READ getFlagUseCustomScreenshotSize WRITE setFlagUseCustomScreenshotSize NOTIFY flagUseCustomScreenshotSizeChanged)
55 	Q_PROPERTY(int  customScreenshotWidth      READ getCustomScreenshotWidth      WRITE setCustomScreenshotWidth      NOTIFY customScreenshotWidthChanged)
56 	Q_PROPERTY(int  customScreenshotHeight     READ getCustomScreenshotHeight     WRITE setCustomScreenshotHeight     NOTIFY customScreenshotHeightChanged)
57 	Q_PROPERTY(QString screenShotFormat        READ getScreenshotFormat           WRITE setScreenshotFormat           NOTIFY screenshotFormatChanged)
58 	Q_PROPERTY(bool flagCursorTimeout          READ getFlagCursorTimeout          WRITE setFlagCursorTimeout          NOTIFY flagCursorTimeoutChanged)
59 	Q_PROPERTY(double cursorTimeout            READ getCursorTimeout              WRITE setCursorTimeout              NOTIFY cursorTimeoutChanged)
60 	Q_PROPERTY(Vec3f skyBackgroundColor        READ getSkyBackgroundColor         WRITE setSkyBackgroundColor         NOTIFY skyBackgroundColorChanged)
61 
62 public:
63 	//! Contains some basic info about the OpenGL context used
64 	struct GLInfo
65 	{
66 		QString vendor;
67 		QString renderer;
68 		QOpenGLContext* mainContext;
69 		QOpenGLFunctions* functions;
70 	};
71 
72 	StelMainView(QSettings* settings);
73 	virtual ~StelMainView() Q_DECL_OVERRIDE;
74 
75 	//! Start the main initialization of Stellarium
76 	void init();
77 	void deinit();
78 
79 	//! Set the application title for the current language.
80 	//! This is useful for e.g. chinese.
81 	void initTitleI18n();
82 
83 	//! Get the StelMainView singleton instance.
getInstance()84 	static StelMainView& getInstance() {Q_ASSERT(singleton); return *singleton;}
85 
86 	//! Delete openGL textures (to call before the GLContext disappears)
87 	void deinitGL();
88 
89 	//! Return the parent gui widget, this should be used as parent to all
90 	//! the StelDialog instances.
getGuiWidget() const91 	QGraphicsWidget* getGuiWidget() const {return guiItem;}
92 	//! Return mouse position coordinates
93 	QPoint getMousePos() const;
94 
95 	//! Returns the main application OpenGL context,
96 	//! which should be used for all drawing Stellarium does
97 	//! @sa glContextMakeCurrent()
98 	//! @sa glContextDoneCurrent()
99 	QOpenGLContext* glContext() const;
100 	//! Make the main GL context (the one returned from glContext()) current
101 	//! on the main view surface
102 	void glContextMakeCurrent();
103 	//! Releases the main GL context
104 	void glContextDoneCurrent();
105 
106 	//! Returns the information about the GL context, this does not require the context to be active.
getGLInformation() const107 	GLInfo getGLInformation() const { return glInfo; }
108 public slots:
109 
110 	//! Set whether fullscreen is activated or not
111 	void setFullScreen(bool);
112 
113 	//! Return focus to the sky item.  To be used when we close a dialog.
114 	void focusSky();
115 
116 	///////////////////////////////////////////////////////////////////////////
117 	// Specific methods
118 	//! Save a screen shot.
119 	//! The format of the file, and hence the filename extension
120 	//! depends on the architecture and build type.
121 	//! @arg filePrefix changes the beginning of the file name
122 	//! @arg saveDir changes the directory where the screenshot is saved
123 	//! If saveDir is "" then StelFileMgr::getScreenshotDir() will be used
124 	//! @arg overwrite if true, @arg filePrefix is used as filename, and existing file will be overwritten.
125 	//! @note To set file type, use setScreenshotFormat() first.
126 	void saveScreenShot(const QString& filePrefix="stellarium-", const QString& saveDir="", const bool overwrite=false);
127 	//! @arg filetype is the preferred file type (ending) like "png", "jpg", "bmp" etc.
128 	//! The supported filetypes depend on the underlying Qt version.
129 	//! The most popular may be PNG, JPG/JPEG, BMP, TIF (LZW compressed), TIFF (uncompressed), WEBP,
130 	//! but as of Qt5.12, we also have ICO (for thumbnails), PBM (Portable Bitmap), PGM (Portable Graymap), PPM (Portable Pixmap),
131 	//! XBM (X Bitmap) and XPM (X Pixmap).
132 	void setScreenshotFormat(const QString filetype);
getScreenshotFormat() const133 	QString getScreenshotFormat() const {return screenShotFormat;}
134 
135 	//! Get whether colors are inverted when saving screenshot
getFlagInvertScreenShotColors() const136 	bool getFlagInvertScreenShotColors() const {return flagInvertScreenShotColors;}
137 	//! Set whether colors should be inverted when saving screenshot
setFlagInvertScreenShotColors(bool b)138 	void setFlagInvertScreenShotColors(bool b) {flagInvertScreenShotColors=b; emit flagInvertScreenShotColorsChanged(b);}
139 
140 	//! Get whether existing files are overwritten when saving screenshot
getFlagOverwriteScreenShots() const141 	bool getFlagOverwriteScreenShots() const {return flagOverwriteScreenshots;}
142 	//! Set whether existing files are overwritten when saving screenshot
setFlagOverwriteScreenShots(bool b)143 	void setFlagOverwriteScreenShots(bool b) {flagOverwriteScreenshots=b; emit flagOverwriteScreenshotsChanged(b);}
144 
145 	//! Get whether custom size should be used for screenshots
getFlagUseCustomScreenshotSize() const146 	bool getFlagUseCustomScreenshotSize() const {return flagUseCustomScreenshotSize;}
147 	//! Set whether custom size should be used for screenshots
setFlagUseCustomScreenshotSize(bool b)148 	void setFlagUseCustomScreenshotSize(bool b) {flagUseCustomScreenshotSize=b; emit flagUseCustomScreenshotSizeChanged(b);}
149 	//! Get custom screenshot width
getCustomScreenshotWidth() const150 	int getCustomScreenshotWidth() const {return customScreenshotWidth;}
151 	//! Set whether custom size should be used for screenshots
setCustomScreenshotWidth(int width)152 	void setCustomScreenshotWidth(int width) {customScreenshotWidth=width; emit customScreenshotWidthChanged(width);}
153 	//! Get custom screenshot height
getCustomScreenshotHeight() const154 	int getCustomScreenshotHeight() const {return customScreenshotHeight;}
155 	//! Set whether custom size should be used for screenshots
setCustomScreenshotHeight(int height)156 	void setCustomScreenshotHeight(int height) {customScreenshotHeight=height; emit customScreenshotHeightChanged(height);}
157 	//! Get screenshot magnification. This should be used by StarMgr, text drawing and other elements which may
158 	//! want to enlarge their output in screenshots to keep them visible.
getCustomScreenshotMagnification() const159 	float getCustomScreenshotMagnification() const {return customScreenshotMagnification;}
160 	//! Get the state of the mouse cursor timeout flag
getFlagCursorTimeout() const161 	bool getFlagCursorTimeout() const {return flagCursorTimeout;}
162 	//! Set the state of the mouse cursor timeout flag
163 	void setFlagCursorTimeout(bool b);
164 	//! Get the mouse cursor timeout in seconds
getCursorTimeout() const165 	double getCursorTimeout() const {return cursorTimeoutTimer->interval() / 1000.0;}
166 	//! Set the mouse cursor timeout in seconds
setCursorTimeout(double t)167 	void setCursorTimeout(double t) {cursorTimeoutTimer->setInterval(static_cast<int>(t * 1000)); emit cursorTimeoutChanged(t);}
168 
169 	//! Set the minimum frames per second. Usually this minimum will be switched to after there are no
170 	//! user events for some seconds to save power. However, if can be useful to set this to a high
171 	//! value to improve playing smoothness in scripts.
172 	//! @param m the new minimum fps setting.
setMinFps(float m)173 	void setMinFps(float m) {minfps=m;}
174 	//! Get the current minimum frames per second.
getMinFps() const175 	float getMinFps() const {return minfps;}
176 	//! Set the maximum frames per second.
177 	//! @param m the new maximum fps setting.
178 	//! @todo this setting currently does nothing
setMaxFps(float m)179 	void setMaxFps(float m) {maxfps = m;}
180 	//! Get the current maximum frames per second.
getMaxFps() const181 	float getMaxFps() const {return maxfps;}
182 
183 	//! Notify that an event was handled by the program and therefore the
184 	//! FPS should be maximized for a couple of seconds.
185 	void thereWasAnEvent();
186 
187 	//! Determines if we should render as fast as possible,
188 	//! or limit the FPS. This depends on the time the last user event
189 	//! happened.
190 	bool needsMaxFPS() const;
191 
192 	//! Set the sky background color. (Actually forwards to the StelRootItem.)  Everything else than black creates a work of art!
193 	void setSkyBackgroundColor(Vec3f color);
194 	//! Get the sky background color. (Actually retrieves from the StelRootItem.)  Everything else than black creates a work of art!
195 	Vec3f getSkyBackgroundColor() const;
196 
197 protected:
198 	//! Hack to determine current monitor pixel ratio
199 	//! @todo Find a better way to handle this
200 	virtual void moveEvent(QMoveEvent* event) Q_DECL_OVERRIDE;
201 	//! Handle window closed event, calling StelApp::quit()
202 	virtual void closeEvent(QCloseEvent* event) Q_DECL_OVERRIDE;
203 	//! Handle window resized events, and change the size of the underlying
204 	//! QGraphicsScene to be the same
205 	virtual void resizeEvent(QResizeEvent* event) Q_DECL_OVERRIDE;
206 	//! Wake up mouse cursor (if it was hidden)
207 	virtual void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
208 
209 	bool eventFilter(QObject *obj, QEvent *event) override;
210 signals:
211 	//! emitted when saveScreenShot is requested with saveScreenShot().
212 	//! doScreenshot() does the actual work (it has to do it in the main
213 	//! thread, where as saveScreenShot() might get called from another one.
214 	//!
215 	//! @remark FS: is threaded access here even a possibility anymore, or a remnant of older code?
216 	void screenshotRequested(void);
217 	void fullScreenChanged(bool b);
218 	//! Emitted when the "Reload shaders" action is perfomed
219 	//! Interested objects should subscribe to this signal and reload their shaders
220 	//! when this is emitted
221 	void reloadShadersRequested();
222 
223 	void updateIconsRequested();
224 	void flagInvertScreenShotColorsChanged(bool b);
225 	void flagOverwriteScreenshotsChanged(bool b);
226 	void flagUseCustomScreenshotSizeChanged(bool use);
227 	void customScreenshotWidthChanged(int width);
228 	void customScreenshotHeightChanged(int height);
229 	void screenshotFormatChanged(QString format);
230 
231 	void skyBackgroundColorChanged(Vec3f color);
232 
233 	void flagCursorTimeoutChanged(bool b);
234 	void cursorTimeoutChanged(double t);
235 
236 private slots:
237 	// Do the actual screenshot generation in the main thread with this method.
238 	void doScreenshot(void);
239 
240 	void fpsTimerUpdate();
241 	void hideCursor();
242 
243 #ifdef OPENGL_DEBUG_LOGGING
244 	void logGLMessage(const QOpenGLDebugMessage& debugMessage);
245 	void contextDestroyed();
246 #endif
247 	void updateNightModeProperty(bool b);
248 
249 	void reloadShaders();
250 
251 private:
252 	//! The graphics scene notifies us when a draw finished, so that we can queue the next one
253 	void drawEnded();
254 	//! Returns the desired OpenGL format settings,
255 	//! on desktop this corresponds to a GL 2.1 context,
256 	//! with 32bit RGBA buffer and 24/8 depth/stencil buffer
257 	QSurfaceFormat getDesiredGLFormat() const;
258 	//! provide extended OpenGL diagnostics in logfile.
259 	void dumpOpenGLdiagnostics() const;
260 	//! Startup diagnostics, providing test for various circumstances of bad OS/OpenGL driver combinations
261 	//! to provide feedback to the user about bad OpenGL drivers.
262 	void processOpenGLdiagnosticsAndWarnings(QSettings *conf, QOpenGLContext* context) const;
263 
264 	//! The StelMainView singleton
265 	static StelMainView* singleton;
266 
267 	GLInfo glInfo;
268 
269 	QSettings* configuration;
270 
271 	class StelRootItem* rootItem;
272 	QGraphicsWidget* guiItem;
273 	QGraphicsEffect* nightModeEffect;
274 
275 	//! The openGL viewport of the graphics scene
276 	//! Responsible for main GL setup, rendering is done in the scene background
277 	StelGLWidget* glWidget;
278 	//! Custom QGraphicsScene, this renders our scene background
279 	StelGraphicsScene* stelScene;
280 
281 	StelGuiBase* gui;
282 	class StelApp* stelApp;
283 
284 	bool updateQueued;
285 	bool flagInvertScreenShotColors;
286 	bool flagOverwriteScreenshots; //! if set to true, screenshot is named exactly screenShotPrefix.png and overwrites existing file
287 	bool flagUseCustomScreenshotSize; //! if true, the next 2 values are observed for screenshots.
288 	int customScreenshotWidth;            //! used when flagCustomResolutionScreenshots==true
289 	int customScreenshotHeight;           //! used when flagCustomResolutionScreenshots==true
290 	float customScreenshotMagnification;  //! tracks the magnification factor customScreenshotHeight/NormalWindowHeight
291 	QString screenShotPrefix;
292 	QString screenShotFormat; //! file type like "png" or "jpg".
293 	QString screenShotDir;
294 
295 	bool flagCursorTimeout;
296 	//! Timer that triggers with the cursor timeout.
297 	QTimer* cursorTimeoutTimer;
298 
299 	double lastEventTimeSec;
300 
301 	//! The minimum desired frame rate in frame per second.
302 	float minfps;
303 	//! The maximum desired frame rate in frame per second.
304 	float maxfps;
305 	QTimer* fpsTimer;
306 
307 #ifdef OPENGL_DEBUG_LOGGING
308 	QOpenGLDebugLogger* glLogger;
309 #endif
310 };
311 
312 
313 #endif // STELMAINVIEW_HPP
314