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; |