refactor source tree organization, switch to meson

This commit is contained in:
Mis012
2022-10-02 23:06:56 +02:00
parent 2f785e2a59
commit 449090143e
296 changed files with 171615 additions and 69 deletions

View File

@@ -0,0 +1,104 @@
#include <gtk/gtk.h>
#include "../drawables/ninepatch.h"
#include "WrapperWidget.h"
/**
* gdk_texture_new_for_surface:
* @surface: a cairo image surface
*
* Creates a new texture object representing the surface.
*
* @surface must be an image surface with format CAIRO_FORMAT_ARGB32.
*
* Returns: a new `GdkTexture`
*/
GdkTexture * gdk_texture_new_for_surface (cairo_surface_t *surface)
{
GdkTexture *texture;
GBytes *bytes;
g_return_val_if_fail (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE, NULL);
g_return_val_if_fail (cairo_image_surface_get_width (surface) > 0, NULL);
g_return_val_if_fail (cairo_image_surface_get_height (surface) > 0, NULL);
bytes = g_bytes_new_with_free_func (cairo_image_surface_get_data (surface),
cairo_image_surface_get_height (surface)
* cairo_image_surface_get_stride (surface),
(GDestroyNotify) cairo_surface_destroy,
cairo_surface_reference (surface));
texture = gdk_memory_texture_new (cairo_image_surface_get_width (surface),
cairo_image_surface_get_height (surface),
GDK_MEMORY_DEFAULT,
bytes,
cairo_image_surface_get_stride (surface));
g_bytes_unref (bytes);
return texture;
}
// ---
G_DEFINE_TYPE(WrapperWidget, wrapper_widget, GTK_TYPE_WIDGET)
static void wrapper_widget_init (WrapperWidget *frame_layout)
{
}
static void wrapper_widget_dispose(GObject *wrapper_widget)
{
gtk_widget_unparent(gtk_widget_get_first_child(GTK_WIDGET(wrapper_widget)));
G_OBJECT_CLASS (wrapper_widget_parent_class)->dispose (wrapper_widget);
}
void wrapper_snapshot(GtkWidget* widget, GtkSnapshot* snapshot)
{
struct ninepatch_t *ninepatch = g_object_get_data(G_OBJECT(widget), "background_ninepatch");
if(ninepatch && 0) {
GtkAllocation alloc;
gtk_widget_get_allocation(widget, &alloc);
ninepatch_stretch(ninepatch, alloc.width, alloc.height);
cairo_surface_t *surface = ninepatch_to_surface(ninepatch);
// GdkPixbuf *pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, ninepatch->__w, ninepatch->__h);
// GdkTexture *texture = gdk_texture_new_for_pixbuf(pixbuf);
GdkTexture *texture = gdk_texture_new_for_surface(surface);
gtk_snapshot_append_texture(snapshot, texture, &GRAPHENE_RECT_INIT(0, 0, ninepatch->__w, ninepatch->__h));
cairo_surface_destroy(surface);
// g_object_unref(pixbuf);
g_object_unref(texture);
}
gtk_widget_snapshot_child(widget, gtk_widget_get_first_child(widget), snapshot);
}
static void wrapper_widget_class_init(WrapperWidgetClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->dispose = wrapper_widget_dispose;
widget_class->snapshot = wrapper_snapshot;
gtk_widget_class_set_layout_manager_type(widget_class, GTK_TYPE_BIN_LAYOUT);
}
GtkWidget * wrapper_widget_new(void)
{
return g_object_new (wrapper_widget_get_type(), NULL);
}
void wrapper_widget_set_child(WrapperWidget *parent, GtkWidget *child) // TODO: make sure there can only be one child
{
gtk_widget_insert_before(child, GTK_WIDGET(parent), NULL);
}

View File

@@ -0,0 +1,19 @@
#ifndef WRAPPER_WIDGET_H
#define WRAPPER_WIDGET_H
G_DECLARE_FINAL_TYPE (WrapperWidget, wrapper_widget, WRAPPER, WIDGET, GtkWidget)
struct _WrapperWidget
{
GtkWidget parent_instance;
};
struct _WrapperWidgetClass
{
GtkWidgetClass parent_class;
};
GtkWidget * wrapper_widget_new(void);
void wrapper_widget_set_child(WrapperWidget *parent, GtkWidget *child);
#endif

View File

