/* scivi - visualization plugin for XMMS * Copyright (C) 2003 Vitaly V. Bursov * * 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 */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include "common.h" #include "utilx.h" #include #include #include #include "glstuff.h" static int glxVersion = 0; void (*scivi_activate_pbuffer)(Scivi *scivi); void (*scivi_activate_window)(Scivi *scivi); void (*scivi_activate_swapbuffers)(Scivi *scivi); void (*scivi_switchto_window)(Scivi *scivi); void (*scivi_switchto_root)(Scivi *scivi); void (*scivi_switchto_fullscreen)(Scivi *scivi); static int setup_window(Scivi *scivi) { /* based on SDL X11 video */ char *title = PACKAGE_STRING; XWMHints *hints; XSizeHints *shints; XTextProperty titleprop; hints = XAllocWMHints(); if(hints) { hints->input = True; hints->flags = InputHint; XSetWMHints(XDPY, XWIN, hints); XFree(hints); } shints = XAllocSizeHints(); if (shints){ shints->min_width = shints->max_width = scivi->width; shints->min_height = shints->max_height = scivi->height; shints->flags = PMaxSize | PMinSize; XSetWMNormalHints(XDPY, XWIN, shints); } if (XStringListToTextProperty((char **)&title, 1, &titleprop)){ XSetWMName(XDPY, XWIN, &titleprop); XFree(titleprop.value); } XSelectInput(XDPY, XWIN, KeyPressMask); // FocusChangeMask | KeyPressMask | KeyReleaseMask // | PropertyChangeMask | StructureNotifyMask | KeymapStateMask); /* Set the class hints so we can get an icon (AfterStep) */ { XClassHint *classhints; classhints = XAllocClassHint(); if(classhints != NULL) { char *classname = "scivi"; classhints->res_name = classname; classhints->res_class = classname; XSetClassHint(XDPY, XWIN, classhints); XFree(classhints); } } /* Allow the window to be deleted by the window manager */ scivi->X.wm_delete = XInternAtom(XDPY, "WM_DELETE_WINDOW", False); XSetWMProtocols(XDPY, XWIN, &scivi->X.wm_delete, 1); return 0; } /********************************* * * GLX 1.3 * */ static int scivi_init_glx13(Scivi *scivi) { int fbconfsc; void *fbconf; void **fbconfs; XVisualInfo *visual; XSetWindowAttributes xattr; int i = 0; int attr[64]; /* setup visual */ i=0; attr[i++] = GLX_RED_SIZE; attr[i++] = 5; attr[i++] = GLX_GREEN_SIZE; attr[i++] = 5; attr[i++] = GLX_BLUE_SIZE; attr[i++] = 5; attr[i++] = GLX_DOUBLEBUFFER; attr[i++] = True; attr[i++] = GLX_DRAWABLE_TYPE; attr[i++] = GLX_WINDOW_BIT; //if supported... FIXME // attr[i++] = GLX_X_VISUAL_TYPE; // attr[i++] = GLX_DIRECT_COLOR; attr[i++] = None; fbconfs = (void*)sc_glXChooseFBConfig(XDPY, 0, attr, &fbconfsc); if ((fbconfsc <= 0) || !fbconfs){ eprintf("Can not get FB configs\n" "Please check your OpenGL driver installation\n"); if (fbconfs) XFree(fbconfs); return 3; } fbconf = fbconfs[0]; visual = sc_glXGetVisualFromFBConfig(XDPY, fbconf); if (!visual){ eprintf("Can not get Visual form FB\n"); XFree(fbconfs); return 3; } xattr.background_pixel = BlackPixel(XDPY, DefaultScreen(XDPY)); xattr.border_pixel = 0; XWIN = XCreateWindow(XDPY, DefaultRootWindow(XDPY), 0, 0, scivi->width, scivi->height, 0, visual->depth, InputOutput, visual->visual, CWBackPixel | CWBorderPixel, &xattr); XFree(visual); visual = NULL; if (!XWIN){ eprintf("Can not create window\n"); XFree(fbconfs); return 4; } if (setup_window(scivi)){ eprintf("Can not setup window\n"); XFree(fbconfs); return 5; } XGLXW = sc_glXCreateWindow(XDPY, fbconf, XWIN, NULL); if (!XGLXW){ eprintf("Can not create GLX window\n"); XFree(fbconfs); return 5; } XGLXR = sc_glXCreateWindow(XDPY, fbconf, DefaultRootWindow(XDPY), NULL); if (!XGLXR){ /* non fatal */ eprintf("Can not create GLX ROOT window\n"); } XCTXW = sc_glXCreateNewContext(XDPY, fbconf, GLX_RGBA_TYPE, NULL, True); if (!XCTXW){ eprintf("Can not create GLX context\n"); XFree(fbconfs); return 6; } XFree(fbconfs); i=0; attr[i++] = GLX_RED_SIZE; attr[i++] = 8; attr[i++] = GLX_GREEN_SIZE; attr[i++] = 8; attr[i++] = GLX_BLUE_SIZE; attr[i++] = 8; attr[i++] = GLX_DOUBLEBUFFER; attr[i++] = False; attr[i++] = GLX_DRAWABLE_TYPE; attr[i++] = GLX_PBUFFER_BIT; attr[i++] = None; fbconfs = (void*)sc_glXChooseFBConfig(XDPY, 0, attr, &fbconfsc); if ((fbconfsc <= 0) || !fbconfs){ eprintf("Can not get FB configs for pbuffer\n"); if (fbconfs) XFree(fbconfs); return 7; } fbconf = fbconfs[0]; i=0; attr[i++] = GLX_PBUFFER_WIDTH; attr[i++] = scivi->pbuf_want_w; attr[i++] = GLX_PBUFFER_HEIGHT; attr[i++] = scivi->pbuf_want_h; attr[i++] = GLX_PRESERVED_CONTENTS; attr[i++] = True; attr[i++] = None; XGLXP = sc_glXCreatePbuffer(XDPY, fbconf, attr); if (!XGLXP){ eprintf("Can not create GLX pbuffer\n"); XFree(fbconfs); return 7; } sc_glXQueryDrawable(XDPY, XGLXP, GLX_WIDTH, &scivi->pbuf_w); sc_glXQueryDrawable(XDPY, XGLXP, GLX_HEIGHT, &scivi->pbuf_h); XCTXP = sc_glXCreateNewContext(XDPY, fbconf, GLX_RGBA_TYPE, XCTXW, True); if (!XCTXP){ eprintf("Can not create GLX pbuffer context\n"); XFree(fbconfs); return 8; } dprintf("Window context is%s direct\n", sc_glXIsDirect(XDPY, XCTXW) ? "" : " NOT"); dprintf("PBuffer context is%s direct\n", sc_glXIsDirect(XDPY, XCTXP) ? "" : " NOT"); return 0; } static void scivi_activate_window_glx13(Scivi *scivi) { if (scivi->visual_mode == 0) sc_glXMakeContextCurrent(XDPY, XGLXW, XGLXW, XCTXW); else if (scivi->visual_mode == 1) sc_glXMakeContextCurrent(XDPY, XGLXR, XGLXR, XCTXW); } static void scivi_activate_pbuffer_glx13(Scivi *scivi) { sc_glXMakeContextCurrent(XDPY, XGLXP, XGLXP, XCTXP); } static void scivi_activate_swapbuffers_glx13(Scivi *scivi) { #if 0 static int c1 = 1, cp = 0; // if (scivi->vsync_enable){ if (scivi->visual_mode == 0){ unsigned int c, c2; //printf("1\n"); // if( sc_glXGetVideoSyncSGI(&c) == 0) // printf("vsc: %ud\n", c); do { sc_glXWaitVideoSyncSGI(100,c1,&c2); } while (cp == c2); cp = c2; c1+=2; if (c1>=100) c1=0; // printf("cc: %d\n",c2); //printf("2\n"); // else // printf("x\n"); // } } #endif if (scivi->visual_mode == 0) sc_glXSwapBuffers(XDPY, XGLXW); else if (scivi->visual_mode == 1) sc_glXSwapBuffers(XDPY, XGLXR); } static void scivi_switchto_window_glx13(Scivi *scivi) { if (scivi->visual_mode != 0){ XMapWindow(XDPY, XWIN); XFlush(XDPY); scivi->visual_mode = 0; sc_glXMakeContextCurrent(XDPY, XGLXW, XGLXW, XCTXW); XClearArea(XDPY, DefaultRootWindow(XDPY), 0, 0, scivi->rootwidth, scivi->rootheight, True); sc_glViewport( 0, 0, scivi->width, scivi->height ); } } static void scivi_switchto_root_glx13(Scivi *scivi) { if (!XGLXR){ Xprintf("Can not change to root window mode."); return; } if (scivi->visual_mode != 1){ Window root_wnd; int x,y; unsigned int w,h, bord_w, dpth; XUnmapWindow(XDPY, XWIN); XFlush(XDPY); scivi->visual_mode = 1; XGetGeometry(XDPY, DefaultRootWindow(XDPY), &root_wnd, &x, &y, &w, &h, &bord_w, &dpth); scivi->rootaspect = (float)w/h; scivi->rootwidth = w; scivi->rootheight = h; /* TODO do we need change root window in a glx context?? */ /* and what is root_wnd exactly? :) */ sc_glXMakeContextCurrent(XDPY, XGLXR, XGLXR, XCTXW); sc_glViewport( 0, 0, w, h ); } } static void scivi_switchto_fullscreen_glx13(Scivi *scivi) { /* TODO */ } /********************************* * * GLX 1.2 * */ static int scivi_init_glx12(Scivi *scivi) { XSetWindowAttributes xattr; XVisualInfo *visual; int i = 0; int attr[64]; /* setup visual */ i=0; attr[i++] = GLX_RGBA; attr[i++] = GLX_RED_SIZE; attr[i++] = 5; attr[i++] = GLX_GREEN_SIZE; attr[i++] = 5; attr[i++] = GLX_BLUE_SIZE; attr[i++] = 5; attr[i++] = GLX_DOUBLEBUFFER; /* looks like we can`t create context without this... */ attr[i++] = GLX_DEPTH_SIZE; attr[i++] = 1; attr[i++] = None; visual = sc_glXChooseVisual(XDPY, DefaultScreen(XDPY), attr); if (!visual){ eprintf("Can not get desired GLX1.2 visual\n"); return 3; } xattr.background_pixel = BlackPixel(XDPY, DefaultScreen(XDPY)); xattr.border_pixel = 0; XWIN = XCreateWindow(XDPY, DefaultRootWindow(XDPY), 0, 0, scivi->width, scivi->height, 0, visual->depth, InputOutput, visual->visual, CWBackPixel | CWBorderPixel, &xattr); if (!XWIN){ eprintf("Can not create window\n"); XFree(visual); return 4; } if (setup_window(scivi)){ eprintf("Can not setup window\n"); XFree(visual); return 5; } XCTXW = sc_glXCreateContext(XDPY, visual, NULL, True); if (!XCTXW){ eprintf("Can not create GLX context\n"); XFree(visual); XCTXP = NULL; return 5; } XCTXP = sc_glXCreateContext(XDPY, visual, XCTXW, True); if (!XCTXP){ eprintf("Can not create GLX context\n"); XFree(visual); return 6; } XFree(visual); if ((scivi->pbuf_want_w <= 0) || (scivi->pbuf_want_h <= 0)){ scivi->pbuf_w = 1; scivi->pbuf_h = 1; while (scivi->pbuf_w <= scivi->width) scivi->pbuf_w = scivi->pbuf_w << 1; while (scivi->pbuf_h <= scivi->height) scivi->pbuf_h = scivi->pbuf_h << 1; scivi->pbuf_w = scivi->pbuf_w >> 1; scivi->pbuf_h = scivi->pbuf_h >> 1; } else { scivi->pbuf_w = scivi->pbuf_want_w; scivi->pbuf_h = scivi->pbuf_want_h; } dprintf("Window buffer context is%s direct\n", sc_glXIsDirect(XDPY, XCTXW) ? "" : " NOT"); dprintf("Pixmap buffer context is%s direct\n", sc_glXIsDirect(XDPY, XCTXP) ? "" : " NOT"); return 0; } static void scivi_activate_window_glx12(Scivi *scivi) { sc_glXMakeCurrent(XDPY, XWIN, XCTXW); } static void scivi_activate_pbuffer_glx12(Scivi *scivi) { sc_glXMakeCurrent(XDPY, XWIN, XCTXP); } static void scivi_activate_swapbuffers_glx12(Scivi *scivi) { sc_glXSwapBuffers(XDPY, XWIN); } static void scivi_switchto_window_glx12(Scivi *scivi) { XMapWindow(XDPY, XWIN); XFlush(XDPY); scivi->visual_mode = 0; sc_glXMakeCurrent(XDPY, XWIN, XCTXW); sc_glViewport( 0, 0, scivi->width, scivi->height ); } static void scivi_switchto_root_glx12(Scivi *scivi) { } static void scivi_switchto_fullscreen_glx12(Scivi *scivi) { } /* * Initialize X and GLX. Common stuff * */ int scivi_init_x(Scivi *scivi) { int dummy1, dummy2, dummy3; int vmaj, vmin; int loadres; XDPY = XOpenDisplay(NULL); if (!XDPY){ Xprintf("Can not open DISPLAY\n"); return 1; } if (!XQueryExtension(XDPY, "GLX", &dummy1, &dummy2, &dummy3)){ Xprintf("GLX extension is not available\n"); return 1; } loadres = scivi_initialize_gl_funcs(NULL); if (loadres < 0){ Xprintf("Can not load GL libraries\n"); return 1; } /* check for GLX version */ if (!sc_glXQueryExtension(XDPY, &scivi->X.glx_errorBase, &scivi->X.glx_eventBase)){ Xprintf("GLX is not available: glXQueryExtension failed\n"); return 2; } if (!sc_glXQueryVersion(XDPY, &vmaj, &vmin)){ Xprintf("GLX is not available: glXQueryVersion failed\n"); return 2; } if ((vmaj < 1) || ((vmaj == 1) && (vmin < 3))){ if ((vmaj < 1) || ((vmaj == 1) && (vmin < 1))){ Xprintf("GLX version is too old. Sorry!\n"); return 2; } else dprintf("Using GLX verson 1.2\n"); glxVersion = 0; } else glxVersion = 1; if (loadres > 0){ Xprintf("Can not initialize GL: some required GL functions are missing\n"); return 1; } if (scivi->X.force_old_glx){ dprintf("Forcing GLX version <1.3\n"); glxVersion = 0; } if (glxVersion){ scivi_activate_pbuffer = scivi_activate_pbuffer_glx13; scivi_activate_window = scivi_activate_window_glx13; scivi_activate_swapbuffers = scivi_activate_swapbuffers_glx13; scivi_switchto_window = scivi_switchto_window_glx13; scivi_switchto_root = scivi_switchto_root_glx13; scivi_switchto_fullscreen = scivi_switchto_fullscreen_glx13; return scivi_init_glx13(scivi); } else { scivi_activate_pbuffer = scivi_activate_pbuffer_glx12; scivi_activate_window = scivi_activate_window_glx12; scivi_activate_swapbuffers = scivi_activate_swapbuffers_glx12; scivi_switchto_window = scivi_switchto_window_glx12; scivi_switchto_root = scivi_switchto_root_glx12; scivi_switchto_fullscreen = scivi_switchto_fullscreen_glx12; return scivi_init_glx12(scivi); } return -1; } void scivi_finit_x(Scivi *scivi, int code) { scivi_activate_pbuffer = NULL; scivi_activate_window = NULL; scivi_activate_swapbuffers = NULL; scivi_switchto_window = NULL; scivi_switchto_root = NULL; scivi_switchto_fullscreen = NULL; if (scivi->visual_mode != 0){ XClearArea(XDPY, DefaultRootWindow(XDPY), 0, 0, scivi->rootwidth, scivi->rootheight, True); } if (glxVersion){ switch (code){ case 0: sc_glXDestroyContext(XDPY, XCTXP); XCTXP = NULL; case 8: sc_glXDestroyPbuffer(XDPY, XGLXP); XGLXP = 0; case 7: sc_glXDestroyContext(XDPY, XCTXW); XCTXW = NULL; case 6: sc_glXDestroyWindow(XDPY, XGLXW); XGLXW = 0; if (XGLXR){ sc_glXDestroyWindow(XDPY, XGLXR); XGLXR = 0; } case 5: XDestroyWindow(XDPY, XWIN); XWIN = 0; case 4: case 3: case 2: XCloseDisplay(XDPY); case 1: XDPY = NULL; /* avoid warning */ } } else { switch (code){ case 0: sc_glXDestroyContext(XDPY, XCTXP); XCTXP = NULL; case 6: sc_glXDestroyContext(XDPY, XCTXW); XCTXW = NULL; case 5: XDestroyWindow(XDPY, XWIN); XWIN = 0; case 4: case 3: case 2: XCloseDisplay(XDPY); case 1: XDPY = NULL; /* avoid warning */ } } scivi_finalize_gl_funcs(); } int scivi_query_pointer(Scivi *scivi, DynamicsData *d) { Window w; Window rw, cw; int rx, ry, wx, wy, m; if (scivi->visual_mode == 0) w = XWIN; else w = DefaultRootWindow(XDPY); if (XQueryPointer(XDPY, w, &rw, &cw, &rx, &ry, &wx, &wy, &m)){ if (scivi->visual_mode == 0){ d->mousex = ((float)wx)/scivi->width; d->mousey = ((float)wy)/scivi->height; } else { d->mousex = ((float)wx)/scivi->rootwidth; d->mousey = ((float)wy)/scivi->rootheight; } d->mousex = (d->mousex - 0.5f)*d->width; d->mousey = -(d->mousey - 0.5f)*d->height; d->mousebtn1 = (m & Button1Mask) ? 1.0f : 0.0f; d->mousebtn2 = (m & Button2Mask) ? 1.0f : 0.0f; d->mousebtn3 = (m & Button3Mask) ? 1.0f : 0.0f; return 0; } return 1; }