diff options
author | Arisotura <thetotalworm@gmail.com> | 2019-06-04 15:53:08 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-06-04 15:53:08 +0200 |
commit | 97f4b5f70b67ea5cc142fbd1f3982c36b915a5d9 (patch) | |
tree | bd3fb3325db3743eef00cf3ddffafdeb644370a9 /src/libui_sdl/libui | |
parent | f769d6e23f7635910e3f6659c6b55d8c6a8e96ff (diff) | |
parent | 3134c8fc66d1fbd5706930a3e3e64ce118406fe5 (diff) |
Merge branch 'master' into fast-forward-hotkey
Diffstat (limited to 'src/libui_sdl/libui')
-rw-r--r-- | src/libui_sdl/libui/ui.h | 25 | ||||
-rw-r--r-- | src/libui_sdl/libui/unix/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/libui_sdl/libui/unix/area.c | 116 | ||||
-rw-r--r-- | src/libui_sdl/libui/unix/draw.c | 4 | ||||
-rw-r--r-- | src/libui_sdl/libui/unix/gl.c | 246 | ||||
-rw-r--r-- | src/libui_sdl/libui/unix/main.c | 24 | ||||
-rw-r--r-- | src/libui_sdl/libui/unix/uipriv_unix.h | 8 | ||||
-rw-r--r-- | src/libui_sdl/libui/unix/window.c | 18 | ||||
-rw-r--r-- | src/libui_sdl/libui/windows/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/libui_sdl/libui/windows/area.cpp | 73 | ||||
-rw-r--r-- | src/libui_sdl/libui/windows/area.hpp | 11 | ||||
-rw-r--r-- | src/libui_sdl/libui/windows/areadraw.cpp | 27 | ||||
-rw-r--r-- | src/libui_sdl/libui/windows/areaevents.cpp | 2 | ||||
-rw-r--r-- | src/libui_sdl/libui/windows/areautil.cpp | 21 | ||||
-rw-r--r-- | src/libui_sdl/libui/windows/draw.cpp | 5 | ||||
-rw-r--r-- | src/libui_sdl/libui/windows/gl.cpp | 161 | ||||
-rw-r--r-- | src/libui_sdl/libui/windows/window.cpp | 15 |
17 files changed, 724 insertions, 35 deletions
diff --git a/src/libui_sdl/libui/ui.h b/src/libui_sdl/libui/ui.h index 5f40aff..e15c127 100644 --- a/src/libui_sdl/libui/ui.h +++ b/src/libui_sdl/libui/ui.h @@ -108,6 +108,8 @@ typedef struct uiWindow uiWindow; #define uiWindow(this) ((uiWindow *) (this)) _UI_EXTERN char *uiWindowTitle(uiWindow *w); _UI_EXTERN void uiWindowSetTitle(uiWindow *w, const char *title); +_UI_EXTERN void uiWindowPosition(uiWindow *w, int *x, int *y); +_UI_EXTERN void uiWindowSetPosition(uiWindow *w, int x, int y); _UI_EXTERN void uiWindowContentSize(uiWindow *w, int *width, int *height); _UI_EXTERN void uiWindowSetContentSize(uiWindow *w, int width, int height); _UI_EXTERN int uiWindowMinimized(uiWindow *w); @@ -326,6 +328,10 @@ _UI_ENUM(uiWindowResizeEdge) { // TODO way to bring up the system menu instead? }; +#define uiGLVersion(major, minor) ((major) | ((minor)<<16)) +#define uiGLVerMajor(ver) ((ver) & 0xFFFF) +#define uiGLVerMinor(ver) ((ver) >> 16) + #define uiArea(this) ((uiArea *) (this)) // TODO give a better name // TODO document the types of width and height @@ -342,6 +348,7 @@ _UI_EXTERN void uiAreaBeginUserWindowMove(uiArea *a); _UI_EXTERN void uiAreaBeginUserWindowResize(uiArea *a, uiWindowResizeEdge edge); _UI_EXTERN void uiAreaSetBackgroundColor(uiArea *a, int r, int g, int b); _UI_EXTERN uiArea *uiNewArea(uiAreaHandler *ah); +_UI_EXTERN uiArea *uiNewGLArea(uiAreaHandler *ah, const unsigned int* req_versions); _UI_EXTERN uiArea *uiNewScrollingArea(uiAreaHandler *ah, int width, int height); struct uiAreaDrawParams { @@ -509,7 +516,7 @@ _UI_EXTERN void uiDrawSave(uiDrawContext *c); _UI_EXTERN void uiDrawRestore(uiDrawContext *c); // bitmap API -_UI_EXTERN uiDrawBitmap* uiDrawNewBitmap(uiDrawContext* c, int width, int height); +_UI_EXTERN uiDrawBitmap* uiDrawNewBitmap(uiDrawContext* c, int width, int height, int alpha); _UI_EXTERN void uiDrawBitmapUpdate(uiDrawBitmap* bmp, const void* data); _UI_EXTERN void uiDrawBitmapDraw(uiDrawContext* c, uiDrawBitmap* bmp, uiRect* srcrect, uiRect* dstrect, int filter); _UI_EXTERN void uiDrawFreeBitmap(uiDrawBitmap* bmp); @@ -599,6 +606,22 @@ _UI_EXTERN void uiDrawTextLayoutSetColor(uiDrawTextLayout *layout, int startChar _UI_EXTERN void uiDrawText(uiDrawContext *c, double x, double y, uiDrawTextLayout *layout); + +// OpenGL support + +typedef struct uiGLContext uiGLContext; + +_UI_EXTERN uiGLContext *uiAreaGetGLContext(uiArea* a); +_UI_EXTERN void uiGLMakeContextCurrent(uiGLContext* ctx); +_UI_EXTERN void uiGLBegin(uiGLContext* ctx); +_UI_EXTERN void uiGLEnd(uiGLContext* ctx); +_UI_EXTERN unsigned int uiGLGetVersion(uiGLContext* ctx); +_UI_EXTERN void *uiGLGetProcAddress(const char* proc); +_UI_EXTERN int uiGLGetFramebuffer(uiGLContext* ctx); +_UI_EXTERN float uiGLGetFramebufferScale(uiGLContext* ctx); +_UI_EXTERN void uiGLSwapBuffers(uiGLContext* ctx); + + _UI_ENUM(uiModifiers) { uiModifierCtrl = 1 << 0, uiModifierAlt = 1 << 1, diff --git a/src/libui_sdl/libui/unix/CMakeLists.txt b/src/libui_sdl/libui/unix/CMakeLists.txt index 9300bcb..c69081e 100644 --- a/src/libui_sdl/libui/unix/CMakeLists.txt +++ b/src/libui_sdl/libui/unix/CMakeLists.txt @@ -43,6 +43,7 @@ list(APPEND _LIBUI_SOURCES unix/text.c unix/util.c unix/window.c + unix/gl.c ) set(_LIBUI_SOURCES ${_LIBUI_SOURCES} PARENT_SCOPE) @@ -62,6 +63,7 @@ macro(_handle_static) set(_oname libui-combined.o) add_custom_command( OUTPUT ${_oname} + DEPENDS ${_LIBUINAME} COMMAND ld -r --whole-archive ${_aname} -o ${_oname} COMMAND diff --git a/src/libui_sdl/libui/unix/area.c b/src/libui_sdl/libui/unix/area.c index 2da9bab..5734b4b 100644 --- a/src/libui_sdl/libui/unix/area.c +++ b/src/libui_sdl/libui/unix/area.c @@ -28,6 +28,8 @@ struct areaWidgetClass { GtkDrawingAreaClass parent_class; }; +typedef struct uiGLContext uiGLContext; + struct uiArea { uiUnixControl c; GtkWidget *widget; // either swidget or areaWidget depending on whether it is scrolling @@ -39,6 +41,10 @@ struct uiArea { GtkWidget *areaWidget; GtkDrawingArea *drawingArea; areaWidget *area; + + gboolean opengl; + uiGLContext *glContext; + unsigned int* req_versions; int bgR, bgG, bgB; @@ -57,6 +63,21 @@ struct uiArea { G_DEFINE_TYPE(areaWidget, areaWidget, GTK_TYPE_DRAWING_AREA) +int boub(GtkWidget* w) { return isAreaWidget(w); } +void baba(GtkWidget* w) +{ + if (!isAreaWidget(w)) return; + + areaWidget *aw = areaWidget(w); + uiArea *a = aw->a; + if (!a->opengl) return; + + GdkGLContext* oldctx = gdk_gl_context_get_current(); + uiGLMakeContextCurrent(a->glContext); + glFinish(); + gdk_gl_context_make_current(oldctx); +} + static void areaWidget_init(areaWidget *aw) { // for events @@ -133,21 +154,28 @@ static gboolean areaWidget_draw(GtkWidget *w, cairo_t *cr) loadAreaSize(a, &(dp.AreaWidth), &(dp.AreaHeight)); - cairo_clip_extents(cr, &clipX0, &clipY0, &clipX1, &clipY1); - dp.ClipX = clipX0; - dp.ClipY = clipY0; - dp.ClipWidth = clipX1 - clipX0; - dp.ClipHeight = clipY1 - clipY0; - - if (a->bgR != -1) + if (!a->opengl) + { + cairo_clip_extents(cr, &clipX0, &clipY0, &clipX1, &clipY1); + dp.ClipX = clipX0; + dp.ClipY = clipY0; + dp.ClipWidth = clipX1 - clipX0; + dp.ClipHeight = clipY1 - clipY0; + + if (a->bgR != -1) + { + cairo_set_source_rgb(cr, a->bgR/255.0, a->bgG/255.0, a->bgB/255.0); + cairo_paint(cr); + } + + // no need to save or restore the graphics state to reset transformations; GTK+ does that for us + (*(a->ah->Draw))(a->ah, a, &dp); + } + else { - cairo_set_source_rgb(cr, a->bgR/255.0, a->bgG/255.0, a->bgB/255.0); - cairo_paint(cr); + areaDrawGL(w, &dp, cr, a->glContext); } - // no need to save or restore the graphics state to reset transformations; GTK+ does that for us - (*(a->ah->Draw))(a->ah, a, &dp); - freeContext(dp.Context); return FALSE; } @@ -598,7 +626,15 @@ static void areaWidget_class_init(areaWidgetClass *class) // control implementation -uiUnixControlAllDefaults(uiArea) +uiUnixControlAllDefaultsExceptDestroy(uiArea) + +static void uiAreaDestroy(uiControl *c) +{ + uiArea* a = uiArea(c); + if (a->opengl && a->glContext) freeGLContext(a->glContext); + g_object_unref(uiArea(c)->widget); + uiFreeControl(c); +} void uiAreaSetBackgroundColor(uiArea *a, int r, int g, int b) { @@ -716,6 +752,7 @@ uiArea *uiNewArea(uiAreaHandler *ah) a->ah = ah; a->scrolling = FALSE; + a->opengl = FALSE; a->areaWidget = GTK_WIDGET(g_object_new(areaWidgetType, "libui-area", a, @@ -730,6 +767,58 @@ uiArea *uiNewArea(uiAreaHandler *ah) return a; } +void _areaCreateGLContext(GtkWidget* widget, gpointer data) +{ + uiArea* a = (uiArea*)data; + + uiGLContext* ctx = NULL; + for (int i = 0; a->req_versions[i] && !ctx; i++) + { + int major = uiGLVerMajor(a->req_versions[i]); + int minor = uiGLVerMinor(a->req_versions[i]); + + // we cannot support any version older than 3.2 via GDK + if ((major < 3) || (major == 3 && minor < 2)) + break; + + ctx = createGLContext(widget, major, minor); + } + + a->glContext = ctx; +} + +uiArea *uiNewGLArea(uiAreaHandler *ah, const unsigned int* req_versions) +{ + uiArea *a; + + uiUnixNewControl(uiArea, a); + + a->ah = ah; + a->scrolling = FALSE; + a->opengl = TRUE; + + a->glContext = NULL; + a->req_versions = req_versions; + a->areaWidget = GTK_WIDGET(g_object_new(areaWidgetType, + "libui-area", a, + NULL)); + a->area = areaWidget(a->areaWidget); + + a->widget = a->areaWidget; + + g_signal_connect(a->widget, "realize", G_CALLBACK(_areaCreateGLContext), a); + + uiAreaSetBackgroundColor(a, -1, -1, -1); + + return a; +} + +uiGLContext *uiAreaGetGLContext(uiArea* a) +{ + if (!a) return NULL; + return a->glContext; +} + uiArea *uiNewScrollingArea(uiAreaHandler *ah, int width, int height) { uiArea *a; @@ -740,6 +829,7 @@ uiArea *uiNewScrollingArea(uiAreaHandler *ah, int width, int height) a->scrolling = TRUE; a->scrollWidth = width; a->scrollHeight = height; + a->opengl = FALSE; a->swidget = gtk_scrolled_window_new(NULL, NULL); a->scontainer = GTK_CONTAINER(a->swidget); diff --git a/src/libui_sdl/libui/unix/draw.c b/src/libui_sdl/libui/unix/draw.c index e55397e..5befcd3 100644 --- a/src/libui_sdl/libui/unix/draw.c +++ b/src/libui_sdl/libui/unix/draw.c @@ -143,13 +143,13 @@ void uiDrawRestore(uiDrawContext *c) // bitmap API -uiDrawBitmap* uiDrawNewBitmap(uiDrawContext* c, int width, int height) +uiDrawBitmap* uiDrawNewBitmap(uiDrawContext* c, int width, int height, int alpha) { uiDrawBitmap* bmp; bmp = uiNew(uiDrawBitmap); - bmp->bmp = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height); + bmp->bmp = cairo_image_surface_create(alpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24, width, height); if (cairo_surface_status(bmp->bmp) != CAIRO_STATUS_SUCCESS) implbug("error creating bitmap: %s", cairo_status_to_string(cairo_surface_status(bmp->bmp))); diff --git a/src/libui_sdl/libui/unix/gl.c b/src/libui_sdl/libui/unix/gl.c new file mode 100644 index 0000000..e1665ee --- /dev/null +++ b/src/libui_sdl/libui/unix/gl.c @@ -0,0 +1,246 @@ +// 26 may 2019 +#include "uipriv_unix.h" + +#include <GL/gl.h> +#include <GL/glx.h> +#include <EGL/egl.h> + +extern GThread* gtkthread; +extern GMutex glmutex; + +struct uiGLContext +{ + GtkWidget* widget; + GdkWindow* window; + + GdkGLContext *gctx; + int vermaj, vermin; + + int width, height; + int scale; + GLuint renderbuffer[2][2]; + GLuint framebuffer[2]; + int backbuffer; +}; + +static void areaAllocRenderbuffer(uiGLContext* glctx); + +static PFNGLGENRENDERBUFFERSPROC _glGenRenderbuffers; +static PFNGLDELETERENDERBUFFERSPROC _glDeleteRenderbuffers; +static PFNGLBINDRENDERBUFFERPROC _glBindRenderbuffer; +static PFNGLRENDERBUFFERSTORAGEPROC _glRenderbufferStorage; +static PFNGLGETRENDERBUFFERPARAMETERIVPROC _glGetRenderbufferParameteriv; + +static PFNGLGENRENDERBUFFERSPROC _glGenFramebuffers; +static PFNGLDELETERENDERBUFFERSPROC _glDeleteFramebuffers; +static PFNGLBINDRENDERBUFFERPROC _glBindFramebuffer; +static PFNGLFRAMEBUFFERTEXTUREPROC _glFramebufferTexture; +static PFNGLFRAMEBUFFERRENDERBUFFERPROC _glFramebufferRenderbuffer; +static PFNGLCHECKFRAMEBUFFERSTATUSPROC _glCheckFramebufferStatus; + +static int _procsLoaded = 0; + +static void _loadGLProcs(GdkGLContext* glctx) +{ + if (_procsLoaded) return; + + _glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)uiGLGetProcAddress("glGenRenderbuffers"); + _glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)uiGLGetProcAddress("glDeleteRenderbuffers"); + _glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)uiGLGetProcAddress("glBindRenderbuffer"); + _glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)uiGLGetProcAddress("glRenderbufferStorage"); + _glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)uiGLGetProcAddress("glGetRenderbufferParameteriv"); + + _glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)uiGLGetProcAddress("glGenFramebuffers"); + _glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)uiGLGetProcAddress("glDeleteFramebuffers"); + _glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)uiGLGetProcAddress("glBindFramebuffer"); + _glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC)uiGLGetProcAddress("glFramebufferTexture"); + _glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)uiGLGetProcAddress("glFramebufferRenderbuffer"); + _glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)uiGLGetProcAddress("glCheckFramebufferStatus"); + + _procsLoaded = 1; +} + +uiGLContext *createGLContext(GtkWidget* widget, int maj, int min) +{ + GdkWindow* gdkwin = gtk_widget_get_window(widget); + + GError* err = NULL; + GdkGLContext* gctx = gdk_window_create_gl_context(gdkwin, &err); + if (err != NULL || gctx == NULL) + { + return NULL; + } + + // TODO: make the set_use_es call conditional (#ifdef or smth) for older versions of gdk? + gdk_gl_context_set_use_es(gctx, FALSE); + gdk_gl_context_set_required_version(gctx, maj, min); + + gboolean res = gdk_gl_context_realize(gctx, &err); + if (err != NULL || res == FALSE) + { + return NULL; + } + + uiGLContext* ctx = uiNew(uiGLContext); + + GtkAllocation allocation; + gtk_widget_get_allocation(widget, &allocation); + int window_scale = gdk_window_get_scale_factor(gdkwin); + ctx->width = allocation.width; + ctx->height = allocation.height; + ctx->scale = window_scale; + + gdk_gl_context_make_current(gctx); + _loadGLProcs(gctx); + areaAllocRenderbuffer(ctx); + ctx->backbuffer = 0; + + ctx->widget = widget; + ctx->window = gdkwin; + ctx->gctx = gctx; + + return ctx; +} + +void freeGLContext(uiGLContext* glctx) +{ + if (glctx == NULL) return; + + gdk_gl_context_make_current(glctx->gctx); + _glDeleteRenderbuffers(4, &glctx->renderbuffer[0][0]); + _glDeleteFramebuffers(2, &glctx->framebuffer[0]); + + gdk_gl_context_clear_current(); + g_object_unref(glctx->gctx); + uiFree(glctx); +} + +static void areaAllocRenderbuffer(uiGLContext* glctx) +{ + // TODO: create textures as a fallback if GL_RGB renderbuffer isn't supported? + // they say GL implementations aren't required to support a GL_RGB renderbuffer + // however, a GL_RGBA one would cause gdk_cairo_draw_from_gl() to fall back to glReadPixels() + + _glGenRenderbuffers(4, &glctx->renderbuffer[0][0]); + _glGenFramebuffers(2, &glctx->framebuffer[0]); + + _glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[0][0]); + _glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, glctx->width*glctx->scale, glctx->height*glctx->scale); + //_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[0][1]); + //_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, glctx->width*glctx->scale, glctx->height*glctx->scale); + + _glBindFramebuffer(GL_FRAMEBUFFER, glctx->framebuffer[0]); + _glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, glctx->renderbuffer[0][0]); + _glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, glctx->renderbuffer[0][1]); + + _glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[1][0]); + _glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, glctx->width*glctx->scale, glctx->height*glctx->scale); + //_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[1][1]); + //_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, glctx->width*glctx->scale, glctx->height*glctx->scale); + + _glBindFramebuffer(GL_FRAMEBUFFER, glctx->framebuffer[1]); + _glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, glctx->renderbuffer[1][0]); + _glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, glctx->renderbuffer[1][1]); + + //if (_glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + // printf("FRAMEBUFFER IS BAD!! %04X\n", _glCheckFramebufferStatus(GL_FRAMEBUFFER)); +} + +static void areaReallocRenderbuffer(uiGLContext* glctx) +{ + _glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[0][0]); + _glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, glctx->width*glctx->scale, glctx->height*glctx->scale); + //_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[0][1]); + //_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, glctx->width*glctx->scale, glctx->height*glctx->scale); + + _glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[1][0]); + _glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, glctx->width*glctx->scale, glctx->height*glctx->scale); + //_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[1][1]); + //_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, glctx->width*glctx->scale, glctx->height*glctx->scale); +} + +void areaDrawGL(GtkWidget* widget, uiAreaDrawParams* dp, cairo_t* cr, uiGLContext* glctx) +{ + int window_scale = gdk_window_get_scale_factor(glctx->window); + + if (glctx->width != dp->AreaWidth || glctx->height != dp->AreaHeight || glctx->scale != window_scale) + { + glctx->width = dp->AreaWidth; + glctx->height = dp->AreaHeight; + glctx->scale = window_scale; + areaReallocRenderbuffer(glctx); + } + else + { + gdk_cairo_draw_from_gl(cr, gtk_widget_get_window(widget), + glctx->renderbuffer[glctx->backbuffer][0], GL_RENDERBUFFER, + 1, 0, 0, glctx->width*glctx->scale, glctx->height*glctx->scale); + } +} + +int uiGLGetFramebuffer(uiGLContext* ctx) +{ + return ctx->framebuffer[ctx->backbuffer]; +} + +float uiGLGetFramebufferScale(uiGLContext* ctx) +{ + return (float)ctx->scale; +} + +void uiGLSwapBuffers(uiGLContext* ctx) +{ + ctx->backbuffer = ctx->backbuffer ? 0 : 1; +} + +void uiGLMakeContextCurrent(uiGLContext* ctx) +{ + if (!ctx) + { + gdk_gl_context_clear_current(); + return; + } + + if (ctx->gctx == gdk_gl_context_get_current()) return; + gdk_gl_context_make_current(ctx->gctx); +} + +void uiGLBegin(uiGLContext* ctx) +{ + if (g_thread_self() != gtkthread) + { + g_mutex_lock(&glmutex); + } +} + +void uiGLEnd(uiGLContext* ctx) +{ + if (g_thread_self() != gtkthread) + { + g_mutex_unlock(&glmutex); + } +} + +void *uiGLGetProcAddress(const char* proc) +{ + // TODO: consider using epoxy or something funny + + void* ptr; + + ptr = glXGetProcAddressARB((const GLubyte*)proc); + if (ptr) return ptr; + + ptr = eglGetProcAddress(proc); + if (ptr) return ptr; + + ptr = dlsym(NULL /* RTLD_DEFAULT */, proc); + if (ptr) return ptr; + + return NULL; +} +unsigned int uiGLGetVersion(uiGLContext* ctx) +{ + if (!ctx) return 0; + return uiGLVersion(ctx->vermaj, ctx->vermin); +} + diff --git a/src/libui_sdl/libui/unix/main.c b/src/libui_sdl/libui/unix/main.c index 409b659..516bd76 100644 --- a/src/libui_sdl/libui/unix/main.c +++ b/src/libui_sdl/libui/unix/main.c @@ -5,6 +5,25 @@ uiInitOptions options; // kind of a hack GThread* gtkthread; +GMutex glmutex; + +static void _eventfilter(GdkEvent* evt, gpointer data) +{ + if (evt->type == GDK_EXPOSE) + { + g_mutex_lock(&glmutex); + gtk_main_do_event(evt); + g_mutex_unlock(&glmutex); + return; + } + + gtk_main_do_event(evt); +} + +static void _eventfilterdestroy(gpointer data) +{ + printf("DELET\n"); +} const char *uiInit(uiInitOptions *o) { @@ -21,6 +40,7 @@ const char *uiInit(uiInitOptions *o) loadFutures(); gtkthread = g_thread_self(); + g_mutex_init(&glmutex); GList* iconlist = NULL; iconlist = g_list_append(iconlist, gdk_pixbuf_new_from_resource("/org/kuriboland/melonDS/icon/melon_16x16.png", NULL)); @@ -31,6 +51,10 @@ const char *uiInit(uiInitOptions *o) gtk_window_set_default_icon_list(iconlist); + g_mutex_init(&glmutex); + + gdk_event_handler_set(_eventfilter, NULL, _eventfilterdestroy); + return NULL; } diff --git a/src/libui_sdl/libui/unix/uipriv_unix.h b/src/libui_sdl/libui/unix/uipriv_unix.h index 33ff1e3..9b77188 100644 --- a/src/libui_sdl/libui/unix/uipriv_unix.h +++ b/src/libui_sdl/libui/unix/uipriv_unix.h @@ -5,7 +5,7 @@ #define GDK_VERSION_MAX_ALLOWED GDK_VERSION_3_10 #include <gtk/gtk.h> #include <math.h> -#include <dlfcn.h> // see drawtext.c +#include <dlfcn.h> // see drawtext.c, gl.c #include <langinfo.h> #include <string.h> #include <stdlib.h> @@ -63,3 +63,9 @@ extern GtkCellRenderer *newCellRendererButton(void); extern void loadFutures(void); extern PangoAttribute *FUTURE_pango_attr_foreground_alpha_new(guint16 alpha); extern gboolean FUTURE_gtk_widget_path_iter_set_object_name(GtkWidgetPath *path, gint pos, const char *name); + +// gl.c +extern uiGLContext *createGLContext(GtkWidget* widget, int maj, int min); +extern void freeGLContext(uiGLContext* glctx); +extern void areaDrawGL(GtkWidget* widget, uiAreaDrawParams* dp, cairo_t* cr, uiGLContext* glctx); + diff --git a/src/libui_sdl/libui/unix/window.c b/src/libui_sdl/libui/unix/window.c index 7da1134..6d5e2de 100644 --- a/src/libui_sdl/libui/unix/window.c +++ b/src/libui_sdl/libui/unix/window.c @@ -102,6 +102,23 @@ static void uiWindowDestroy(uiControl *c) uiFreeControl(uiControl(w)); } +void uiWindowSetPosition(uiWindow *w, int x, int y) +{ + if (!w) return; + + gtk_window_move(w->window, x, y); +} + +void uiWindowPosition(uiWindow *w, int *x, int *y) +{ + if (!w) return; + + int xx, yy; + gtk_window_get_position(w->window, &xx, &yy); + if (x) *x = xx; + if (y) *y = yy; +} + uiUnixControlDefaultHandle(uiWindow) uiControl *uiWindowParent(uiControl *c) @@ -442,3 +459,4 @@ uiWindow *uiNewWindow(const char *title, int width, int height, int maximized, i return w; } + diff --git a/src/libui_sdl/libui/windows/CMakeLists.txt b/src/libui_sdl/libui/windows/CMakeLists.txt index 4695eb4..9d5313a 100644 --- a/src/libui_sdl/libui/windows/CMakeLists.txt +++ b/src/libui_sdl/libui/windows/CMakeLists.txt @@ -29,6 +29,7 @@ list(APPEND _LIBUI_SOURCES windows/fontbutton.cpp windows/fontdialog.cpp windows/form.cpp + windows/gl.cpp windows/graphemes.cpp windows/grid.cpp windows/group.cpp diff --git a/src/libui_sdl/libui/windows/area.cpp b/src/libui_sdl/libui/windows/area.cpp index 2185f25..72d5145 100644 --- a/src/libui_sdl/libui/windows/area.cpp +++ b/src/libui_sdl/libui/windows/area.cpp @@ -25,8 +25,11 @@ static LRESULT CALLBACK areaWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM } // always recreate the render target if necessary - if (a->rt == NULL) - a->rt = makeHWNDRenderTarget(a->hwnd); + if (!a->openGL) + { + if (a->rt == NULL) + a->rt = makeHWNDRenderTarget(a->hwnd); + } if (areaDoDraw(a, uMsg, wParam, lParam, &lResult) != FALSE) return lResult; @@ -34,12 +37,14 @@ static LRESULT CALLBACK areaWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM if (uMsg == WM_WINDOWPOSCHANGED) { if ((wp->flags & SWP_NOSIZE) != 0) return DefWindowProcW(hwnd, uMsg, wParam, lParam); + a->width = -1; + a->height = -1; uiWindowsEnsureGetClientRect(a->hwnd, &client); areaDrawOnResize(a, &client); areaScrollOnResize(a, &client); { double w, h; - loadAreaSize(a, a->rt, &w, &h); + loadAreaSize(a, &w, &h); a->ah->Resize(a->ah, a, (int)w, (int)h); } return 0; @@ -56,7 +61,15 @@ static LRESULT CALLBACK areaWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM // control implementation -uiWindowsControlAllDefaults(uiArea) +uiWindowsControlAllDefaultsExceptDestroy(uiArea) + +static void uiAreaDestroy(uiControl *c) +{ + uiArea* a = uiArea(c); + if (a->openGL && a->glcontext) freeGLContext(a->glcontext); + uiWindowsEnsureDestroyWindow(a->hwnd); + uiFreeControl(c); +} static void uiAreaMinimumSize(uiWindowsControl *c, int *width, int *height) { @@ -182,6 +195,9 @@ uiArea *uiNewArea(uiAreaHandler *ah) uiWindowsNewControl(uiArea, a); + a->width = -1; + a->height = -1; + a->ah = ah; a->scrolling = FALSE; clickCounterReset(&(a->cc)); @@ -195,6 +211,50 @@ uiArea *uiNewArea(uiAreaHandler *ah) uiAreaSetBackgroundColor(a, -1, -1, -1); + a->openGL = 0; + + return a; +} + +uiGLContext *uiAreaGetGLContext(uiArea* a) +{ + if (!a->openGL) userbug("trying to get GL context from non-GL area"); + + return a->glcontext; +} + +uiArea *uiNewGLArea(uiAreaHandler *ah, const unsigned int* req_versions) +{ + uiArea *a; + + uiWindowsNewControl(uiArea, a); + + a->width = -1; + a->height = -1; + + a->ah = ah; + a->scrolling = FALSE; + clickCounterReset(&(a->cc)); + + // a->hwnd is assigned in areaWndProc() + uiWindowsEnsureCreateControlHWND(0, + areaClass, L"", + 0, + hInstance, a, + FALSE); + + uiAreaSetBackgroundColor(a, -1, -1, -1); + + a->openGL = 1; + + for (int i = 0; req_versions[i]; i++) + { + int major = uiGLVerMajor(req_versions[i]); + int minor = uiGLVerMinor(req_versions[i]); + a->glcontext = createGLContext(a, major, minor); + if (a->glcontext) break; + } + return a; } @@ -204,6 +264,9 @@ uiArea *uiNewScrollingArea(uiAreaHandler *ah, int width, int height) uiWindowsNewControl(uiArea, a); + a->width = -1; + a->height = -1; + a->ah = ah; a->scrolling = TRUE; a->scrollWidth = width; @@ -219,6 +282,8 @@ uiArea *uiNewScrollingArea(uiAreaHandler *ah, int width, int height) uiAreaSetBackgroundColor(a, -1, -1, -1); + a->openGL = 0; // TODO, eventually??? + // set initial scrolling parameters areaUpdateScroll(a); diff --git a/src/libui_sdl/libui/windows/area.hpp b/src/libui_sdl/libui/windows/area.hpp index add62dd..cfc45a4 100644 --- a/src/libui_sdl/libui/windows/area.hpp +++ b/src/libui_sdl/libui/windows/area.hpp @@ -10,6 +10,8 @@ struct uiArea { HWND hwnd; uiAreaHandler *ah; + int width, height; + BOOL scrolling; int scrollWidth; int scrollHeight; @@ -26,6 +28,9 @@ struct uiArea { int bgR, bgG, bgB; + int openGL; + uiGLContext* glcontext; + ID2D1HwndRenderTarget *rt; }; @@ -42,6 +47,10 @@ extern void areaUpdateScroll(uiArea *a); extern BOOL areaDoEvents(uiArea *a, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult); // areautil.cpp -extern void loadAreaSize(uiArea *a, ID2D1RenderTarget *rt, double *width, double *height); +extern void loadAreaSize(uiArea *a, double *width, double *height); extern void pixelsToDIP(uiArea *a, double *x, double *y); extern void dipToPixels(uiArea *a, double *x, double *y); + +// gl.cpp +extern uiGLContext* createGLContext(uiArea* a, int vermajor, int verminor); +extern void freeGLContext(uiGLContext* c); diff --git a/src/libui_sdl/libui/windows/areadraw.cpp b/src/libui_sdl/libui/windows/areadraw.cpp index a9ad477..f369255 100644 --- a/src/libui_sdl/libui/windows/areadraw.cpp +++ b/src/libui_sdl/libui/windows/areadraw.cpp @@ -6,6 +6,13 @@ static HRESULT doPaint(uiArea *a, ID2D1RenderTarget *rt, RECT *clip) { uiAreaHandler *ah = a->ah; uiAreaDrawParams dp; + + if (a->openGL) + { + //(*(ah->Draw))(ah, a, &dp); + return S_OK; + } + COLORREF bgcolorref; D2D1_COLOR_F bgcolor; D2D1_MATRIX_3X2_F scrollTransform; @@ -13,7 +20,7 @@ static HRESULT doPaint(uiArea *a, ID2D1RenderTarget *rt, RECT *clip) // no need to save or restore the graphics state to reset transformations; it's handled by resetTarget() in draw.c, called during the following dp.Context = newContext(rt); - loadAreaSize(a, rt, &(dp.AreaWidth), &(dp.AreaHeight)); + loadAreaSize(a, &(dp.AreaWidth), &(dp.AreaHeight)); dp.ClipX = clip->left; dp.ClipY = clip->top; @@ -113,6 +120,9 @@ static void onWM_PAINT(uiArea *a) static void onWM_PRINTCLIENT(uiArea *a, HDC dc) { + // TODO???? + if (a->openGL) return; + ID2D1DCRenderTarget *rt; RECT client; HRESULT hr; @@ -143,13 +153,16 @@ BOOL areaDoDraw(uiArea *a, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lRe // TODO only if the render target wasn't just created? void areaDrawOnResize(uiArea *a, RECT *newClient) { - D2D1_SIZE_U size; + if (!a->openGL) + { + D2D1_SIZE_U size; - size.width = newClient->right - newClient->left; - size.height = newClient->bottom - newClient->top; - // don't track the error; we'll get that in EndDraw() - // see https://msdn.microsoft.com/en-us/library/windows/desktop/dd370994%28v=vs.85%29.aspx - a->rt->Resize(&size); + size.width = newClient->right - newClient->left; + size.height = newClient->bottom - newClient->top; + // don't track the error; we'll get that in EndDraw() + // see https://msdn.microsoft.com/en-us/library/windows/desktop/dd370994%28v=vs.85%29.aspx + a->rt->Resize(&size); + } // according to Rick Brewster, we must always redraw the entire client area after calling ID2D1RenderTarget::Resize() (see http://stackoverflow.com/a/33222983/3408572) // we used to have a uiAreaHandler.RedrawOnResize() method to decide this; now you know why we don't anymore diff --git a/src/libui_sdl/libui/windows/areaevents.cpp b/src/libui_sdl/libui/windows/areaevents.cpp index 3ff7a47..46d6ab9 100644 --- a/src/libui_sdl/libui/windows/areaevents.cpp +++ b/src/libui_sdl/libui/windows/areaevents.cpp @@ -109,7 +109,7 @@ static void areaMouseEvent(uiArea *a, int down, int up, WPARAM wParam, LPARAM l me.Y += a->vscrollpos; } - loadAreaSize(a, NULL, &(me.AreaWidth), &(me.AreaHeight)); + loadAreaSize(a, &(me.AreaWidth), &(me.AreaHeight)); me.Down = down; me.Up = up; diff --git a/src/libui_sdl/libui/windows/areautil.cpp b/src/libui_sdl/libui/windows/areautil.cpp index 212ea42..ea13221 100644 --- a/src/libui_sdl/libui/windows/areautil.cpp +++ b/src/libui_sdl/libui/windows/areautil.cpp @@ -2,20 +2,35 @@ #include "uipriv_windows.hpp" #include "area.hpp" -void loadAreaSize(uiArea *a, ID2D1RenderTarget *rt, double *width, double *height) +// TODO: make those int rather than double +void loadAreaSize(uiArea *a, double *width, double *height) { D2D1_SIZE_F size; + if (a->width != -1) + { + *width = (double)a->width; + *height = (double)a->height; + return; + } + *width = 0; *height = 0; if (!a->scrolling) { - if (rt == NULL) + /*if (rt == NULL) rt = a->rt; size = realGetSize(rt); *width = size.width; *height = size.height; - dipToPixels(a, width, height); + dipToPixels(a, width, height);*/ + RECT rect; + GetWindowRect(a->hwnd, &rect); + *width = (double)(rect.right - rect.left); + *height = (double)(rect.bottom - rect.top); } + + a->width = (int)*width; + a->height = (int)*height; } void pixelsToDIP(uiArea *a, double *x, double *y) diff --git a/src/libui_sdl/libui/windows/draw.cpp b/src/libui_sdl/libui/windows/draw.cpp index 11a777d..9a815b9 100644 --- a/src/libui_sdl/libui/windows/draw.cpp +++ b/src/libui_sdl/libui/windows/draw.cpp @@ -522,7 +522,7 @@ void uiDrawRestore(uiDrawContext *c) // bitmap API -uiDrawBitmap* uiDrawNewBitmap(uiDrawContext* c, int width, int height) +uiDrawBitmap* uiDrawNewBitmap(uiDrawContext* c, int width, int height, int alpha) { uiDrawBitmap* bmp; HRESULT hr; @@ -532,7 +532,8 @@ uiDrawBitmap* uiDrawNewBitmap(uiDrawContext* c, int width, int height) D2D1_BITMAP_PROPERTIES bp2 = D2D1::BitmapProperties(); bp2.dpiX = 0; bp2.dpiY = 0; - bp2.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE); + bp2.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, + alpha ? D2D1_ALPHA_MODE_PREMULTIPLIED : D2D1_ALPHA_MODE_IGNORE); //c->rt->BeginDraw(); diff --git a/src/libui_sdl/libui/windows/gl.cpp b/src/libui_sdl/libui/windows/gl.cpp new file mode 100644 index 0000000..c621721 --- /dev/null +++ b/src/libui_sdl/libui/windows/gl.cpp @@ -0,0 +1,161 @@ +// 31 march 2019 +#include "uipriv_windows.hpp" +#include "area.hpp" + +#include <GL/gl.h> +#include <GL/wglext.h> + +struct uiGLContext +{ + uiArea* a; + + HWND hwnd; + HDC dc; + HGLRC rc; + + unsigned int version; +}; + + +uiGLContext* createGLContext(uiArea* a, int vermajor, int verminor) +{ + uiGLContext* ctx; + BOOL res; + + ctx = uiNew(uiGLContext); + + ctx->a = a; + ctx->hwnd = a->hwnd; + + PIXELFORMATDESCRIPTOR pfd; + memset(&pfd, 0, sizeof(pfd)); + pfd.nSize = sizeof(pfd); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = 24; + pfd.cAlphaBits = 8; + pfd.cDepthBits = 24; + pfd.cStencilBits = 8; + pfd.iLayerType = PFD_MAIN_PLANE; + + ctx->dc = GetDC(ctx->hwnd); + if (!ctx->dc) + { + uiFree(ctx); + return NULL; + } + + int pixelformat = ChoosePixelFormat(ctx->dc, &pfd); + res = SetPixelFormat(ctx->dc, pixelformat, &pfd); + if (!res) + { + ReleaseDC(ctx->hwnd, ctx->dc); + uiFree(ctx); + return NULL; + } + + ctx->rc = wglCreateContext(ctx->dc); + if (!ctx->rc) + { + ReleaseDC(ctx->hwnd, ctx->dc); + uiFree(ctx); + return NULL; + } + + wglMakeCurrent(ctx->dc, ctx->rc); + + if (vermajor >= 3) + { + HGLRC (*wglCreateContextAttribsARB)(HDC,HGLRC,const int*); + HGLRC rc_better = NULL; + + wglCreateContextAttribsARB = (HGLRC(*)(HDC,HGLRC,const int*))wglGetProcAddress("wglCreateContextAttribsARB"); + if (wglCreateContextAttribsARB) + { + int attribs[15]; + int i = 0; + + attribs[i++] = WGL_CONTEXT_MAJOR_VERSION_ARB; + attribs[i++] = vermajor; + attribs[i++] = WGL_CONTEXT_MINOR_VERSION_ARB; + attribs[i++] = verminor; + + attribs[i] = 0; + rc_better = wglCreateContextAttribsARB(ctx->dc, NULL, attribs); + } + + wglMakeCurrent(NULL, NULL); + wglDeleteContext(ctx->rc); + + if (!rc_better) + { + ReleaseDC(ctx->hwnd, ctx->dc); + uiFree(ctx); + return NULL; + } + + ctx->version = uiGLVersion(vermajor, verminor); + ctx->rc = rc_better; + wglMakeCurrent(ctx->dc, ctx->rc); + } + + return ctx; +} + +void freeGLContext(uiGLContext* ctx) +{ + if (ctx == NULL) return; + wglMakeCurrent(NULL, NULL); + wglDeleteContext(ctx->rc); + ReleaseDC(ctx->hwnd, ctx->dc); + uiFree(ctx); +} + +void uiGLMakeContextCurrent(uiGLContext* ctx) +{ + if (ctx == NULL) + { + wglMakeCurrent(NULL, NULL); + return; + } + + if (wglGetCurrentContext() == ctx->rc) return; + int res = wglMakeCurrent(ctx->dc, ctx->rc); +} + +unsigned int uiGLGetVersion(uiGLContext* ctx) +{ + if (ctx == NULL) return 0; + return ctx->version; +} + +void *uiGLGetProcAddress(const char* proc) +{ + return (void*)wglGetProcAddress(proc); +} + +void uiGLBegin(uiGLContext* ctx) +{ +} + +void uiGLEnd(uiGLContext* ctx) +{ +} + +void uiGLSwapBuffers(uiGLContext* ctx) +{ + if (ctx == NULL) return; + SwapBuffers(ctx->dc); +} + +int uiGLGetFramebuffer(uiGLContext* ctx) +{ + return 0; +} + +float uiGLGetFramebufferScale(uiGLContext* ctx) +{ + // TODO + return 1; +} diff --git a/src/libui_sdl/libui/windows/window.cpp b/src/libui_sdl/libui/windows/window.cpp index f52e2f6..18d1171 100644 --- a/src/libui_sdl/libui/windows/window.cpp +++ b/src/libui_sdl/libui/windows/window.cpp @@ -363,6 +363,21 @@ static void windowMonitorRect(HWND hwnd, RECT *r) *r = mi.rcMonitor; } +void uiWindowPosition(uiWindow *w, int *x, int *y) +{ + RECT rect; + if (GetWindowRect(w->hwnd, &rect) == 0) + logLastError(L"error getting window position"); + *x = rect.left; + *y = rect.top; +} + +void uiWindowSetPosition(uiWindow *w, int x, int y) +{ + if (SetWindowPos(w->hwnd, NULL, x, y, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOOWNERZORDER | SWP_NOZORDER) == 0) + logLastError(L"error moving window"); +} + void uiWindowContentSize(uiWindow *w, int *width, int *height) { RECT r; |