@@ -0,0 +1,496 @@
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glcorearb.h>
#include <EGL/egl.h>
#include <GLES/gl.h>
#include <GLES/glext.h>
#include <gtk/gtk.h>
#include "../defines.h"
#include "../util.h"
#include "WrapperWidget.h"
#include "../generated_headers/android_opengl_GLSurfaceView.h"
//#define FIXME__WIDTH 540
//#define FIXME__HEIGHT 960
// FIXME: what do we do here? we should probably take these from the size of the GLArea, but how do we change the sizes of all the textures and buffers etc when the GLArea changes size?
// for now, borrow the initial app window width/height
extern int FIXME__WIDTH;
extern int FIXME__HEIGHT;
// mainly frame markers (very obtrusive, not recommended for most builds)
#ifdef DEBUG_GLAREA
#define d_printf(...) printf(VA_ARGS)
#else
#define d_printf(...)
#endif
#define ___GL_TRACE___(message) glDebugMessageInsert(GL_DEBUG_SOURCE_THIRD_PARTY, GL_DEBUG_TYPE_MARKER, 0xdeadbeef, GL_DEBUG_SEVERITY_NOTIFICATION, strlen(message), message)
JNIEXPORT void JNICALL Java_android_opengl_GLSurfaceView_native_1constructor__Landroid_content_Context_2(JNIEnv *env, jobject this, jobject context)
{
GtkWidget *wrapper = wrapper_widget_new();
GtkWidget *gl_area = gtk_gl_area_new();
wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), gl_area);
_SET_LONG_FIELD(this, "widget", _INTPTR(gl_area));
}
//two triangles put together to make a square
const float positions[] = {
-1, -1, 0,
-1, 1, 0,
1, -1, 0,
1, -1, 0,
-1, 1, 0,
1, 1, 0
};
const char *vertexStr = "#version 320 es\n"
"in vec3 pos;\n"
"out vec2 texCoords;\n"
"void main(){\n"
" texCoords = vec2(pos.x, pos.y);\n"
" gl_Position = vec4((pos.x * 2.0) - 1.0, (pos.y * 2.0) - 1.0, pos.z, 1.0);\n"
"}\n";
const char *fragmentStr = "#version 320 es\n"
"out highp vec4 outputColor;\n"
"in highp vec2 texCoords;\n"
"uniform sampler2D texSampler;\n"
"void main(){\n"
" outputColor = texture(texSampler, texCoords);\n"
"}\n";
struct render_priv {
GLuint program;
GLuint vao;
int texUnit;
GLuint texBufferdObject;
GLuint sampler;
/* --- */
EGLSurface eglSurface;
EGLContext eglContext;
GLuint FramebufferName;
GLuint renderedTexture;
GLuint texture_id;
EGLImage egl_image;
};
static void check_shader_compile_error(GLuint shader)
{
GLint compileResult;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
if(compileResult != GL_TRUE) {
GLint log_size = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_size);
GLchar *info_log = malloc(log_size);
glGetShaderInfoLog(shader, log_size, &log_size, info_log);
fprintf(stderr, "\nError compiling one of the shaders used by GLSurfaceView:\n%s\n---\nsince this error shouldn't ever happen, we fail hard\n", info_log);
free(info_log);
exit(1);
}
}
static void check_program_link_error(GLuint program)
{
GLint link_status = 0;
glGetProgramiv(program, GL_LINK_STATUS, &link_status);
if(link_status != GL_TRUE) {
GLint log_size = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_size);
GLchar *info_log = malloc(log_size);
glGetProgramInfoLog(program, log_size, &log_size, info_log);
fprintf(stderr, "\nError linking the program used by GLSurfaceView:\n%s\n---\nsince this error shouldn't ever happen, we fail hard\n", info_log);
free(info_log);
exit(1);
}
}
#define check_egl_error() \
do { \
EGLint error_ = eglGetError(); \
if(error_ != EGL_SUCCESS) \
fprintf(stderr, "\nError in %s (%s:%d): \n" \
"eglGetError reported 0x%x\n" \
"this might be because we need to implement more stuff, so we will continue from here\n", \
__func__, __FILE__, __LINE__, error_); \
} while(0)
// TODO: use this where appropriate
#define check_gl_error() \
do { \
GLenum error_ = glGetError(); \
if(error_ != GL_NO_ERROR) \
fprintf(stderr, "\nError in %s (%s:%d): \n" \
"glGetError reported 0x%x\n" \
"this might be because we need to implement more stuff, so we will continue from here\n", \
__func__, __FILE__, __LINE__, error_); \
} while(0)
struct jni_gl_callback_data { JavaVM *jvm; jobject this; jobject renderer; bool first_time;};
static void on_realize(GtkGLArea *gl_area, struct jni_gl_callback_data *d)
{
gtk_gl_area_make_current(gl_area);
struct render_priv *render_priv = g_object_get_data(G_OBJECT(gl_area), "render_priv");
JNIEnv *env;
(*d->jvm)->GetEnv(d->jvm, (void**)&env, JNI_VERSION_1_6);
EGLDisplay eglDisplay = eglGetDisplay((EGLNativeDisplayType)0);
EGLDisplay old_eglDisplay = eglGetCurrentDisplay();
d_printf("GTK version: >%d__%d__%d<\n", gtk_get_major_version(), gtk_get_minor_version(), gtk_get_micro_version());
d_printf("OpenGL version: >%s<\n", glGetString(GL_VERSION));
glGenTextures(1, &render_priv->texture_id);
// vertex shader
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexStr, NULL);
glCompileShader(vertexShader);
check_shader_compile_error(vertexShader);
// fragment shader
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentStr, NULL);
glCompileShader(fragmentShader);
check_shader_compile_error(fragmentShader);
// program
render_priv->program = glCreateProgram();
glAttachShader(render_priv->program, vertexShader);
glAttachShader(render_priv->program, fragmentShader);
glLinkProgram(render_priv->program);
check_program_link_error(render_priv->program);
glUseProgram(render_priv->program);
// the triangles
glGenVertexArrays(1, &render_priv->vao);
glBindVertexArray(render_priv->vao);
GLuint positionBufferObject;
glGenBuffers(1, &positionBufferObject);
glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*6*3,positions, GL_STREAM_DRAW);
GLuint posIndex = glGetAttribLocation(render_priv->program, "pos");
glEnableVertexAttribArray(posIndex);
glVertexAttribPointer(posIndex, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glUseProgram(0);
glUseProgram(render_priv->program);
// the texture we will be rendering to
glGenTextures(1, &render_priv->texBufferdObject);
glBindTexture(GL_TEXTURE_2D, render_priv->texBufferdObject);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glBindTexture(GL_TEXTURE_2D, 0);
// texture sampler for our triangles
glGenSamplers(1, &render_priv->sampler);
glSamplerParameteri(render_priv->sampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glSamplerParameteri(render_priv->sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glSamplerParameteri(render_priv->sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
GLuint samplerUniform = glGetUniformLocation(render_priv->program, "texSampler");
glUniform1i(samplerUniform, render_priv->texUnit);
glUseProgram(0);
// EGL setup
eglInitialize(eglDisplay, 0, 0);
eglBindAPI(EGL_OPENGL_ES_API);
EGLConfig eglConfig;
// a roundabout way to let the app define the parameter list, and then choose the best fit out of all the returned configs
eglConfig = (EGLConfig)_PTR((*env)->CallLongMethod(env, d->this, handle_cache.gl_surface_view.wrap_EGLConfigChooser_chooseConfig, _INTPTR(eglDisplay)));
if((*env)->ExceptionCheck(env))
(*env)->ExceptionDescribe(env);
check_egl_error();
// set up the pbuffer (TODO: is there any way to dynamically change the width/height?)
EGLint pbufferAttribs[5];
pbufferAttribs[0] = EGL_WIDTH;
pbufferAttribs[1] = FIXME__WIDTH;
pbufferAttribs[2] = EGL_HEIGHT;
pbufferAttribs[3] = FIXME__HEIGHT;
pbufferAttribs[4] = EGL_NONE;
render_priv->eglSurface = eglCreatePbufferSurface(eglDisplay, eglConfig, pbufferAttribs);
check_egl_error();
// a roundabout way to run eglCreateContext with the atrribute list that the app chose
render_priv->eglContext = (EGLContext)_PTR((*env)->CallLongMethod(env, d->this, handle_cache.gl_surface_view.wrap_EGLContextFactory_createContext, _INTPTR(eglDisplay), _INTPTR(eglConfig)));
check_egl_error();
// save the EGL state before we change it, so we can switch back later
EGLContext old_eglContext = eglGetCurrentContext();
EGLSurface old_read_surface = eglGetCurrentSurface(EGL_READ);
EGLSurface old_draw_surface = eglGetCurrentSurface(EGL_DRAW);
bool result = eglMakeCurrent(eglDisplay, render_priv->eglSurface, render_priv->eglSurface, render_priv->eglContext);
check_egl_error();
// set up the framebuffer
glGenFramebuffers(1, &render_priv->FramebufferName);
glBindFramebuffer(GL_FRAMEBUFFER, render_priv->FramebufferName);
check_gl_error();
glGenTextures(1, &render_priv->renderedTexture);
glBindTexture(GL_TEXTURE_2D, render_priv->renderedTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, FIXME__WIDTH, FIXME__HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
check_gl_error();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
check_gl_error();
GLuint depthrenderbuffer;
glGenRenderbuffers(1, &depthrenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthrenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, FIXME__WIDTH, FIXME__HEIGHT);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthrenderbuffer);
check_gl_error();
// Set "renderedTexture" as our colour attachement #0
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, render_priv->renderedTexture, 0);
check_gl_error();
// Set the list of draw buffers.
GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0};
glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers
check_gl_error();
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
fprintf(stderr, "Error: glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE\n");
// create the EGL Image which we will use to access the rendered-to texture from Gtk's EGL context
render_priv->egl_image = eglCreateImage(eglDisplay, render_priv->eglContext, EGL_GL_TEXTURE_2D, (EGLClientBuffer)(intptr_t)render_priv->renderedTexture, NULL);
check_egl_error();
// Here we call the app's onSurfaceCreated callback. This is the android API's equivalent of the `realize` callback that we are currently in.
___GL_TRACE___("---- calling onSurfaceCreated");
(*env)->CallVoidMethod(env, d->renderer, handle_cache.renderer.onSurfaceCreated, _GET_OBJ_FIELD(d->this, "java_gl_wrapper", "Ljavax/microedition/khronos/opengles/GL10;"), NULL); // FIXME passing NULL only works if the app doesn't use these parameters
if((*env)->ExceptionCheck(env))
(*env)->ExceptionDescribe(env);
___GL_TRACE___("---- returned from calling onSurfaceCreated");
// This should be called from Gtk's `resize` callback. However, until we figure out how to resize the pbuffer, the framebuffer, and the texture, we can't afford to pass the actual widget's dimensions here
___GL_TRACE___("---- calling onSurfaceChanged");
(*env)->CallVoidMethod(env, d->renderer, handle_cache.renderer.onSurfaceChanged, NULL, FIXME__WIDTH, FIXME__HEIGHT); // FIXME put this in the right callback (and pass the actual dimensions)
if((*env)->ExceptionCheck(env))
(*env)->ExceptionDescribe(env);
___GL_TRACE___("---- returned from calling onSurfaceChanged");
// restore the EGL context so that Gtk doesn't get confused
result = eglMakeCurrent(old_eglDisplay, old_read_surface, old_draw_surface, old_eglContext);
check_egl_error();
}
static gboolean render(GtkGLArea *gl_area, GdkGLContext *context, struct jni_gl_callback_data *d)
{
struct render_priv *render_priv = g_object_get_data(G_OBJECT(gl_area), "render_priv");
JNIEnv *env;
(*d->jvm)->GetEnv(d->jvm, (void**)&env, JNI_VERSION_1_6);
EGLDisplay eglDisplay = eglGetDisplay((EGLNativeDisplayType)0);
EGLDisplay old_eglDisplay = eglGetCurrentDisplay();
// save the EGL state before we change it, so we can switch back later
EGLContext old_eglContext = eglGetCurrentContext();
EGLSurface old_read_surface = eglGetCurrentSurface(EGL_READ);
EGLSurface old_draw_surface = eglGetCurrentSurface(EGL_DRAW);
bool result = eglMakeCurrent(eglDisplay, render_priv->eglSurface, render_priv->eglSurface, render_priv->eglContext);
check_egl_error();
// bind the framebuffer that we are rendering into
check_gl_error();
glBindFramebuffer(GL_FRAMEBUFFER, render_priv->FramebufferName);
check_gl_error();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, render_priv->renderedTexture, 0);
check_gl_error();
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
fprintf(stderr, "Error: glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE\n");
d_printf("OpenGL version before calling onDrawFrame: >%s<\n", glGetString(GL_VERSION));
d_printf("\n\n\n---- calling onDrawFrame\n\n");
// this marks the part where the app is doing the rendering (as opposed to Gtk) for easier orientation in a trace (e.g apitrace)
// TODO: make a program that extracts just these fragments from a trace
// TODO: add a unique identifier of this GLArea (worst case the pointer to this widget)
check_gl_error();
___GL_TRACE___("---- calling onDrawFrame");
// Here we call the app's onDrawFrame callback. This is the android API's equivalent of the `render` callback that we are currently in.
(*env)->CallVoidMethod(env, d->renderer, handle_cache.renderer.onDrawFrame, NULL); // FIXME passing NULL only works if the app doesn't use this parameter
if((*env)->ExceptionCheck(env))
(*env)->ExceptionDescribe(env);
___GL_TRACE___("---- returned from calling onDrawFrame");
check_gl_error();
d_printf("\n---- returned from calling onDrawFrame\n\n\n\n");
eglSwapBuffers(eglDisplay, render_priv->eglSurface);
// switch the EGL context back to Gtk's one
result = eglMakeCurrent(old_eglDisplay, old_read_surface, old_draw_surface, old_eglContext);
check_egl_error();
gtk_gl_area_make_current(gl_area);
d_printf("OpenGL version after restore: >%s<\n", glGetString(GL_VERSION));
d_printf("\n\n\n---- drawing the texture containing our frame\n\n");
___GL_TRACE___("---- drawing the texture containing our frame");
// draw on a black background (TODO: isn't this pointless?)
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// draw two triangles (a rectangle) painted with the texture that we were rendering into
glUseProgram(render_priv->program);
glBindVertexArray(render_priv->vao);
glActiveTexture(GL_TEXTURE0 + render_priv->texUnit);
glBindTexture(GL_TEXTURE_2D, render_priv->texBufferdObject);
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, render_priv->egl_image);
glBindSampler(render_priv->texUnit, render_priv->sampler);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
glUseProgram(0);
___GL_TRACE___("---- end of drawing the texture containing our frame");
d_printf("\n---- end of drawing the texture containing our frame\n\n\n\n");
return TRUE;
}
struct jni_callback_data { JavaVM *jvm; jobject this; jclass this_class; };
static void call_ontouch_callback(int action, float x, float y, struct jni_callback_data *d)
{
JNIEnv *env;
(*d->jvm)->GetEnv(d->jvm, (void**)&env, JNI_VERSION_1_6);
jobject motion_event = (*env)->NewObject(env, handle_cache.motion_event.class, handle_cache.motion_event.constructor, action, x, y);
(*env)->CallBooleanMethod(env, d->this, handle_cache.gl_surface_view.onTouchEvent, motion_event);
if((*env)->ExceptionCheck(env))
(*env)->ExceptionDescribe(env);
(*env)->DeleteLocalRef(env, motion_event);
}
static gboolean on_event(GtkEventControllerLegacy* self, GdkEvent* event, struct jni_callback_data *d)
{
double x;
double y;
// TODO: this doesn't work for multitouch
switch(gdk_event_get_event_type(event)) {
case GDK_BUTTON_PRESS:
gdk_event_get_position(event, &x, &y);
call_ontouch_callback(MOTION_EVENT_ACTION_DOWN, (float)x, (float)y, d);
break;
case GDK_BUTTON_RELEASE:
gdk_event_get_position(event, &x, &y);
call_ontouch_callback(MOTION_EVENT_ACTION_UP, (float)x, (float)y, d);
break;
case GDK_MOTION_NOTIFY:
gdk_event_get_position(event, &x, &y);
call_ontouch_callback(MOTION_EVENT_ACTION_MOVE, (float)x, (float)y, d);
break;
}
}
extern gboolean tick_callback(GtkWidget* widget, GdkFrameClock* frame_clock, gpointer user_data);
JNIEXPORT void JNICALL Java_android_opengl_GLSurfaceView_native_1set_1renderer(JNIEnv *env, jobject this, jobject renderer, jboolean implements_onTouchEvent)
{
GtkWidget *gl_area = GTK_WIDGET(_PTR(_GET_LONG_FIELD(this, "widget")));
gtk_gl_area_set_has_stencil_buffer(GTK_GL_AREA(gl_area), true); // FIXME don't assume what the app wants
gtk_gl_area_set_has_depth_buffer(GTK_GL_AREA(gl_area), true);
gtk_gl_area_set_use_es(GTK_GL_AREA(gl_area), true); // FIXME
struct render_priv *render_priv = malloc(sizeof(struct render_priv));
render_priv->texUnit = 0;
render_priv->sampler = 0;
render_priv->FramebufferName = 0;
g_object_set_data(G_OBJECT(gl_area), "render_priv", render_priv);
JavaVM *jvm;
(*env)->GetJavaVM(env, &jvm);
struct jni_gl_callback_data *gl_callback_data = malloc(sizeof(struct jni_gl_callback_data));
gl_callback_data->jvm = jvm;
gl_callback_data->this = _REF(this);
gl_callback_data->renderer = _REF(renderer);
gl_callback_data->first_time = 1;
g_signal_connect(gl_area, "render", G_CALLBACK(render), gl_callback_data);
g_signal_connect(gl_area, "realize", G_CALLBACK(on_realize), gl_callback_data);
if(implements_onTouchEvent) {
struct jni_callback_data *callback_data = malloc(sizeof(struct jni_callback_data));
callback_data->jvm = jvm;
callback_data->this = _REF(this);
callback_data->this_class = _REF(_CLASS(this));
printf("callback_data->jvm: %p\n", callback_data->jvm);
GtkEventController *controller = gtk_event_controller_legacy_new();
gtk_widget_add_controller(gl_area, controller);
g_signal_connect(controller, "event", G_CALLBACK(on_event), callback_data);
printf("GREP FOR MEEEE -- //FIXME\n");
}
gtk_widget_add_tick_callback(gl_area, tick_callback, NULL, NULL);
//FIXME
gtk_widget_set_hexpand(gtk_widget_get_parent(GTK_WIDGET(gl_area)), true);
}

