Mercurial > audlegacy-plugins
view src/projectm-1.0/main.cxx @ 2402:ace0b59f541a
First steps on GTK+ based projectM plugin.
TODO:
* Turn this into a proper GTK+ widget (possibly as something like libGTKprojectM).
* Add resize handlers.
* Add option to hook into keyboard events maybe.
author | William Pitcock <nenolod@atheme.org> |
---|---|
date | Mon, 18 Feb 2008 00:09:38 -0600 |
parents | ff0a27216c6a |
children | 3528a910a034 |
line wrap: on
line source
/* * main.cxx: plugin glue to libprojectm * Copyright (c) 2008 William Pitcock <nenolod@sacredspiral.co.uk> * Portions copyright (c) 2004-2006 Peter Sperl * * This program is free software; you may distribute it under the terms * of the GNU General Public License; version 2. */ #include <stdio.h> #include <string.h> #include <string> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <gtk/gtk.h> #include <gtk/gtkgl.h> extern "C" { #include <audacious/util.h> #include <audacious/plugin.h> #include <audacious/playlist.h> #include <audacious/auddrct.h> } #include <math.h> #include "ConfigFile.h" #include <libprojectM/projectM.hpp> #include <GL/gl.h> #define CONFIG_FILE "/share/projectM/config.inp" // Forward declarations extern "C" void projectM_xmms_init(void); extern "C" void projectM_cleanup(void); extern "C" void projectM_render_pcm(gint16 pcm_data[2][512]); extern "C" int worker_func(void *); std::string read_config(); extern "C" VisPlugin projectM_vtable; int SDLThreadWrapper(void *); void handle_playback_trigger(void *, void *); static void projectM_draw_init(GtkWidget *widget, void *data); static gboolean projectM_idle_func(GtkWidget *widget); static gboolean projectM_draw_impl(GtkWidget *widget, GdkEventExpose *event, gpointer data); class projectMPlugin { public: projectM *pm; GdkGLConfig *glconfig; GtkWidget *window; GtkWidget *vbox; GtkWidget *drawing_area; gboolean is_sync; gboolean error; gint idle_id; projectMPlugin() { gtk_gl_init(NULL, NULL); this->pm = NULL; this->glconfig = gdk_gl_config_new_by_mode((GdkGLConfigMode) (GDK_GL_MODE_RGBA | GDK_GL_MODE_DEPTH | GDK_GL_MODE_DOUBLE)); if (!this->glconfig) { this->error++; return; } this->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(this->window), "ProjectM"); gtk_container_set_reallocate_redraws(GTK_CONTAINER(this->window), TRUE); this->vbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(this->window), this->vbox); gtk_widget_show(this->vbox); this->drawing_area = gtk_drawing_area_new(); gtk_widget_set_size_request(this->drawing_area, 512, 512); gtk_widget_set_gl_capability(this->drawing_area, this->glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE); gtk_widget_add_events(this->drawing_area, GDK_VISIBILITY_NOTIFY_MASK); gtk_box_pack_start(GTK_BOX(this->vbox), this->drawing_area, TRUE, TRUE, 0); g_signal_connect(G_OBJECT(this->drawing_area), "realize", G_CALLBACK(projectM_draw_init), NULL); g_signal_connect(G_OBJECT(this->drawing_area), "expose_event", G_CALLBACK(projectM_draw_impl), NULL); } ~projectMPlugin() { delete this->pm; this->pm = 0; aud_hook_dissociate("playback begin", handle_playback_trigger); } void initUI(void) { gtk_widget_show(this->drawing_area); gtk_widget_show(this->window); this->idle_id = g_idle_add_full (GDK_PRIORITY_REDRAW, (GSourceFunc) projectM_idle_func, this->drawing_area, NULL); /* XXX */ aud_hook_associate("playback begin", handle_playback_trigger, NULL); } void addPCMData(gint16 pcm_data[2][512]) { if (this->pm) this->pm->pcm->addPCM16(pcm_data); } void triggerPlaybackBegin(PlaylistEntry *entry) { std::string title(entry->title); if (this->pm) this->pm->projectM_setTitle(title); } }; /* glue to implementation section */ projectMPlugin *thePlugin = 0; static void projectM_draw_init(GtkWidget *widget, void *data) { GdkGLContext *glcontext = gtk_widget_get_gl_context(widget); GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(widget); if (!gdk_gl_drawable_gl_begin(gldrawable, glcontext)) return; std::string configFile = read_config(); thePlugin->pm = new projectM(configFile); thePlugin->pm->projectM_resetGL(widget->allocation.width, widget->allocation.height); gdk_gl_drawable_swap_buffers(gldrawable); gdk_gl_drawable_gl_end(gldrawable); } static gboolean projectM_draw_impl(GtkWidget *widget, GdkEventExpose *event, gpointer data) { GdkGLContext *glcontext = gtk_widget_get_gl_context(widget); GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(widget); if (!gdk_gl_drawable_gl_begin(gldrawable, glcontext)) return FALSE; thePlugin->pm->renderFrame(); gdk_gl_drawable_swap_buffers(gldrawable); gdk_gl_drawable_gl_end(gldrawable); return TRUE; } static gboolean projectM_idle_func(GtkWidget *widget) { gdk_window_invalidate_rect(widget->window, &widget->allocation, FALSE); gdk_window_process_updates(widget->window, FALSE); return TRUE; } void handle_playback_trigger(gpointer plentry_p, gpointer unused) { PlaylistEntry *entry = reinterpret_cast<PlaylistEntry *>(plentry_p); if (!thePlugin) return; thePlugin->triggerPlaybackBegin(entry); } extern "C" void projectM_xmms_init(void) { if (thePlugin) return; thePlugin = new projectMPlugin; thePlugin->initUI(); } extern "C" void projectM_cleanup(void) { if (!thePlugin) return; delete thePlugin; } extern "C" void projectM_render_pcm(gint16 pcm_data[2][512]) { if (!thePlugin) return; thePlugin->addPCMData(pcm_data); } /******************************************************************************** * XXX: This code is from projectM and still needs to be rewritten! * ********************************************************************************/ std::string read_config() { // int n; char num[512]; FILE *in; FILE *out; char *home; char projectM_home[1024]; char projectM_config[1024]; strcpy(projectM_config, PROJECTM_PREFIX); strcpy(projectM_config + strlen(PROJECTM_PREFIX), CONFIG_FILE); projectM_config[strlen(PROJECTM_PREFIX) + strlen(CONFIG_FILE)] = '\0'; //printf("dir:%s \n",projectM_config); home = getenv("HOME"); strcpy(projectM_home, home); strcpy(projectM_home + strlen(home), "/.projectM/config.inp"); projectM_home[strlen(home) + strlen("/.projectM/config.inp")] = '\0'; if ((in = fopen(projectM_home, "r")) != 0) { //printf("reading ~/.projectM/config.inp \n"); fclose(in); return std::string(projectM_home); } else { printf("trying to create ~/.projectM/config.inp \n"); strcpy(projectM_home, home); strcpy(projectM_home + strlen(home), "/.projectM"); projectM_home[strlen(home) + strlen("/.projectM")] = '\0'; mkdir(projectM_home, 0755); strcpy(projectM_home, home); strcpy(projectM_home + strlen(home), "/.projectM/config.inp"); projectM_home[strlen(home) + strlen("/.projectM/config.inp")] = '\0'; if ((out = fopen(projectM_home, "w")) != 0) { if ((in = fopen(projectM_config, "r")) != 0) { while (fgets(num, 80, in) != NULL) { fputs(num, out); } fclose(in); fclose(out); if ((in = fopen(projectM_home, "r")) != 0) { printf("created ~/.projectM/config.inp successfully\n"); fclose(in); return std::string(projectM_home); } else { printf("This shouldn't happen, using implementation defualts\n"); abort(); } } else { printf("Cannot find projectM default config, using implementation defaults\n"); abort(); } } else { printf("Cannot create ~/.projectM/config.inp, using default config file\n"); if ((in = fopen(projectM_config, "r")) != 0) { printf("Successfully opened default config file\n"); fclose(in); return std::string(projectM_config); } else { printf("Using implementation defaults, your system is really messed up, I'm suprised we even got this far\n"); abort(); } } } abort(); }