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 */
|
||||
|
||||
const bool SolveSpace::FLIP_FRAMEBUFFER = false;
|
||||
|
||||
@interface GLViewWithEditor : NSView
|
||||
- (void)drawGL;
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <giomm/file.h>
|
||||
#include <gdkmm/cursor.h>
|
||||
#include <gtkmm/drawingarea.h>
|
||||
#include <gtkmm/glarea.h>
|
||||
#include <gtkmm/scrollbar.h>
|
||||
#include <gtkmm/entry.h>
|
||||
#include <gtkmm/eventbox.h>
|
||||
|
@ -33,7 +34,6 @@
|
|||
#include <gtkmm/radiobuttongroup.h>
|
||||
#include <gtkmm/menu.h>
|
||||
#include <gtkmm/menubar.h>
|
||||
#include <gtkmm/scrolledwindow.h>
|
||||
#include <gtkmm/filechooserdialog.h>
|
||||
#include <gtkmm/messagedialog.h>
|
||||
#include <gtkmm/main.h>
|
||||
|
@ -213,121 +213,6 @@ void ScheduleLater() {
|
|||
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 */
|
||||
|
||||
class EditorOverlay : public Gtk::Fixed {
|
||||
|
@ -441,26 +326,27 @@ double DeltaYOfScrollEvent(GdkEventScroll *event) {
|
|||
return delta_y;
|
||||
}
|
||||
|
||||
class GraphicsWidget : public GlWidget {
|
||||
class GraphicsWidget : public Gtk::GLArea {
|
||||
public:
|
||||
GraphicsWidget() {
|
||||
set_events(Gdk::POINTER_MOTION_MASK |
|
||||
Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::BUTTON_MOTION_MASK |
|
||||
Gdk::SCROLL_MASK |
|
||||
Gdk::LEAVE_NOTIFY_MASK);
|
||||
set_double_buffered(true);
|
||||
set_has_alpha(true);
|
||||
set_has_depth_buffer(true);
|
||||
set_use_es(true);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool on_configure_event(GdkEventConfigure *event) override {
|
||||
_w = event->width;
|
||||
_h = event->height;
|
||||
|
||||
return GlWidget::on_configure_event(event);;
|
||||
void on_resize(int width, int height) override {
|
||||
_w = width;
|
||||
_h = height;
|
||||
}
|
||||
|
||||
void on_gl_draw() override {
|
||||
bool on_render(const Glib::RefPtr<Gdk::GLContext> &context) override {
|
||||
SS.GW.Paint();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool on_motion_notify_event(GdkEventMotion *event) override {
|
||||
|
@ -1196,11 +1082,14 @@ DialogChoice LocateImportedFileYesNoCancel(const std::string &filename,
|
|||
|
||||
/* Text window */
|
||||
|
||||
class TextWidget : public GlWidget {
|
||||
class TextWidget : public Gtk::GLArea {
|
||||
public:
|
||||
TextWidget(Glib::RefPtr<Gtk::Adjustment> adjustment) : _adjustment(adjustment) {
|
||||
set_events(Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::SCROLL_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) {
|
||||
|
@ -1212,8 +1101,9 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
void on_gl_draw() override {
|
||||
bool on_render(const Glib::RefPtr<Gdk::GLContext> &context) override {
|
||||
SS.TW.Paint();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool on_motion_notify_event(GdkEventMotion *event) override {
|
||||
|
|
|
@ -93,8 +93,6 @@ void ScheduleLater() {
|
|||
// Rendering
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const bool FLIP_FRAMEBUFFER = false;
|
||||
|
||||
std::shared_ptr<ViewportCanvas> CreateRenderer() {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -757,8 +757,6 @@ void SolveSpace::ShowTextWindow(bool visible)
|
|||
ShowWindow(TextWnd, visible ? SW_SHOWNOACTIVATE : SW_HIDE);
|
||||
}
|
||||
|
||||
const bool SolveSpace::FLIP_FRAMEBUFFER = false;
|
||||
|
||||
#if HAVE_OPENGL == 2
|
||||
static void CreateGlContext(HWND hwnd, EGLDisplay *eglDisplay, EGLSurface *eglSurface,
|
||||
EGLContext *eglContext) {
|
||||
|
|
|
@ -172,7 +172,7 @@ public:
|
|||
// An interface for view-dependent visualization.
|
||||
class ViewportCanvas : public Canvas {
|
||||
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 NewFrame() = 0;
|
||||
|
|
|
@ -215,8 +215,8 @@ public:
|
|||
void DoPoint(Vector p, double radius);
|
||||
void DoStippledLine(const Vector &a, const Vector &b, hStroke hcs, double phase = 0.0);
|
||||
|
||||
void UpdateProjection(bool flip = FLIP_FRAMEBUFFER);
|
||||
void SetCamera(const Camera &camera, bool filp = FLIP_FRAMEBUFFER) override;
|
||||
void UpdateProjection();
|
||||
void SetCamera(const Camera &camera) override;
|
||||
void SetLighting(const Lighting &lighting) 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();
|
||||
|
||||
glViewport(0, 0, camera.width, camera.height);
|
||||
|
@ -717,17 +717,12 @@ void OpenGl1Renderer::UpdateProjection(bool flip) {
|
|||
double mat[16];
|
||||
// Last thing before display is to apply the perspective
|
||||
double clp = camera.tangent * camera.scale;
|
||||
double sy = flip ? -1.0 : 1.0;
|
||||
MakeMatrix(mat, 1, 0, 0, 0,
|
||||
0, sy, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, clp, 1);
|
||||
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
|
||||
Vector projRight = camera.projRight,
|
||||
projUp = camera.projUp,
|
||||
|
@ -829,9 +824,9 @@ void OpenGl1Renderer::GetIdent(const char **vendor, const char **renderer, const
|
|||
*version = (const char *)glGetString(GL_VERSION);
|
||||
}
|
||||
|
||||
void OpenGl1Renderer::SetCamera(const Camera &c, bool flip) {
|
||||
void OpenGl1Renderer::SetCamera(const Camera &c) {
|
||||
camera = c;
|
||||
UpdateProjection(flip);
|
||||
UpdateProjection();
|
||||
}
|
||||
|
||||
void OpenGl1Renderer::SetLighting(const Lighting &l) {
|
||||
|
|
|
@ -129,8 +129,8 @@ public:
|
|||
void DoPoint(Vector p, hStroke hs);
|
||||
void DoStippledLine(const Vector &a, const Vector &b, hStroke hcs);
|
||||
|
||||
void UpdateProjection(bool flip = FLIP_FRAMEBUFFER);
|
||||
void SetCamera(const Camera &c, bool flip) override;
|
||||
void UpdateProjection();
|
||||
void SetCamera(const Camera &c) override;
|
||||
void SetLighting(const Lighting &l) 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);
|
||||
}
|
||||
|
||||
void OpenGl2Renderer::UpdateProjection(bool flip) {
|
||||
void OpenGl2Renderer::UpdateProjection() {
|
||||
glViewport(0, 0, camera.width, camera.height);
|
||||
|
||||
double mat1[16];
|
||||
|
@ -547,18 +547,13 @@ void OpenGl2Renderer::UpdateProjection(bool flip) {
|
|||
|
||||
// Last thing before display is to apply the perspective
|
||||
double clp = camera.tangent * camera.scale;
|
||||
double fy = flip ? -1.0 : 1.0;
|
||||
MakeMatrix(mat2,
|
||||
1, 0, 0, 0,
|
||||
0, fy, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
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];
|
||||
MultMatrix(mat1, mat2, projection);
|
||||
|
||||
|
@ -668,9 +663,9 @@ void OpenGl2Renderer::GetIdent(const char **vendor, const char **renderer, const
|
|||
*version = (const char *)glGetString(GL_VERSION);
|
||||
}
|
||||
|
||||
void OpenGl2Renderer::SetCamera(const Camera &c, bool flip) {
|
||||
void OpenGl2Renderer::SetCamera(const Camera &c) {
|
||||
camera = c;
|
||||
UpdateProjection(flip);
|
||||
UpdateProjection();
|
||||
}
|
||||
|
||||
void OpenGl2Renderer::SetLighting(const Lighting &l) {
|
||||
|
|
|
@ -149,8 +149,6 @@ enum class ContextCommand : uint32_t;
|
|||
#define PATH_SEP "/"
|
||||
#endif
|
||||
|
||||
extern const bool FLIP_FRAMEBUFFER;
|
||||
|
||||
bool PathEqual(const std::string &a, const std::string &b);
|
||||
std::string PathSepPlatformToUnix(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.y = -(double)camera.height / 2.0;
|
||||
|
||||
Lighting lighting = {};
|
||||
lighting.backgroundColor = RGBi(0, 0, 0);
|
||||
|
||||
canvas->NewFrame();
|
||||
canvas->SetCamera(camera);
|
||||
canvas->SetLighting(lighting);
|
||||
|
||||
UiCanvas uiCanvas = {};
|
||||
uiCanvas.canvas = canvas;
|
||||
|
|
Loading…
Reference in New Issue