View File

@@ -0,0 +1,103 @@
#include <gtk/gtk.h>
#include "../defines.h"
#include "../util.h"
#include "WrapperWidget.h"
#include "../generated_headers/android_widget_LinearLayout.h"
#include "../generated_headers/android_view_ViewGroup.h"
G_DECLARE_FINAL_TYPE (FrameLayoutWidget, frame_layout_widget, FRAME_LAYOUT, WIDGET, GtkWidget)
struct _FrameLayoutWidget
{
GtkWidget parent_instance;
};
struct _FrameLayoutWidgetClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE(FrameLayoutWidget, frame_layout_widget, GTK_TYPE_WIDGET)
static void frame_layout_widget_init (FrameLayoutWidget *frame_layout)
{
}
static void frame_layout_widget_dispose(GObject *frame_layout)
{
GtkWidget *child;
while((child = gtk_widget_get_first_child(GTK_WIDGET(frame_layout))) != NULL) {
gtk_widget_unparent(child);
}
G_OBJECT_CLASS (frame_layout_widget_parent_class)->dispose (frame_layout);
}
static void frame_layout_widget_class_init(FrameLayoutWidgetClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->dispose = frame_layout_widget_dispose;
gtk_widget_class_set_layout_manager_type(widget_class, GTK_TYPE_BIN_LAYOUT);
}
GtkWidget * frame_layout_widget_new (void)
{
return g_object_new (frame_layout_widget_get_type(), NULL);
}
void frame_layout_widget_insert_child(FrameLayoutWidget *parent, GtkWidget *child)
{
printf("::::::::::: FrameLayoutWidget: inserting something at the end of the widget list\n");
gtk_widget_insert_before(child, GTK_WIDGET(parent), NULL);
}
void frame_layout_widget_insert_child_at_index(FrameLayoutWidget *parent, GtkWidget *child, int index)
{
printf("::::::::::: FrameLayoutWidget: inserting something at index %d\n", index);
GtkWidget *iter = gtk_widget_get_first_child(GTK_WIDGET(parent));
GtkWidget *next = NULL;
for(int i = 0; i < index; i++) {
next = gtk_widget_get_next_sibling(iter);
if(next == NULL)
break;
iter = next;
}
gtk_widget_insert_before(child, GTK_WIDGET(parent), iter);
}
// ---
JNIEXPORT void JNICALL Java_android_widget_FrameLayout_native_1constructor__Landroid_util_AttributeSet_2(JNIEnv *env, jobject this, jobject attrs)
{
GtkWidget *wrapper = wrapper_widget_new();
GtkWidget *frame_layout = frame_layout_widget_new();
wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), frame_layout);
gtk_widget_set_name(GTK_WIDGET(frame_layout), "FrameLayout");
_SET_LONG_FIELD(this, "widget", _INTPTR(frame_layout));
}
JNIEXPORT void JNICALL Java_android_widget_FrameLayout_native_1constructor__Landroid_content_Context_2(JNIEnv *env, jobject this, jobject context) {
GtkWidget *wrapper = wrapper_widget_new();
GtkWidget *frame_layout = frame_layout_widget_new();
wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), frame_layout);
gtk_widget_set_name(GTK_WIDGET(frame_layout), "FrameLayout");
_SET_LONG_FIELD(this, "widget", _INTPTR(frame_layout));
}
JNIEXPORT void JNICALL Java_android_widget_FrameLayout_addView(JNIEnv *env, jobject this, jobject child, jint index, jobject layout_params)
{
Java_android_view_ViewGroup_addView(env, this, child, index, layout_params);
if(index >= 0)
frame_layout_widget_insert_child_at_index(FRAME_LAYOUT_WIDGET(_PTR(_GET_LONG_FIELD(this, "widget"))), gtk_widget_get_parent(GTK_WIDGET(_PTR(_GET_LONG_FIELD(child, "widget")))), index);
else
frame_layout_widget_insert_child(FRAME_LAYOUT_WIDGET(_PTR(_GET_LONG_FIELD(this, "widget"))), gtk_widget_get_parent(GTK_WIDGET(_PTR(_GET_LONG_FIELD(child, "widget")))));
}

