168 lines
		
	
	
	
		
			4.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			168 lines
		
	
	
	
		
			4.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// This file is part of Desktop App Toolkit,
 | 
						|
// a set of libraries for developing nice desktop applications.
 | 
						|
//
 | 
						|
// For license and copyright information please follow this link:
 | 
						|
// https://github.com/desktop-app/legal/blob/master/LEGAL
 | 
						|
//
 | 
						|
#include "ui/gl/gl_surface.h"
 | 
						|
 | 
						|
#include "ui/rp_widget.h"
 | 
						|
#include "ui/painter.h"
 | 
						|
 | 
						|
#include <QtGui/QtEvents>
 | 
						|
#include <QtGui/QOpenGLContext>
 | 
						|
#include <QtGui/QWindow>
 | 
						|
#include <QtGui/QPaintEngine>
 | 
						|
#include <QtWidgets/QOpenGLWidget>
 | 
						|
 | 
						|
namespace Ui::GL {
 | 
						|
namespace {
 | 
						|
 | 
						|
struct SurfaceTraits : RpWidgetDefaultTraits {
 | 
						|
	static constexpr bool kSetZeroGeometry = false;
 | 
						|
};
 | 
						|
 | 
						|
class SurfaceOpenGL final
 | 
						|
	: public RpWidgetBase<QOpenGLWidget, SurfaceTraits> {
 | 
						|
public:
 | 
						|
	SurfaceOpenGL(QWidget *parent, std::unique_ptr<Renderer> renderer);
 | 
						|
	~SurfaceOpenGL();
 | 
						|
 | 
						|
private:
 | 
						|
	void initializeGL() override;
 | 
						|
	void resizeGL(int w, int h) override;
 | 
						|
	void paintEvent(QPaintEvent *e) override;
 | 
						|
	void callDeInit();
 | 
						|
 | 
						|
	const std::unique_ptr<Renderer> _renderer;
 | 
						|
	QMetaObject::Connection _connection;
 | 
						|
 | 
						|
};
 | 
						|
 | 
						|
class SurfaceRaster final : public RpWidgetBase<QWidget, SurfaceTraits> {
 | 
						|
public:
 | 
						|
	SurfaceRaster(QWidget *parent, std::unique_ptr<Renderer> renderer);
 | 
						|
 | 
						|
private:
 | 
						|
	void paintEvent(QPaintEvent *e) override;
 | 
						|
 | 
						|
	const std::unique_ptr<Renderer> _renderer;
 | 
						|
 | 
						|
};
 | 
						|
 | 
						|
SurfaceOpenGL::SurfaceOpenGL(
 | 
						|
	QWidget *parent,
 | 
						|
	std::unique_ptr<Renderer> renderer)
 | 
						|
: RpWidgetBase<QOpenGLWidget, SurfaceTraits>(parent)
 | 
						|
, _renderer(std::move(renderer)) {
 | 
						|
}
 | 
						|
 | 
						|
SurfaceOpenGL::~SurfaceOpenGL() {
 | 
						|
	callDeInit();
 | 
						|
}
 | 
						|
 | 
						|
void SurfaceOpenGL::initializeGL() {
 | 
						|
	Expects(window()->windowHandle() != nullptr);
 | 
						|
 | 
						|
	if (_connection) {
 | 
						|
		QObject::disconnect(base::take(_connection));
 | 
						|
	}
 | 
						|
	const auto context = this->context();
 | 
						|
	_connection = QObject::connect(
 | 
						|
		context,
 | 
						|
		&QOpenGLContext::aboutToBeDestroyed,
 | 
						|
		[=] { callDeInit(); });
 | 
						|
	_renderer->init(this, *context->functions());
 | 
						|
}
 | 
						|
 | 
						|
void SurfaceOpenGL::resizeGL(int w, int h) {
 | 
						|
	_renderer->resize(this, *context()->functions(), w, h);
 | 
						|
}
 | 
						|
 | 
						|
void SurfaceOpenGL::paintEvent(QPaintEvent *e) {
 | 
						|
	if (!updatesEnabled() || size().isEmpty() || !isValid()) {
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	auto redirectOffset = QPoint();
 | 
						|
	const auto rpd = redirected(&redirectOffset);
 | 
						|
	const auto device = rpd ? rpd : static_cast<QPaintDevice*>(this);
 | 
						|
	const auto engine = device->paintEngine();
 | 
						|
	if (!engine) {
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	engine->begin(device);
 | 
						|
	const auto f = context()->functions();
 | 
						|
	if (const auto bg = _renderer->clearColor()) {
 | 
						|
		f->glClearColor(bg->redF(), bg->greenF(), bg->blueF(), bg->alphaF());
 | 
						|
		f->glClear(GL_COLOR_BUFFER_BIT);
 | 
						|
	}
 | 
						|
	f->glDisable(GL_BLEND);
 | 
						|
	f->glViewport(0, 0, device->width(), device->height());
 | 
						|
	_renderer->paint(this, *f);
 | 
						|
	engine->end();
 | 
						|
}
 | 
						|
 | 
						|
void SurfaceOpenGL::callDeInit() {
 | 
						|
	if (!_connection) {
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	QObject::disconnect(base::take(_connection));
 | 
						|
	const auto surface = window()->windowHandle();
 | 
						|
	Assert(surface != nullptr);
 | 
						|
	const auto context = this->context();
 | 
						|
	context->makeCurrent(surface);
 | 
						|
	_renderer->deinit(this, *context->functions());
 | 
						|
}
 | 
						|
 | 
						|
SurfaceRaster::SurfaceRaster(
 | 
						|
	QWidget *parent,
 | 
						|
	std::unique_ptr<Renderer> renderer)
 | 
						|
: RpWidgetBase<QWidget, SurfaceTraits>(parent)
 | 
						|
, _renderer(std::move(renderer)) {
 | 
						|
}
 | 
						|
 | 
						|
void SurfaceRaster::paintEvent(QPaintEvent *e) {
 | 
						|
	_renderer->paintFallback(Painter(this), e->region(), Backend::Raster);
 | 
						|
}
 | 
						|
 | 
						|
} // namespace
 | 
						|
 | 
						|
void Renderer::paint(
 | 
						|
		not_null<QOpenGLWidget*> widget,
 | 
						|
		QOpenGLFunctions &f) {
 | 
						|
	paintFallback(Painter(widget.get()), widget->rect(), Backend::OpenGL);
 | 
						|
}
 | 
						|
 | 
						|
std::unique_ptr<RpWidgetWrap> CreateSurface(
 | 
						|
		Fn<ChosenRenderer(Capabilities)> chooseRenderer) {
 | 
						|
	auto chosen = chooseRenderer(CheckCapabilities(nullptr));
 | 
						|
	switch (chosen.backend) {
 | 
						|
	case Backend::OpenGL:
 | 
						|
		return std::make_unique<SurfaceOpenGL>(
 | 
						|
			nullptr,
 | 
						|
			std::move(chosen.renderer));
 | 
						|
	case Backend::Raster:
 | 
						|
		return std::make_unique<SurfaceRaster>(
 | 
						|
			nullptr,
 | 
						|
			std::move(chosen.renderer));
 | 
						|
	}
 | 
						|
	Unexpected("Backend value in Ui::GL::CreateSurface.");
 | 
						|
}
 | 
						|
 | 
						|
std::unique_ptr<RpWidgetWrap> CreateSurface(
 | 
						|
		QWidget *parent,
 | 
						|
		ChosenRenderer chosen) {
 | 
						|
	switch (chosen.backend) {
 | 
						|
	case Backend::OpenGL:
 | 
						|
		return std::make_unique<SurfaceOpenGL>(
 | 
						|
			parent,
 | 
						|
			std::move(chosen.renderer));
 | 
						|
	case Backend::Raster:
 | 
						|
		return std::make_unique<SurfaceRaster>(
 | 
						|
			parent,
 | 
						|
			std::move(chosen.renderer));
 | 
						|
	}
 | 
						|
	Unexpected("Backend value in Ui::GL::CreateSurface.");
 | 
						|
}
 | 
						|
 | 
						|
} // namespace Ui::GL
 |