GTK: remove GlWidget, use standard Gtk::GLArea.
This removes a large number of hacks from the codebase, speeds up the rendering, and removes tearing when dragging entities.pull/106/head
parent
7dbbd75969
commit
6bb73a162c
|
@ -104,8 +104,6 @@ void SolveSpace::ScheduleLater() {
|
||||||
|
|
||||||
/* OpenGL view */
|
/* OpenGL view */
|
||||||
|
|
||||||
const bool SolveSpace::FLIP_FRAMEBUFFER = false;
|
|
||||||
|
|
||||||
@interface GLViewWithEditor : NSView
|
@interface GLViewWithEditor : NSView
|
||||||
- (void)drawGL;
|
- (void)drawGL;
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <giomm/file.h>
|
#include <giomm/file.h>
|
||||||
#include <gdkmm/cursor.h>
|
#include <gdkmm/cursor.h>
|
||||||
#include <gtkmm/drawingarea.h>
|
#include <gtkmm/drawingarea.h>
|
||||||
|
#include <gtkmm/glarea.h>
|
||||||
#include <gtkmm/scrollbar.h>
|
#include <gtkmm/scrollbar.h>
|
||||||
#include <gtkmm/entry.h>
|
#include <gtkmm/entry.h>
|
||||||
#include <gtkmm/eventbox.h>
|
#include <gtkmm/eventbox.h>
|
||||||
|
@ -33,7 +34,6 @@
|
||||||
#include <gtkmm/radiobuttongroup.h>
|
#include <gtkmm/radiobuttongroup.h>
|
||||||
#include <gtkmm/menu.h>
|
#include <gtkmm/menu.h>
|
||||||
#include <gtkmm/menubar.h>
|
#include <gtkmm/menubar.h>
|
||||||
#include <gtkmm/scrolledwindow.h>
|
|
||||||
#include <gtkmm/filechooserdialog.h>
|
#include <gtkmm/filechooserdialog.h>
|
||||||
#include <gtkmm/messagedialog.h>
|
#include <gtkmm/messagedialog.h>
|
||||||
#include <gtkmm/main.h>
|
#include <gtkmm/main.h>
|
||||||
|
@ -213,121 +213,6 @@ void ScheduleLater() {
|
||||||
Glib::signal_idle().connect(&LaterCallback);
|
Glib::signal_idle().connect(&LaterCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* GL wrapper */
|
|
||||||
|
|
||||||
const bool FLIP_FRAMEBUFFER = true;
|
|
||||||
|
|
||||||
class GlWidget : public Gtk::DrawingArea {
|
|
||||||
public:
|
|
||||||
GlWidget() : _offscreen() {
|
|
||||||
_xdisplay = gdk_x11_get_default_xdisplay();
|
|
||||||
|
|
||||||
int glxmajor, glxminor;
|
|
||||||
ssassert(glXQueryVersion(_xdisplay, &glxmajor, &glxminor),
|
|
||||||
"Expected OpenGL to be available");
|
|
||||||
|
|
||||||
ssassert(glxmajor > 1 || (glxmajor == 1 && glxminor >= 3),
|
|
||||||
"Expected GLX >= 1.3");
|
|
||||||
|
|
||||||
static int fbconfig_attrs[] = {
|
|
||||||
GLX_RENDER_TYPE, GLX_RGBA_BIT,
|
|
||||||
GLX_RED_SIZE, 8,
|
|
||||||
GLX_GREEN_SIZE, 8,
|
|
||||||
GLX_BLUE_SIZE, 8,
|
|
||||||
GLX_DEPTH_SIZE, 24,
|
|
||||||
None
|
|
||||||
};
|
|
||||||
int fbconfig_num = 0;
|
|
||||||
GLXFBConfig *fbconfigs = glXChooseFBConfig(_xdisplay, DefaultScreen(_xdisplay),
|
|
||||||
fbconfig_attrs, &fbconfig_num);
|
|
||||||
ssassert(fbconfigs && fbconfig_num > 0,
|
|
||||||
"Expected an available framebuffer configuration");
|
|
||||||
|
|
||||||
/* prefer FBConfigs with depth of 32;
|
|
||||||
* Mesa software rasterizer explodes with a BadMatch without this;
|
|
||||||
* without this, Intel on Mesa flickers horribly for some reason.
|
|
||||||
this does not seem to affect other rasterizers (ie NVidia).
|
|
||||||
|
|
||||||
see this Mesa bug:
|
|
||||||
http://lists.freedesktop.org/archives/mesa-dev/2015-January/074693.html */
|
|
||||||
GLXFBConfig fbconfig = fbconfigs[0];
|
|
||||||
for(int i = 0; i < fbconfig_num; i++) {
|
|
||||||
XVisualInfo *visual_info = glXGetVisualFromFBConfig(_xdisplay, fbconfigs[i]);
|
|
||||||
/* some GL visuals, notably on Chromium GL, do not have an associated
|
|
||||||
X visual; this is not an obstacle as we always render offscreen. */
|
|
||||||
if(!visual_info) continue;
|
|
||||||
int depth = visual_info->depth;
|
|
||||||
XFree(visual_info);
|
|
||||||
|
|
||||||
if(depth == 32) {
|
|
||||||
fbconfig = fbconfigs[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_glcontext = glXCreateNewContext(_xdisplay,
|
|
||||||
fbconfig, GLX_RGBA_TYPE, 0, True);
|
|
||||||
ssassert(_glcontext != NULL, "Cannot create an OpenGL context");
|
|
||||||
|
|
||||||
XFree(fbconfigs);
|
|
||||||
|
|
||||||
/* create a dummy X window to create a rendering context against.
|
|
||||||
we could use a Pbuffer, but some implementations (Chromium GL)
|
|
||||||
don't support these. we could use an existing window, but
|
|
||||||
some implementations (Chromium GL... do you see a pattern?)
|
|
||||||
do really strange things, i.e. draw a black rectangle on
|
|
||||||
the very front of the desktop if you do this. */
|
|
||||||
_xwindow = XCreateSimpleWindow(_xdisplay,
|
|
||||||
XRootWindow(_xdisplay, gdk_x11_get_default_screen()),
|
|
||||||
/*x*/ 0, /*y*/ 0, /*width*/ 1, /*height*/ 1,
|
|
||||||
/*border_width*/ 0, /*border*/ 0, /*background*/ 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
~GlWidget() {
|
|
||||||
glXMakeCurrent(_xdisplay, None, NULL);
|
|
||||||
|
|
||||||
XDestroyWindow(_xdisplay, _xwindow);
|
|
||||||
|
|
||||||
_offscreen.Clear();
|
|
||||||
|
|
||||||
glXDestroyContext(_xdisplay, _glcontext);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
/* Draw on a GLX framebuffer object, then read pixels out and draw them on
|
|
||||||
the Cairo context. Slower, but you get to overlay nice widgets. */
|
|
||||||
bool on_draw(const Cairo::RefPtr<Cairo::Context> &cr) override {
|
|
||||||
ssassert(glXMakeCurrent(_xdisplay, _xwindow, _glcontext),
|
|
||||||
"Cannot make OpenGL context current");
|
|
||||||
|
|
||||||
Gdk::Rectangle allocation = get_allocation();
|
|
||||||
bool success = _offscreen.Render(
|
|
||||||
allocation.get_width(), allocation.get_height(),
|
|
||||||
sigc::mem_fun(this, &GlWidget::on_gl_draw));
|
|
||||||
ssassert(success, "Cannot allocate offscreen rendering buffer");
|
|
||||||
|
|
||||||
Cairo::RefPtr<Cairo::ImageSurface> surface =
|
|
||||||
Cairo::ImageSurface::create(&_offscreen.data[0], Cairo::FORMAT_RGB24,
|
|
||||||
allocation.get_width(), allocation.get_height(),
|
|
||||||
allocation.get_width() * 4);
|
|
||||||
cr->set_source(surface, 0, 0);
|
|
||||||
cr->paint();
|
|
||||||
surface->finish();
|
|
||||||
|
|
||||||
glXSwapBuffers(_xdisplay, _xwindow);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void on_gl_draw() = 0;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Display *_xdisplay;
|
|
||||||
GLXContext _glcontext;
|
|
||||||
GlOffscreen _offscreen;
|
|
||||||
::Window _xwindow;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Editor overlay */
|
/* Editor overlay */
|
||||||
|
|
||||||
class EditorOverlay : public Gtk::Fixed {
|
class EditorOverlay : public Gtk::Fixed {
|
||||||
|
@ -441,26 +326,27 @@ double DeltaYOfScrollEvent(GdkEventScroll *event) {
|
||||||
return delta_y;
|
return delta_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
class GraphicsWidget : public GlWidget {
|
class GraphicsWidget : public Gtk::GLArea {
|
||||||
public:
|
public:
|
||||||
GraphicsWidget() {
|
GraphicsWidget() {
|
||||||
set_events(Gdk::POINTER_MOTION_MASK |
|
set_events(Gdk::POINTER_MOTION_MASK |
|
||||||
Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::BUTTON_MOTION_MASK |
|
Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::BUTTON_MOTION_MASK |
|
||||||
Gdk::SCROLL_MASK |
|
Gdk::SCROLL_MASK |
|
||||||
Gdk::LEAVE_NOTIFY_MASK);
|
Gdk::LEAVE_NOTIFY_MASK);
|
||||||
set_double_buffered(true);
|
set_has_alpha(true);
|
||||||
|
set_has_depth_buffer(true);
|
||||||
|
set_use_es(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool on_configure_event(GdkEventConfigure *event) override {
|
void on_resize(int width, int height) override {
|
||||||
_w = event->width;
|
_w = width;
|
||||||
_h = event->height;
|
_h = height;
|
||||||
|
|
||||||
return GlWidget::on_configure_event(event);;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_gl_draw() override {
|
bool on_render(const Glib::RefPtr<Gdk::GLContext> &context) override {
|
||||||
SS.GW.Paint();
|
SS.GW.Paint();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool on_motion_notify_event(GdkEventMotion *event) override {
|
bool on_motion_notify_event(GdkEventMotion *event) override {
|
||||||
|
@ -1196,11 +1082,14 @@ DialogChoice LocateImportedFileYesNoCancel(const std::string &filename,
|
||||||
|
|
||||||
/* Text window */
|
/* Text window */
|
||||||
|
|
||||||
class TextWidget : public GlWidget {
|
class TextWidget : public Gtk::GLArea {
|
||||||
public:
|
public:
|
||||||
TextWidget(Glib::RefPtr<Gtk::Adjustment> adjustment) : _adjustment(adjustment) {
|
TextWidget(Glib::RefPtr<Gtk::Adjustment> adjustment) : _adjustment(adjustment) {
|
||||||
set_events(Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::SCROLL_MASK |
|
set_events(Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::SCROLL_MASK |
|
||||||
Gdk::LEAVE_NOTIFY_MASK);
|
Gdk::LEAVE_NOTIFY_MASK);
|
||||||
|
set_has_alpha(true);
|
||||||
|
set_has_depth_buffer(true);
|
||||||
|
set_use_es(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_cursor_hand(bool is_hand) {
|
void set_cursor_hand(bool is_hand) {
|
||||||
|
@ -1212,8 +1101,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void on_gl_draw() override {
|
bool on_render(const Glib::RefPtr<Gdk::GLContext> &context) override {
|
||||||
SS.TW.Paint();
|
SS.TW.Paint();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool on_motion_notify_event(GdkEventMotion *event) override {
|
bool on_motion_notify_event(GdkEventMotion *event) override {
|
||||||
|
|
|
@ -93,8 +93,6 @@ void ScheduleLater() {
|
||||||
// Rendering
|
// Rendering
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
const bool FLIP_FRAMEBUFFER = false;
|
|
||||||
|
|
||||||
std::shared_ptr<ViewportCanvas> CreateRenderer() {
|
std::shared_ptr<ViewportCanvas> CreateRenderer() {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -757,8 +757,6 @@ void SolveSpace::ShowTextWindow(bool visible)
|
||||||
ShowWindow(TextWnd, visible ? SW_SHOWNOACTIVATE : SW_HIDE);
|
ShowWindow(TextWnd, visible ? SW_SHOWNOACTIVATE : SW_HIDE);
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool SolveSpace::FLIP_FRAMEBUFFER = false;
|
|
||||||
|
|
||||||
#if HAVE_OPENGL == 2
|
#if HAVE_OPENGL == 2
|
||||||
static void CreateGlContext(HWND hwnd, EGLDisplay *eglDisplay, EGLSurface *eglSurface,
|
static void CreateGlContext(HWND hwnd, EGLDisplay *eglDisplay, EGLSurface *eglSurface,
|
||||||
EGLContext *eglContext) {
|
EGLContext *eglContext) {
|
||||||
|
|
|
@ -172,7 +172,7 @@ public:
|
||||||
// An interface for view-dependent visualization.
|
// An interface for view-dependent visualization.
|
||||||
class ViewportCanvas : public Canvas {
|
class ViewportCanvas : public Canvas {
|
||||||
public:
|
public:
|
||||||
virtual void SetCamera(const Camera &camera, bool filp = FLIP_FRAMEBUFFER) = 0;
|
virtual void SetCamera(const Camera &camera) = 0;
|
||||||
virtual void SetLighting(const Lighting &lighting) = 0;
|
virtual void SetLighting(const Lighting &lighting) = 0;
|
||||||
|
|
||||||
virtual void NewFrame() = 0;
|
virtual void NewFrame() = 0;
|
||||||
|
|
|
@ -215,8 +215,8 @@ public:
|
||||||
void DoPoint(Vector p, double radius);
|
void DoPoint(Vector p, double radius);
|
||||||
void DoStippledLine(const Vector &a, const Vector &b, hStroke hcs, double phase = 0.0);
|
void DoStippledLine(const Vector &a, const Vector &b, hStroke hcs, double phase = 0.0);
|
||||||
|
|
||||||
void UpdateProjection(bool flip = FLIP_FRAMEBUFFER);
|
void UpdateProjection();
|
||||||
void SetCamera(const Camera &camera, bool filp = FLIP_FRAMEBUFFER) override;
|
void SetCamera(const Camera &camera) override;
|
||||||
void SetLighting(const Lighting &lighting) override;
|
void SetLighting(const Lighting &lighting) override;
|
||||||
|
|
||||||
void NewFrame() override;
|
void NewFrame() override;
|
||||||
|
@ -702,7 +702,7 @@ void OpenGl1Renderer::InvalidatePixmap(std::shared_ptr<const Pixmap> pm) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl1Renderer::UpdateProjection(bool flip) {
|
void OpenGl1Renderer::UpdateProjection() {
|
||||||
UnSelectPrimitive();
|
UnSelectPrimitive();
|
||||||
|
|
||||||
glViewport(0, 0, camera.width, camera.height);
|
glViewport(0, 0, camera.width, camera.height);
|
||||||
|
@ -717,17 +717,12 @@ void OpenGl1Renderer::UpdateProjection(bool flip) {
|
||||||
double mat[16];
|
double mat[16];
|
||||||
// Last thing before display is to apply the perspective
|
// Last thing before display is to apply the perspective
|
||||||
double clp = camera.tangent * camera.scale;
|
double clp = camera.tangent * camera.scale;
|
||||||
double sy = flip ? -1.0 : 1.0;
|
|
||||||
MakeMatrix(mat, 1, 0, 0, 0,
|
MakeMatrix(mat, 1, 0, 0, 0,
|
||||||
0, sy, 0, 0,
|
0, 1, 0, 0,
|
||||||
0, 0, 1, 0,
|
0, 0, 1, 0,
|
||||||
0, 0, clp, 1);
|
0, 0, clp, 1);
|
||||||
glMultMatrixd(mat);
|
glMultMatrixd(mat);
|
||||||
|
|
||||||
// If we flip the framebuffer, then we also flip the handedness
|
|
||||||
// of the coordinate system, and so the face winding order.
|
|
||||||
glFrontFace(flip ? GL_CW : GL_CCW);
|
|
||||||
|
|
||||||
// Before that, we apply the rotation
|
// Before that, we apply the rotation
|
||||||
Vector projRight = camera.projRight,
|
Vector projRight = camera.projRight,
|
||||||
projUp = camera.projUp,
|
projUp = camera.projUp,
|
||||||
|
@ -829,9 +824,9 @@ void OpenGl1Renderer::GetIdent(const char **vendor, const char **renderer, const
|
||||||
*version = (const char *)glGetString(GL_VERSION);
|
*version = (const char *)glGetString(GL_VERSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl1Renderer::SetCamera(const Camera &c, bool flip) {
|
void OpenGl1Renderer::SetCamera(const Camera &c) {
|
||||||
camera = c;
|
camera = c;
|
||||||
UpdateProjection(flip);
|
UpdateProjection();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl1Renderer::SetLighting(const Lighting &l) {
|
void OpenGl1Renderer::SetLighting(const Lighting &l) {
|
||||||
|
|
|
@ -129,8 +129,8 @@ public:
|
||||||
void DoPoint(Vector p, hStroke hs);
|
void DoPoint(Vector p, hStroke hs);
|
||||||
void DoStippledLine(const Vector &a, const Vector &b, hStroke hcs);
|
void DoStippledLine(const Vector &a, const Vector &b, hStroke hcs);
|
||||||
|
|
||||||
void UpdateProjection(bool flip = FLIP_FRAMEBUFFER);
|
void UpdateProjection();
|
||||||
void SetCamera(const Camera &c, bool flip) override;
|
void SetCamera(const Camera &c) override;
|
||||||
void SetLighting(const Lighting &l) override;
|
void SetLighting(const Lighting &l) override;
|
||||||
|
|
||||||
void NewFrame() override;
|
void NewFrame() override;
|
||||||
|
@ -528,7 +528,7 @@ void OpenGl2Renderer::DrawPixmap(std::shared_ptr<const Pixmap> pm,
|
||||||
mli->mesh.AddPixmap(o, u, v, ta, tb);
|
mli->mesh.AddPixmap(o, u, v, ta, tb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl2Renderer::UpdateProjection(bool flip) {
|
void OpenGl2Renderer::UpdateProjection() {
|
||||||
glViewport(0, 0, camera.width, camera.height);
|
glViewport(0, 0, camera.width, camera.height);
|
||||||
|
|
||||||
double mat1[16];
|
double mat1[16];
|
||||||
|
@ -547,18 +547,13 @@ void OpenGl2Renderer::UpdateProjection(bool flip) {
|
||||||
|
|
||||||
// Last thing before display is to apply the perspective
|
// Last thing before display is to apply the perspective
|
||||||
double clp = camera.tangent * camera.scale;
|
double clp = camera.tangent * camera.scale;
|
||||||
double fy = flip ? -1.0 : 1.0;
|
|
||||||
MakeMatrix(mat2,
|
MakeMatrix(mat2,
|
||||||
1, 0, 0, 0,
|
1, 0, 0, 0,
|
||||||
0, fy, 0, 0,
|
0, 1, 0, 0,
|
||||||
0, 0, 1, 0,
|
0, 0, 1, 0,
|
||||||
0, 0, clp, 1
|
0, 0, clp, 1
|
||||||
);
|
);
|
||||||
|
|
||||||
// If we flip the framebuffer, then we also flip the handedness
|
|
||||||
// of the coordinate system, and so the face winding order.
|
|
||||||
glFrontFace(flip ? GL_CW : GL_CCW);
|
|
||||||
|
|
||||||
double projection[16];
|
double projection[16];
|
||||||
MultMatrix(mat1, mat2, projection);
|
MultMatrix(mat1, mat2, projection);
|
||||||
|
|
||||||
|
@ -668,9 +663,9 @@ void OpenGl2Renderer::GetIdent(const char **vendor, const char **renderer, const
|
||||||
*version = (const char *)glGetString(GL_VERSION);
|
*version = (const char *)glGetString(GL_VERSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl2Renderer::SetCamera(const Camera &c, bool flip) {
|
void OpenGl2Renderer::SetCamera(const Camera &c) {
|
||||||
camera = c;
|
camera = c;
|
||||||
UpdateProjection(flip);
|
UpdateProjection();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl2Renderer::SetLighting(const Lighting &l) {
|
void OpenGl2Renderer::SetLighting(const Lighting &l) {
|
||||||
|
|
|
@ -149,8 +149,6 @@ enum class ContextCommand : uint32_t;
|
||||||
#define PATH_SEP "/"
|
#define PATH_SEP "/"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern const bool FLIP_FRAMEBUFFER;
|
|
||||||
|
|
||||||
bool PathEqual(const std::string &a, const std::string &b);
|
bool PathEqual(const std::string &a, const std::string &b);
|
||||||
std::string PathSepPlatformToUnix(const std::string &filename);
|
std::string PathSepPlatformToUnix(const std::string &filename);
|
||||||
std::string PathSepUnixToPlatform(const std::string &filename);
|
std::string PathSepUnixToPlatform(const std::string &filename);
|
||||||
|
|
|
@ -865,8 +865,12 @@ void TextWindow::Paint() {
|
||||||
camera.offset.x = -(double)camera.width / 2.0;
|
camera.offset.x = -(double)camera.width / 2.0;
|
||||||
camera.offset.y = -(double)camera.height / 2.0;
|
camera.offset.y = -(double)camera.height / 2.0;
|
||||||
|
|
||||||
|
Lighting lighting = {};
|
||||||
|
lighting.backgroundColor = RGBi(0, 0, 0);
|
||||||
|
|
||||||
canvas->NewFrame();
|
canvas->NewFrame();
|
||||||
canvas->SetCamera(camera);
|
canvas->SetCamera(camera);
|
||||||
|
canvas->SetLighting(lighting);
|
||||||
|
|
||||||
UiCanvas uiCanvas = {};
|
UiCanvas uiCanvas = {};
|
||||||
uiCanvas.canvas = canvas;
|
uiCanvas.canvas = canvas;
|
||||||
|
|
Loading…
Reference in New Issue