View File

@@ -0,0 +1,24 @@
#include <gtk/gtk.h>
#include "../defines.h"
#include "../util.h"
#include "WrapperWidget.h"
#include "../generated_headers/android_widget_ImageView.h"
JNIEXPORT void JNICALL Java_android_widget_ImageView_native_1constructor__Landroid_util_AttributeSet_2(JNIEnv *env, jobject this, jobject attrs)
{
GtkWidget *wrapper = wrapper_widget_new();
GtkWidget *image = gtk_image_new_from_icon_name("FIXME"); // will not actually use gtk_image_new_from_icon_name when implementing this, but we want that nice "broken image" icon
wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), image);
_SET_LONG_FIELD(this, "widget", _INTPTR(image));}
JNIEXPORT void JNICALL Java_android_widget_ImageView_native_1constructor__Landroid_content_Context_2(JNIEnv *env, jobject this, jobject context)
{
GtkWidget *wrapper = wrapper_widget_new();
GtkWidget *image = gtk_image_new_from_icon_name("FIXME"); // will not actually use gtk_image_new_from_icon_name when implementing this, but we want that nice "broken image" icon
wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), image);
_SET_LONG_FIELD(this, "widget", _INTPTR(image));
}

View File

@@ -0,0 +1,67 @@
#include <gtk/gtk.h>
#include "../defines.h"
#include "../util.h"
#include "WrapperWidget.h"
#include "../drawables/ninepatch.h"
#include "../generated_headers/android_widget_LinearLayout.h"
#include "../generated_headers/android_view_ViewGroup.h"
JNIEXPORT void JNICALL Java_android_widget_LinearLayout_native_1constructor__Landroid_util_AttributeSet_2(JNIEnv *env, jobject this, jobject attrs)
{
int orientation = attribute_set_get_int(env, attrs, "orientation", NULL, 0);
GtkWidget *wrapper = wrapper_widget_new();
GtkWidget *box = gtk_box_new(orientation ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL, 1); // spacing of 1
wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), box);
gtk_widget_set_name(GTK_WIDGET(box), "LinearLayout");
_SET_LONG_FIELD(this, "widget", _INTPTR(box));
}
JNIEXPORT void JNICALL Java_android_widget_LinearLayout_native_1constructor__Landroid_content_Context_2(JNIEnv *env, jobject this, jobject context) {
GtkWidget *wrapper = wrapper_widget_new();
GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); // spacing of 0
wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), box);
gtk_widget_set_name(GTK_WIDGET(box), "LinearLayout");
gtk_widget_set_hexpand_set(box, true); // FIXME: to counteract expand on drawing areas
gtk_widget_set_vexpand_set(box, true); // XXX
_SET_LONG_FIELD(this, "widget", _INTPTR(box));
// struct ninepatch_t *ninepatch = ninepatch_new("/home/Mis012/Github_and_other_sources/org.happysanta.gd_29_src.tar.gz/res/drawable-mdpi/btn_br_down.9.png");
// g_object_set_data(G_OBJECT(wrapper), "background_ninepatch", ninepatch);
}
JNIEXPORT void JNICALL Java_android_widget_LinearLayout_addView(JNIEnv *env, jobject this, jobject child, jint index, jobject layout_params)
{
Java_android_view_ViewGroup_addView(env, this, child, index, layout_params);
gtk_box_append(GTK_BOX(_PTR(_GET_LONG_FIELD(this, "widget"))), gtk_widget_get_parent(GTK_WIDGET(_PTR(_GET_LONG_FIELD(child, "widget"))))); // FIXME - ignores index argument
}
JNIEXPORT void JNICALL Java_android_widget_LinearLayout_removeView(JNIEnv *env, jobject this, jobject child)
{
Java_android_view_ViewGroup_removeView(env, this, child);
gtk_box_remove(GTK_BOX(_PTR(_GET_LONG_FIELD(this, "widget"))), gtk_widget_get_parent(GTK_WIDGET(_PTR(_GET_LONG_FIELD(child, "widget")))));
}
JNIEXPORT void JNICALL Java_android_widget_LinearLayout_removeAllViews(JNIEnv *env, jobject this)
{
Java_android_view_ViewGroup_removeAllViews(env, this);
GtkBox *box = GTK_BOX(_PTR(_GET_LONG_FIELD(this, "widget")));
GtkWidget *child;
while((child = gtk_widget_get_first_child(GTK_WIDGET(box))) != NULL) {
gtk_box_remove(box, child);
}
}
JNIEXPORT void JNICALL Java_android_widget_LinearLayout_setOrientation(JNIEnv *env, jobject this, jint orientation)
{
gtk_orientable_set_orientation(GTK_ORIENTABLE(_PTR(_GET_LONG_FIELD(this, "widget"))), orientation ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL);
}

