From 80520e51c618c62e4a928d24fb43f0fdfbbe3842 Mon Sep 17 00:00:00 2001 From: Maximilian Mader Date: Wed, 25 Sep 2019 22:47:33 +0200 Subject: [PATCH] [GTK3] Prototype rendering of tilemap and tileset --- gtk3/main.c | 160 ++++++++++++++++++++++++----- gtk3/resources/gtk/menus-common.ui | 152 +++++++++++++-------------- gtk3/resources/ui/window.ui | 60 +++++------ 3 files changed, 242 insertions(+), 130 deletions(-) diff --git a/gtk3/main.c b/gtk3/main.c index 105a837..43ea4bc 100644 --- a/gtk3/main.c +++ b/gtk3/main.c @@ -29,8 +29,14 @@ static void run(UserData *user_data); static GtkApplication *main_application; static GtkBuilder *builder; -static GtkApplicationWindow *main_window; static GtkGLArea *gl_area; + +static GtkApplicationWindow *main_window; +static GtkWindow *vram_viewer; +static GtkWindow *memory_viewer; +static GtkWindow *console; +static GtkWindow *printer; + static shader_t shader; static GB_gameboy_t gb; @@ -42,9 +48,20 @@ static bool underclock_down = false, rewind_down = false, do_rewind = false, rew static double clock_mutliplier = 1.0; static char *battery_save_path_ptr; static Rect rect; - +static bool vram_viewer_visible = false; static bool running = true; +static const size_t tileset_buffer_length = 256 * 192 * 4; +static uint32_t tileset_buffer[tileset_buffer_length] = {0}; + +static const size_t tilemap_buffer_length = 256 * 256 * 4; +static uint32_t tilemap_buffer[tilemap_buffer_length] = {0}; + +// Returns a GObject by ID from our GtkBuilder instance +static GObject *get_object(gchararray id) { + return gtk_builder_get_object(builder, id); +} + static unsigned char number_of_buffers(void) { bool should_blend = true; @@ -85,6 +102,15 @@ static void vblank(GB_gameboy_t *gb) { // Queue drawing of the current frame gtk_gl_area_queue_render(gl_area); + + if (vram_viewer_visible) { + // TODO: Only update what is needed + GB_draw_tileset(gb, tileset_buffer, GB_PALETTE_NONE, 0); + GB_draw_tilemap(gb, tilemap_buffer, GB_PALETTE_AUTO, 0, GB_MAP_AUTO, GB_TILESET_AUTO); + + // Queue a redraw of the VRAM viewer + gtk_widget_queue_draw(GTK_WIDGET(vram_viewer)); + } while (gtk_events_pending()) { gtk_main_iteration(); @@ -158,17 +184,18 @@ static void set_combo_box_row_separator_func(GtkContainer *container) { // Returns true if the application should show a menubar static gboolean show_menubar(void) { - GtkSettings *settings = gtk_settings_get_default(); - gboolean result; + switch (get_show_menubar()) { + case MENUBAR_AUTO: { + GtkSettings *settings = gtk_settings_get_default(); + gboolean result; - g_object_get(settings, "gtk-shell-shows-menubar", &result, NULL); + g_object_get(settings, "gtk-shell-shows-menubar", &result, NULL); - return result; -} - -// Returns a GObject by ID from our GtkBuilder instance -static GObject *get_object(gchararray id) { - return gtk_builder_get_object(builder, id); + return result; + } + case MENUBAR_SHOW: return true; + case MENUBAR_HIDE: return false; + } } // Returns a `GApplication`s `GMenuModel` by ID @@ -212,12 +239,26 @@ static void activate_preferences(GSimpleAction *action, GVariant *parameter, gpo gtk_widget_show_all(GTK_WIDGET(get_object("preferences"))); } +// app.open_vram_viewer GAction +// Opens the VRAM viewer window +static void activate_open_vram_viewer(GSimpleAction *action, GVariant *parameter, gpointer user_data) { + gtk_widget_show_all(GTK_WIDGET(vram_viewer)); +} + +// app.open_memory_viewer GAction +// Opens the memory viewer window +static void activate_open_memory_viewer(GSimpleAction *action, GVariant *parameter, gpointer user_data) { + gtk_widget_show_all(GTK_WIDGET(memory_viewer)); +} + // List of GActions for the `app` prefix static GActionEntry app_entries[] = { { "quit", activate_quit, NULL, NULL, NULL }, { "about", activate_about, NULL, NULL, NULL }, { "open_gtk_debugger", activate_open_gtk_debugger, NULL, NULL, NULL }, { "preferences", activate_preferences, NULL, NULL, NULL }, + { "open_vram_viewer", activate_open_vram_viewer, NULL, NULL, NULL }, + { "open_memory_viewer", activate_open_memory_viewer, NULL, NULL, NULL }, }; G_MODULE_EXPORT void on_quit(GtkWidget *w, gpointer app) { @@ -228,12 +269,6 @@ G_MODULE_EXPORT void on_show_window(GtkWidget *w, gpointer window) { gtk_widget_show_all(GTK_WIDGET(window)); } -G_MODULE_EXPORT void on_boot_rom_location_changed(GtkWidget *w, gpointer user_data_gptr) { - GtkComboBox *box = GTK_COMBO_BOX(w); - - g_print("Active: %s", gtk_combo_box_get_active_id(box)); -} - G_MODULE_EXPORT void gl_init() { const char *renderer; @@ -260,12 +295,66 @@ G_MODULE_EXPORT void gl_draw() { G_MODULE_EXPORT void gl_finish() { } +G_MODULE_EXPORT void on_vram_viewer_realize(gpointer visible) { + vram_viewer_visible = true; +} + +G_MODULE_EXPORT void on_vram_viewer_unrealize(gpointer visible) { + vram_viewer_visible = false; +} + +G_MODULE_EXPORT gboolean on_draw_vram_viewer_tileset(GtkWidget *widget, cairo_t *cr, gpointer data) { + guint width, height; + GtkStyleContext *context; + + context = gtk_widget_get_style_context(widget); + width = gtk_widget_get_allocated_width(widget); + height = gtk_widget_get_allocated_height(widget); + + gtk_render_background(context, cr, 0, 0, width, height); + + cairo_surface_t *surface = cairo_image_surface_create_for_data( + (unsigned char *) tileset_buffer, + CAIRO_FORMAT_RGB24, + 256, + 192, + cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, 256) + ); + + cairo_set_source_surface(cr, surface, 0, 0); + cairo_paint(cr); + + return FALSE; +} + +G_MODULE_EXPORT gboolean on_vram_viewer_tilemap(GtkWidget *widget, cairo_t *cr, gpointer data) { + guint width, height; + GtkStyleContext *context; + + context = gtk_widget_get_style_context(widget); + width = gtk_widget_get_allocated_width(widget); + height = gtk_widget_get_allocated_height(widget); + + gtk_render_background(context, cr, 0, 0, width, height); + + cairo_surface_t *surface = cairo_image_surface_create_for_data( + (unsigned char *) tilemap_buffer, + CAIRO_FORMAT_RGB24, + 256, + 256, + cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, 256) + ); + + cairo_set_source_surface(cr, surface, 0, 0); + cairo_paint(cr); + + return FALSE; +} + // This functions gets called immediately after registration of the GApplication static void startup(GApplication *app, gpointer user_data_gptr) { UserData *user_data = user_data_gptr; - init_settings(user_data->config_path); - builder = gtk_builder_new_from_resource(RESOURCE_PREFIX "ui/window.ui"); gtk_builder_connect_signals(builder, NULL); @@ -274,9 +363,17 @@ static void startup(GApplication *app, gpointer user_data_gptr) { GtkWindow *preferences = GTK_WINDOW(get_object("preferences")); set_combo_box_row_separator_func(GTK_CONTAINER(preferences)); - GtkWindow *vram_viewer = GTK_WINDOW(get_object("vram_viewer")); + init_settings(user_data->config_path, preferences); + + vram_viewer = GTK_WINDOW(get_object("vram_viewer")); set_combo_box_row_separator_func(GTK_CONTAINER(vram_viewer)); + memory_viewer = GTK_WINDOW(get_object("memory_viewer")); + set_combo_box_row_separator_func(GTK_CONTAINER(memory_viewer)); + + console = GTK_WINDOW(get_object("console")); + printer = GTK_WINDOW(get_object("printer")); + // setup main window main_window = GTK_APPLICATION_WINDOW(gtk_application_window_new(GTK_APPLICATION(app))); gtk_application_window_set_show_menubar(main_window, true); @@ -284,11 +381,26 @@ static void startup(GApplication *app, gpointer user_data_gptr) { // create our renderer area gl_area = GTK_GL_AREA(gtk_gl_area_new()); gtk_gl_area_set_auto_render(gl_area, false); - g_signal_connect(gl_area, "realize", G_CALLBACK(gl_init), NULL); - g_signal_connect(gl_area, "render", G_CALLBACK(gl_draw), NULL); - g_signal_connect(gl_area, "resize", G_CALLBACK(gl_resize), NULL); + + // Connect signal handlers + g_signal_connect(gl_area, "realize", G_CALLBACK(gl_init), NULL); + g_signal_connect(gl_area, "render", G_CALLBACK(gl_draw), NULL); + g_signal_connect(gl_area, "resize", G_CALLBACK(gl_resize), NULL); g_signal_connect(gl_area, "unrealize", G_CALLBACK(gl_finish), NULL); + g_signal_connect(vram_viewer, "realize", G_CALLBACK(on_vram_viewer_realize), NULL); + g_signal_connect(vram_viewer, "unrealize", G_CALLBACK(on_vram_viewer_unrealize), NULL); + + // Just hide our sub-windows when closing them + g_signal_connect(preferences, "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL); + g_signal_connect(vram_viewer, "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL); + g_signal_connect(memory_viewer, "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL); + g_signal_connect(console, "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL); + g_signal_connect(printer, "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL); + + g_signal_connect(get_object("vram_viewer_tileset_canvas"), "draw", G_CALLBACK(on_draw_vram_viewer_tileset), NULL); + g_signal_connect(get_object("vram_viewer_tilemap_canvas"), "draw", G_CALLBACK(on_vram_viewer_tilemap), NULL); + gtk_container_add(GTK_CONTAINER(main_window), GTK_WIDGET(gl_area)); // Handle the whole menubar situation … @@ -311,7 +423,7 @@ static void startup(GApplication *app, gpointer user_data_gptr) { gtk_menu_button_set_menu_model(hamburger_button, hamburger_menu); } - gtk_window_set_title(GTK_WINDOW(main_window), "SameBoy v" xstr(VERSION)); + gtk_window_set_title(GTK_WINDOW(main_window), "SameBoy"); // Define a set of window icons GList *icon_list = NULL; diff --git a/gtk3/resources/gtk/menus-common.ui b/gtk3/resources/gtk/menus-common.ui index 5adb447..276a7ef 100644 --- a/gtk3/resources/gtk/menus-common.ui +++ b/gtk3/resources/gtk/menus-common.ui @@ -71,7 +71,7 @@ Author: Maximilian Mader file-section-0 _Open - win.open + app.open Open _Recent @@ -85,7 +85,7 @@ Author: Maximilian Mader file-section-1 Close - win.close + app.close @@ -96,11 +96,11 @@ Author: Maximilian Mader edit-section-0 Undo - win.undo + app.undo Redo - win.redo + app.redo @@ -108,23 +108,23 @@ Author: Maximilian Mader edit-section-1 Cut - win.cut + app.cut Copy - win.copy + app.copy Paste - win.paste + app.paste Delete - win.delete + app.delete Select All - win.select_all + app.select_all @@ -135,23 +135,23 @@ Author: Maximilian Mader find-section-0 Find… - win.find + app.find Find Next - win.find_next + app.find_next Find Previous - win.find_previous + app.find_previous Use Selection for Find - win.find_selection + app.find_selection Jump to Selection - win.jump_selection + app.jump_selection @@ -164,11 +164,11 @@ Author: Maximilian Mader emulation-section-0 Reset - win.reset + app.reset Pause - win.pause + app.pause @@ -178,53 +178,53 @@ Author: Maximilian Mader Save State Slot 1 - 0 - win.save_state + 0 + app.save_state Slot 2 - 1 - win.save_state + 1 + app.save_state Slot 3 - 2 - win.save_state + 2 + app.save_state Slot 4 - 3 - win.save_state + 3 + app.save_state Slot 5 - 4 - win.save_state + 4 + app.save_state Slot 6 - 5 - win.save_state + 5 + app.save_state Slot 7 - 6 - win.save_state + 6 + app.save_state Slot 8 - 7 - win.save_state + 7 + app.save_state Slot 9 - 8 - win.save_state + 8 + app.save_state Slot 10 - 9 - win.save_state + 9 + app.save_state @@ -232,53 +232,53 @@ Author: Maximilian Mader Save State Slot 1 - 0 - win.load_state + 0 + app.load_state Slot 2 - 1 - win.load_state + 1 + app.load_state Slot 3 - 2 - win.load_state + 2 + app.load_state Slot 4 - 3 - win.load_state + 3 + app.load_state Slot 5 - 4 - win.load_state + 4 + app.load_state Slot 6 - 5 - win.load_state + 5 + app.load_state Slot 7 - 6 - win.load_state + 6 + app.load_state Slot 8 - 7 - win.load_state + 7 + app.load_state Slot 9 - 8 - win.load_state + 8 + app.load_state Slot 10 - 9 - win.load_state + 9 + app.load_state @@ -287,22 +287,22 @@ Author: Maximilian Mader emulation-section-2 Game Boy - win.change_model + app.change_model DMG Super Game Boy - win.change_model + app.change_model SGB Game Boy Color - win.change_model + app.change_model CGB Game Boy Advance - win.change_model + app.change_model AGB @@ -311,7 +311,7 @@ Author: Maximilian Mader emulation-section-3 Mute Sound - win.toggle_mute + app.toggle_mute @@ -319,7 +319,7 @@ Author: Maximilian Mader emulation-section-4 Blend Frames - win.toggle_blend_frames + app.toggle_blend_frames @@ -330,13 +330,13 @@ Author: Maximilian Mader connectivity-section-0 None - win.change_serial_device - none + app.change_serial_device + none Game Boy Printer - win.change_serial_device - gb_printer + app.change_serial_device + gb_printer @@ -347,7 +347,7 @@ Author: Maximilian Mader developer-section-0 Developer Mode - win.toggle_developer_mode + app.toggle_developer_mode @@ -355,11 +355,11 @@ Author: Maximilian Mader developer-section-1 Show Console - win.show_console + app.show_console Clear Console - win.clear_console + app.clear_console @@ -367,7 +367,7 @@ Author: Maximilian Mader developer-section-2 Break Debugger - win.break_debugger + app.break_debugger @@ -375,11 +375,11 @@ Author: Maximilian Mader developer-section-3 Show Memory Viewer - win.open_memory_viewer + app.open_memory_viewer Show VRAM Viewer - win.open_vram_viewer + app.open_vram_viewer @@ -398,11 +398,11 @@ Author: Maximilian Mader window-section-0 Minimize - win.minimize + app.minimize Zoom - win.zoom + app.zoom @@ -410,7 +410,7 @@ Author: Maximilian Mader window-section-1 Bring All to Front - win.bring_to_front + app.bring_to_front @@ -421,7 +421,7 @@ Author: Maximilian Mader help-section-0 SameBoy Help - win.help + app.help diff --git a/gtk3/resources/ui/window.ui b/gtk3/resources/ui/window.ui index 44ce981..9072597 100644 --- a/gtk3/resources/ui/window.ui +++ b/gtk3/resources/ui/window.ui @@ -612,24 +612,6 @@ Maximilian Mader https://github.com/max-m 3 - - - Keep Aspect Ratio - True - True - False - 5 - 10 - True - True - - - - False - True - 4 - - Use Integer Scaling @@ -648,6 +630,24 @@ Maximilian Mader https://github.com/max-m 4 + + + Keep Aspect Ratio + True + True + False + 5 + 10 + True + True + + + + False + True + 4 + + 1 @@ -1258,18 +1258,6 @@ Maximilian Mader https://github.com/max-m True False vertical - - - True - True - False - - - False - True - 0 - - True @@ -1384,6 +1372,18 @@ Maximilian Mader https://github.com/max-m False True + 0 + + + + + True + True + False + + + True + True 1