/* XMMS - Cross-platform multimedia player * Copyright (C) 1998-1999 Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies * * Dancing Particules * Copyright (C) 2002 Pierre Tardy * * based on * Bezier Plugin * Copyright (C) 1999 Rick Haines * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include "xmms/xmmsctrl.h" #include "xmms/configfile.h" #include "xmms/plugin.h" #include #include "gl.h" #include "gl_plugin.h" #include #include #include #include #include "etoile.h" #include #include #include #include #include #include typedef struct globs_ { GLint WIDTH; GLint HEIGHT; GLuint effect; GLuint beat; GLuint old_beat; GLuint max_fps; GLuint old_max_fps; GLfloat energy; gboolean paused; gboolean fullscreen; gboolean mouse; gboolean finished; gboolean in_thread; gboolean init; gboolean changement; gboolean freeze; } globs; globs general = { 640, 480, 0, 4, 4, 40, 40, 0, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE }; globs *point_general = &general; int draw_thread_func (void *); char *configfilename = "/usr/X11R6/share/dancingparticles/dancingparticles.conf"; char *curtitle= "XMMS Launching!!"; gboolean paused; gboolean titleHasChanged; gboolean forceEffectChange = false; gboolean nextEffect; void dp_init(void); static void dp_cleanup(void); static void dp_configure(void); static void dp_playback_start(void); static void dp_playback_stop(void); static void about_box(); void dp_render_freq(gint16 data[2][256]); static void init_mutexes(void); static void destroy_mutexes(void); static SDL_Surface *opengl_screen = NULL; static SDL_Thread *draw_thread = NULL; SDL_mutex *mutex = NULL; VisPlugin dp_vplugin = { NULL, /* internal */ NULL, /* internal xb */ 0, /* internal */ NULL, /* description */ 0, /* # of pcm channels wanted */ 256, /* # of freq channels wanted */ dp_init, /* called when plugin enabled */ dp_cleanup, /* called when plugin disabled */ about_box, /* display about box */ dp_configure, /* display configure box */ NULL, /* called to disable plugin */ dp_playback_start, /* called when playback starts */ dp_playback_stop, /* called when playback stops */ NULL, /* called with pcm data */ dp_render_freq /* called with freq data */ }; unsigned int fast_sqrt_table[0x10000]; // declare table of square roots extern "C" { VisPlugin* get_vplugin_info(void) { #define VERSION "0.6" dp_vplugin.description = g_strdup_printf("OpenGL dancing particules Plugin %s", VERSION); return &dp_vplugin; } } void dp_read_config(void) { } void dp_write_config(void) { } void init_vidmodes(void) { } void init_mutexes (void) { mutex = SDL_CreateMutex(); } void destroy_mutexes (void) { SDL_DestroyMutex(mutex); } void create_window (int width, int height) { Uint32 flags; flags = SDL_OPENGL | SDL_RESIZABLE; SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); if (opengl_screen) SDL_FreeSurface(opengl_screen); opengl_screen = NULL; if (point_general->fullscreen) flags |= SDL_FULLSCREEN; opengl_screen = SDL_SetVideoMode(width, height, 16, flags); if (opengl_screen == NULL) { fprintf (stderr, "Graphic mode is not available: %s\n", SDL_GetError ()); point_general->finished = TRUE; point_general->in_thread = TRUE; exit (1); } SDL_WM_SetCaption("Dancing Particles", "DP"); glViewport(0, 0, point_general->WIDTH, point_general->HEIGHT); } void dp_init(void) { if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_NOPARACHUTE) < 0) { printf ("\n\nSDL_Init... [FAILED]"); draw_thread = NULL; dp_vplugin.disable_plugin (&dp_vplugin); return; } init_mutexes(); draw_thread = SDL_CreateThread (draw_thread_func, NULL); point_general->paused = FALSE; point_general->finished = FALSE; point_general->init = FALSE; point_general->changement = FALSE; point_general->freeze = FALSE; configfilename = g_strconcat(g_get_home_dir(), "/.xmms/Plugins/dancingparticles.conf", NULL); build_sqrt_table(); } static gboolean started; void dp_playback_start(void) { started = true; } void dp_playback_stop(void) { int i; for(i = 0; i < 64; i++) heights[i] = 0; started = false; } static gint disable_dp_vplugin(gpointer data) { dp_vplugin.disable_plugin(&dp_vplugin); return FALSE; } /* ***************************************************************** */ const int TCK_PER_FRAME = 2; static void update_playlist_info() { static gint lastpos = -1; if(started) { gint curpos = xmms_remote_get_playlist_pos(dp_vplugin.xmms_session); if(curpos!=lastpos) { if(lastpos!=-1) free(curtitle); char *title = xmms_remote_get_playlist_title(dp_vplugin.xmms_session,curpos); if(title==0) title = "Dancing Particles"; curtitle = strdup(title); lastpos = curpos; titleHasChanged = true; } } } static void look_conf_file() { static long lasttime = 0; static int nextcheck = 0; if(nextcheck-- <0 ) { struct stat buf; nextcheck = 30;//every 30 frame if(stat(configfilename, &buf)==0) { if(lasttime==0) lasttime = buf.st_mtime; if(lasttime != buf.st_mtime) { lasttime = buf.st_mtime; init_parameters(); curtitle = "Config reloaded!"; titleHasChanged = true; } } } } void sdl_keypress (void) { SDL_Event event; bool found = false; while (SDL_PollEvent(&event)); switch (event.type) { case SDL_QUIT: point_general->finished = TRUE; point_general->in_thread = TRUE; break; case SDL_VIDEORESIZE: if (event.resize.h != point_general->HEIGHT || event.resize.w != point_general->WIDTH) { point_general->WIDTH = (guint)event.resize.w; point_general->HEIGHT = (guint)event.resize.h; create_window(point_general->WIDTH, point_general->HEIGHT); } break; case SDL_KEYDOWN: for(int i = 0 ; i < nump ; i++) { if(ps[i].key==event.key.keysym.sym) { found = true; forceEffectChange = true; nextEffect = i; } } if(!found) { switch (event.key.keysym.sym) { case SDLK_ESCAPE: point_general->mouse = !point_general->mouse; point_general->fullscreen = !point_general->fullscreen; SDL_WM_ToggleFullScreen(opengl_screen); SDL_ShowCursor(point_general->mouse); break; case SDLK_p: point_general->paused = !point_general->paused; break; case SDLK_f: point_general->freeze = !point_general->freeze; printf(" Freeze mode: "); if (point_general->freeze) printf("ON "); else printf("OFF "); break; case SDLK_z: xmms_remote_playlist_prev(0); break; case SDLK_x: xmms_remote_play(0); break; case SDLK_c: xmms_remote_pause(0); break; case SDLK_v: xmms_remote_stop(0); break; case SDLK_b: xmms_remote_playlist_next(0); break; case SDLK_s: xmms_remote_toggle_shuffle(0); break; case SDLK_r: xmms_remote_toggle_repeat(0); break; case SDLK_LEFT: xmms_remote_jump_to_time(0, xmms_remote_get_output_time(0) - 10000); break; case SDLK_RIGHT: xmms_remote_jump_to_time(0, xmms_remote_get_output_time(0) + 10000); break; case SDLK_F1: point_general->WIDTH = 640; point_general->HEIGHT = 480; create_window(point_general->WIDTH, point_general->HEIGHT); break; case SDLK_F2: point_general->WIDTH = 800; point_general->HEIGHT = 600; create_window(point_general->WIDTH, point_general->HEIGHT); break; case SDLK_F3: point_general->WIDTH = 1024; point_general->HEIGHT = 768; create_window(point_general->WIDTH, point_general->HEIGHT); break; case SDLK_F4: point_general->WIDTH = 1280; point_general->HEIGHT = 1024; create_window(point_general->WIDTH, point_general->HEIGHT); break; case SDLK_F5: point_general->WIDTH = 1600; point_general->HEIGHT = 1200; create_window(point_general->WIDTH, point_general->HEIGHT); break; default: break; } } default: break; } } static void dp_cleanup (void) { point_general->finished = TRUE; point_general->in_thread = FALSE; if (draw_thread) { SDL_WaitThread(draw_thread, NULL); if (opengl_screen) SDL_FreeSurface(opengl_screen); opengl_screen = NULL; printf("\n\nSDL_Destroy thread... [OK]"); destroy_mutexes(); printf("\nSDL_Destroy mutex... [OK]"); } SDL_Quit(); printf("\nSDL_Quit... [OK]"); printf("\n"); } float framerate = 50; Uint32 last_time_fps; void calc_fps (void) { Uint32 this_time; this_time = SDL_GetTicks(); framerate = (float)1000.0 / (this_time - last_time_fps); last_time_fps = this_time; } void calc_max_fps (void) { double target; if (point_general->max_fps) { if (framerate > point_general->max_fps) { target = (1.0 / point_general->max_fps) - (1.0 / framerate); xmms_usleep((int)(target * 1000000)); framerate = (float)point_general->max_fps; } } } int draw_thread_func (void *ignored) { printf("\nSDL_Create thread... [OK]"); create_window(point_general->WIDTH, point_general->HEIGHT); init_gl(); printf("\nSDL_Create Gl Window... [OK]"); printf("\n\n"); while (!point_general->finished) { if (!point_general->paused) { SDL_mutexP(mutex); update_playlist_info(); look_conf_file(); etoileLoop(); draw_gl(); SDL_mutexV(mutex); calc_fps(); calc_max_fps(); printf("\rFPS: %3.2f", framerate); printf(" "); SDL_GL_SwapBuffers(); } else xmms_usleep(100); sdl_keypress(); } if (point_general->in_thread) gtk_idle_add (disable_dp_vplugin, NULL); return 0; } #define TITLEFONT "-*-helvetica-bold-r-normal--*-180-*-*-*-*-*-*" #define TEXTFONT "-*-courier-medium-r-normal--*-120-*-*-*-*-*-*" typedef struct { gboolean open; GtkWidget *window; GtkWidget *close; GtkWidget *text; } dialog_t; static dialog_t about_dialog = { 0,0,0,0}; static dialog_t error_dialog = { 0,0,0,0}; static dialog_t config_dialog = { 0,0,0,0}; extern char readme[]; extern char configtext[]; static void close_cb(GtkWidget *w, gpointer data) { if (about_dialog.open && (w == about_dialog.window || w == about_dialog.close)) { gtk_widget_destroy(about_dialog.window); about_dialog.open = FALSE; } else if (error_dialog.open && (w == error_dialog.window || w == error_dialog.close)) { gtk_widget_destroy(error_dialog.window); error_dialog.open = FALSE; } else if (config_dialog.open && (w == config_dialog.window || w == config_dialog.close)) { gtk_widget_destroy(config_dialog.window); config_dialog.open = FALSE; } } // TODO this seems to be bugged static void addtext(GtkWidget *twidget, const char *text) { GdkFont *font; const char *body; int len; printf("/* find the end of first line */\n"); for (len = 0, body = text; *body && *body != '\n'; body++, len++) { } if (*body == '\n'); body++, len++; printf("/* Add the first line in the "TITLEFONT" */\n"); font = gdk_font_load(TITLEFONT); if(font) gtk_text_insert(GTK_TEXT(twidget), font, NULL, NULL, text, len); gdk_font_unref(font); printf("/* If there's any remaining text, add it in "TEXTFONT" */\n"); if (*body) { font = gdk_font_load(TEXTFONT); gtk_text_insert(GTK_TEXT(twidget), font, NULL, NULL, body, -1); gdk_font_unref(font); } } static dialog_t showtext(const char *text, const char *close_label) { GtkWidget *vbox, *scroll, *bbox; dialog_t ret; /* Create a new window */ ret.window = gtk_window_new(GTK_WINDOW_DIALOG); gtk_container_border_width(GTK_CONTAINER(ret.window), 10); gtk_window_position(GTK_WINDOW(ret.window), GTK_WIN_POS_MOUSE); /* Create a vbox inside the window */ vbox = gtk_vbox_new(FALSE, 10); gtk_container_add(GTK_CONTAINER(ret.window), vbox); /* Create a scrolled window in the vbox */ scroll = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); gtk_box_pack_start(GTK_BOX(vbox), scroll, FALSE, FALSE, 0); /* Create a text widget in the scrolled window */ ret.text = gtk_text_new(NULL, NULL); gtk_widget_set_usize(ret.text, 450, 300); gtk_container_add(GTK_CONTAINER(scroll), ret.text); /* Stuff the text into it, using the Courier font */ addtext(ret.text, text); gtk_text_set_editable(GTK_TEXT(ret.text), FALSE); /* Create a button box under the text widget */ bbox = gtk_hbutton_box_new(); gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5); gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0); /* Add a [Close] button */ ret.close = gtk_button_new_with_label(close_label); gtk_signal_connect_object(GTK_OBJECT(ret.close), "clicked", GTK_SIGNAL_FUNC(close_cb), GTK_OBJECT(ret.window)); GTK_WIDGET_SET_FLAGS(ret.close, GTK_CAN_DEFAULT); gtk_box_pack_start(GTK_BOX(bbox), ret.close, TRUE, TRUE, 0); gtk_widget_grab_default(ret.close); /* Also make the window manager's close button close the window */ gtk_signal_connect_object(GTK_OBJECT(ret.window), "delete_event", GTK_SIGNAL_FUNC(close_cb), GTK_OBJECT(ret.window)); /* Show everything */ gtk_widget_show(ret.close); gtk_widget_show(bbox); gtk_widget_show(ret.text); gtk_widget_show(scroll); gtk_widget_show(vbox); gtk_widget_show(ret.window); ret.open = TRUE; return ret; } void about_box() { /* If already showing the window, do nothing */ if (about_dialog.open) return; about_dialog = showtext(readme, "Close"); } int IKnowAboutConfigFile = 0; void init_parameters(); void dp_configure(void) { if(!IKnowAboutConfigFile) { /* If already showing the window, do nothing */ if (!config_dialog.open) config_dialog = showtext(configtext, "Close"); } init_parameters(); } void about_error(char *format, ...) { char buf[2000]; va_list args; /* format the error message */ va_start(args, format); vsnprintf(buf,2000, format, args); va_end(args); printf("dldflkj\n"); /* if no error window yet, then create one */ if (error_dialog.open) { printf("addtext\n"); addtext(error_dialog.text, buf); } else { printf("showtext\n"); error_dialog = showtext(buf, "Shit Happens"); } } /*main(int argc, char **argv) { gtk_init(&argc, &argv); about(); gtk_main(); return 0; }*/