View File

@@ -0,0 +1,37 @@
#include <gtk/gtk.h>
#include "../defines.h"
#include "../util.h"
#include "WrapperWidget.h"
#include "../generated_headers/android_widget_RelativeLayout.h"
#include "../generated_headers/android_view_ViewGroup.h"
// FIXME not a relative layout
JNIEXPORT void JNICALL Java_android_widget_RelativeLayout_native_1constructor__Landroid_util_AttributeSet_2(JNIEnv *env, jobject this, jobject attrs)
{
int orientation = attribute_set_get_int(env, attrs, "orientation", NULL, 0);
GtkWidget *wrapper = wrapper_widget_new();
GtkWidget *box = gtk_box_new(orientation ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL, 1); // spacing of 1
wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), box);
gtk_widget_set_name(GTK_WIDGET(box), "RelativeLayout");
_SET_LONG_FIELD(this, "widget", _INTPTR(box));
}
JNIEXPORT void JNICALL Java_android_widget_RelativeLayout_native_1constructor__Landroid_content_Context_2(JNIEnv *env, jobject this, jobject context) {
GtkWidget *wrapper = wrapper_widget_new();
GtkWidget *box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 1); // spacing of 1
wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), box);
gtk_widget_set_name(GTK_WIDGET(box), "RelativeLayout");
_SET_LONG_FIELD(this, "widget", _INTPTR(box));
}
JNIEXPORT void JNICALL Java_android_widget_RelativeLayout_addView(JNIEnv *env, jobject this, jobject child, jint index, jobject layout_params)
{
Java_android_view_ViewGroup_addView(env, this, child, index, layout_params);
gtk_box_append(GTK_BOX(_PTR(_GET_LONG_FIELD(this, "widget"))), gtk_widget_get_parent(GTK_WIDGET(_PTR(_GET_LONG_FIELD(child, "widget")))));
}

View File

@@ -0,0 +1,60 @@
#include <gtk/gtk.h>
#include "../defines.h"
#include "../util.h"
#include "WrapperWidget.h"
#include "../generated_headers/android_widget_ScrollView.h"
#include "../generated_headers/android_view_ViewGroup.h"
// FIXME not a scrollview
JNIEXPORT void JNICALL Java_android_widget_ScrollView_native_1constructor__Landroid_util_AttributeSet_2(JNIEnv *env, jobject this, jobject attrs)
{
int orientation = attribute_set_get_int(env, attrs, "orientation", NULL, 0);
GtkWidget *wrapper = wrapper_widget_new();
GtkWidget *box = gtk_box_new(orientation ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL, 1); // spacing of 1
wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), box);
gtk_widget_set_name(GTK_WIDGET(box), "ScrollView");
_SET_LONG_FIELD(this, "widget", _INTPTR(box));
}
JNIEXPORT void JNICALL Java_android_widget_ScrollView_native_1constructor__Landroid_content_Context_2(JNIEnv *env, jobject this, jobject context) {
GtkWidget *wrapper = wrapper_widget_new();
GtkWidget *box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 1); // spacing of 1
wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), box);
gtk_widget_set_name(GTK_WIDGET(box), "ScrollView");
_SET_LONG_FIELD(this, "widget", _INTPTR(box));
}
JNIEXPORT void JNICALL Java_android_widget_ScrollView_removeView(JNIEnv *env, jobject this, jobject child)
{
Java_android_view_ViewGroup_removeView(env, this, child);
GtkWidget *_child = gtk_widget_get_parent(GTK_WIDGET(_PTR(_GET_LONG_FIELD(child, "widget"))));
gtk_box_remove(GTK_BOX(_PTR(_GET_LONG_FIELD(this, "widget"))), g_object_ref(_child));
g_object_force_floating(G_OBJECT(_child));
}
JNIEXPORT void JNICALL Java_android_widget_ScrollView_removeAllViews(JNIEnv *env, jobject this)
{
Java_android_view_ViewGroup_removeAllViews(env, this);
GtkBox *box = GTK_BOX(_PTR(_GET_LONG_FIELD(this, "widget")));
GtkWidget *child;
while((child = gtk_widget_get_first_child(GTK_WIDGET(box))) != NULL) {
gtk_box_remove(box, g_object_ref(child));
g_object_force_floating(G_OBJECT(child));
}
}
JNIEXPORT void JNICALL Java_android_widget_ScrollView_addView(JNIEnv *env, jobject this, jobject child, jint index, jobject layout_params)
{
Java_android_view_ViewGroup_addView(env, this, child, index, layout_params);
gtk_box_append(GTK_BOX(_PTR(_GET_LONG_FIELD(this, "widget"))), gtk_widget_get_parent(GTK_WIDGET(_PTR(_GET_LONG_FIELD(child, "widget")))));
}

View File

@@ -0,0 +1,65 @@
#include <gtk/gtk.h>
#include "../defines.h"
#include "../util.h"
#include "WrapperWidget.h"
#include "../generated_headers/android_widget_TextView.h"
JNIEXPORT void JNICALL Java_android_widget_TextView_native_1constructor__Landroid_util_AttributeSet_2(JNIEnv *env, jobject this, jobject attrs)
{
const char *text = attribute_set_get_string(env, attrs, "text", NULL);
// _SET_OBJ_FIELD(this, "text", "Ljava/lang/String;", _JSTRING(text)); //TODO: sadly this might be needed, but it's not atm
GtkWidget *wrapper = wrapper_widget_new();
GtkWidget *label = gtk_label_new(text);
wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), label);
_SET_LONG_FIELD(this, "widget", _INTPTR(label));
}
JNIEXPORT void JNICALL Java_android_widget_TextView_native_1constructor__Landroid_content_Context_2(JNIEnv *env, jobject this, jobject attrs)
{
// _SET_OBJ_FIELD(this, "text", "Ljava/lang/String;", _JSTRING(text)); //TODO: sadly this might be needed, but it's not atm
GtkWidget *wrapper = wrapper_widget_new();
GtkWidget *label = gtk_label_new("FIXME");
wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), label);
_SET_LONG_FIELD(this, "widget", _INTPTR(label));
}
JNIEXPORT void JNICALL Java_android_widget_TextView_native_1setText(JNIEnv *env, jobject this, jobject charseq)
{
// _SET_OBJ_FIELD(this, "text", "Ljava/lang/String;", charseq); //TODO: sadly this might be needed, but it's not atm
gtk_label_set_text(GTK_LABEL(_PTR(_GET_LONG_FIELD(this, "widget"))), _CSTRING(charseq));
}
JNIEXPORT void JNICALL Java_android_widget_TextView_setTextSize(JNIEnv *env, jobject this, jfloat size)
{
GtkLabel *label = GTK_LABEL(_PTR(_GET_LONG_FIELD(this, "widget")));
PangoAttrList *attrs;
PangoAttrList *old_attrs = gtk_label_get_attributes(label);
if(old_attrs)
attrs = pango_attr_list_copy(old_attrs);
else
attrs = pango_attr_list_new();
PangoAttribute *size_attr = pango_attr_size_new(size * PANGO_SCALE);
pango_attr_list_change(attrs, size_attr);
gtk_label_set_attributes(label, attrs);
pango_attr_list_unref(attrs);
}
JNIEXPORT void JNICALL Java_android_widget_TextView_native_1set_1markup(JNIEnv *env, jobject this, jint value)
{
GtkLabel *label = GTK_LABEL(_PTR(_GET_LONG_FIELD(this, "widget")));
printf("weeeheee!\n");
gtk_label_set_use_markup(label, value);
printf("gtk_label_get_use_markup: %d, >%s<\n", gtk_label_get_use_markup(label), gtk_label_get_text(label));
}