diff options
-rw-r--r-- | libvo/vo_gl2.c | 70 | ||||
-rw-r--r-- | libvo/vo_x11.c | 23 | ||||
-rw-r--r-- | libvo/x11_common.c | 133 | ||||
-rw-r--r-- | libvo/x11_common.h | 3 |
4 files changed, 224 insertions, 5 deletions
diff --git a/libvo/vo_gl2.c b/libvo/vo_gl2.c index 12e8e27881..a10567ed84 100644 --- a/libvo/vo_gl2.c +++ b/libvo/vo_gl2.c @@ -598,6 +598,50 @@ static void draw_alpha_15(int x0,int y0, int w,int h, unsigned char* src, unsign static void draw_alpha_null(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){ } +static int choose_glx_visual(Display *dpy, int scr, XVisualInfo *res_vi) +{ + XVisualInfo template, *vi_list; + int vi_num, i, best_i, best_weight; + + template.screen = scr; + vi_list = XGetVisualInfo(dpy, VisualScreenMask, &template, &vi_num); + if (!vi_list) return -1; + best_weight = 1000000; + for (i = 0; i < vi_num; i++) { + int val, res, w = 0; + /* of course, the visual must support OpenGL rendering... */ + res = glXGetConfig(dpy, vi_list + i, GLX_USE_GL, &val); + if (res || val == False) continue; + /* also it must be doublebuffered ... */ + res = glXGetConfig(dpy, vi_list + i, GLX_DOUBLEBUFFER, &val); + if (res || val == False) continue; + /* furthermore it must be RGBA (not color indexed) ... */ + res = glXGetConfig(dpy, vi_list + i, GLX_RGBA, &val); + if (res || val == False) continue; + /* prefer less depth buffer size, */ + res = glXGetConfig(dpy, vi_list + i, GLX_DEPTH_SIZE, &val); + if (res) continue; + w += val*2; + /* stencil buffer size */ + res = glXGetConfig(dpy, vi_list + i, GLX_STENCIL_SIZE, &val); + if (res) continue; + w += val*2; + /* and colorbuffer alpha size */ + res = glXGetConfig(dpy, vi_list + i, GLX_ALPHA_SIZE, &val); + if (res) continue; + w += val; + /* and finally, prefer DirectColor-ed visuals to allow color corrections */ + if (vi_list[i].class != DirectColor) w += 100; + if (w < best_weight) { + best_weight = w; + best_i = i; + } + } + if (best_weight < 1000000) *res_vi = vi_list[best_i]; + XFree(vi_list); + return (best_weight < 1000000) ? 0 : -1; +} + /* connect to server, create and map window, * allocate colors and (shared) memory */ @@ -609,7 +653,7 @@ config(uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uin char *hello = (title == NULL) ? "OpenGL rulez" : title; // char *name = ":0.0"; XSizeHints hint; - XVisualInfo *vinfo; + XVisualInfo *vinfo, vinfo_buf; XEvent xev; // XGCValues xgcv; @@ -655,7 +699,7 @@ config(uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uin // XGetWindowAttributes(mDisplay, DefaultRootWindow(mDisplay), &attribs); // XMatchVisualInfo(mDisplay, screen, depth, TrueColor, &vinfo); - vinfo=glXChooseVisual( mDisplay,mScreen,wsGLXAttrib ); + vinfo = choose_glx_visual(mDisplay,mScreen,&vinfo_buf) < 0 ? NULL : &vinfo_buf; if (vinfo == NULL) { printf("[gl2] no GLX support present\n"); @@ -664,7 +708,7 @@ config(uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uin xswa.background_pixel = 0; xswa.border_pixel = 1; - xswa.colormap = XCreateColormap(mDisplay, mRootWin, vinfo->visual, AllocNone); + xswa.colormap = vo_x11_create_colormap(vinfo); xswamask = CWBackPixel | CWBorderPixel | CWColormap; if ( vo_window == None ) @@ -1115,6 +1159,26 @@ static uint32_t control(uint32_t request, void *data, ...) switch (request) { case VOCTRL_QUERY_FORMAT: return query_format(*((uint32_t*)data)); + case VOCTRL_SET_EQUALIZER: + { + va_list ap; + int value; + + va_start(ap, data); + value = va_arg(ap, int); + va_end(ap); + return vo_x11_set_equalizer(data, value); + } + case VOCTRL_GET_EQUALIZER: + { + va_list ap; + int *value; + + va_start(ap, data); + value = va_arg(ap, int *); + va_end(ap); + return vo_x11_get_equalizer(data, value); + } } return VO_NOTIMPL; } diff --git a/libvo/vo_x11.c b/libvo/vo_x11.c index c164c3067b..2ef8a871e7 100644 --- a/libvo/vo_x11.c +++ b/libvo/vo_x11.c @@ -260,7 +260,8 @@ static uint32_t config( uint32_t width,uint32_t height,uint32_t d_width,uint32_t Visual *visual; depth = vo_find_depth_from_visuals(mDisplay, mScreen, &visual); } - XMatchVisualInfo( mDisplay,mScreen,depth,TrueColor,&vinfo ); + if ( !XMatchVisualInfo( mDisplay,mScreen,depth,DirectColor,&vinfo )) + XMatchVisualInfo( mDisplay,mScreen,depth,TrueColor,&vinfo ); /* set image size (which is indeed neither the input nor output size), if zoom is on it will be changed during draw_slice anyway so we dont dupplicate the aspect code here @@ -292,7 +293,7 @@ static uint32_t config( uint32_t width,uint32_t height,uint32_t d_width,uint32_t bg=WhitePixel( mDisplay,mScreen ); fg=BlackPixel( mDisplay,mScreen ); - theCmap=XCreateColormap( mDisplay,mRootWin,vinfo.visual,AllocNone ); + theCmap=vo_x11_create_colormap(&vinfo); xswa.background_pixel=0; xswa.border_pixel=0; @@ -633,6 +634,24 @@ static uint32_t control(uint32_t request, void *data, ...) return VO_TRUE; case VOCTRL_GET_IMAGE: return get_image(data); + case VOCTRL_SET_EQUALIZER: + { + va_list ap; + int value; + va_start(ap, data); + value = va_arg(ap, int); + va_end(ap); + return vo_x11_set_equalizer(data, value); + } + case VOCTRL_GET_EQUALIZER: + { + va_list ap; + int *value; + va_start(ap, data); + value = va_arg(ap, int *); + va_end(ap); + return vo_x11_get_equalizer(data, value); + } case VOCTRL_FULLSCREEN: vo_x11_fullscreen(); return VO_TRUE; diff --git a/libvo/x11_common.c b/libvo/x11_common.c index 5bdfc35abc..2e4f7c6300 100644 --- a/libvo/x11_common.c +++ b/libvo/x11_common.c @@ -1,6 +1,7 @@ #include <stdio.h> #include <stdlib.h> +#include <math.h> #include <inttypes.h> #include "config.h" @@ -969,3 +970,135 @@ int vo_find_depth_from_visuals(Display *dpy, int screen, Visual **visual_return) return bestvisual_depth; } + +static Colormap cmap = None; +static XColor cols[256]; +static int cm_size, red_mask, green_mask, blue_mask; + + +Colormap vo_x11_create_colormap(XVisualInfo *vinfo) +{ + unsigned k, r, g, b, ru, gu, bu, m, rv, gv, bv, rvu, gvu, bvu; + + if (vinfo->class != DirectColor) + return XCreateColormap(mDisplay, mRootWin, vinfo->visual, AllocNone); + + /* can this function get called twice or more? */ + if (cmap) return cmap; + cm_size = vinfo->colormap_size; + red_mask = vinfo->red_mask; + green_mask = vinfo->green_mask; + blue_mask = vinfo->blue_mask; + ru = (red_mask&(red_mask-1))^red_mask; + gu = (green_mask&(green_mask-1))^green_mask; + bu = (blue_mask&(blue_mask-1))^blue_mask; + rvu = 65536ull*ru/(red_mask + ru); + gvu = 65536ull*gu/(green_mask + gu); + bvu = 65536ull*bu/(blue_mask + bu); + r = g = b = 0; + rv = gv = bv = 0; + m = DoRed|DoGreen|DoBlue; + for (k = 0; k < cm_size; k++) { + int t; + cols[k].pixel = r|g|b; + cols[k].red = rv; + cols[k].green = gv; + cols[k].blue = bv; + cols[k].flags = m; + t = (r + ru) & red_mask; if (t < r) m &= ~DoRed; r = t; + t = (g + gu) & green_mask; if (t < g) m &= ~DoGreen; g = t; + t = (b + bu) & blue_mask; if (t < b) m &= ~DoBlue; b = t; + rv += rvu; + gv += gvu; + bv += bvu; + } + cmap = XCreateColormap(mDisplay, mRootWin, vinfo->visual, AllocAll); + XStoreColors(mDisplay, cmap, cols, cm_size); + return cmap; +} + +/* + * Via colormaps/gamma ramps we can do gamma, brightness, contrast, + * hue and red/green/blue intensity, but we cannot do saturation. + * Currently only gamma, brightness and contrast are implemented. + * Is there sufficient interest for hue and/or red/green/blue intensity? + */ +/* these values have range [-100,100] and are initially 0 */ +static int vo_gamma = 0; +static int vo_brightness = 0; +static int vo_contrast = 0; + + +uint32_t vo_x11_set_equalizer(char *name, int value) +{ + float gamma, brightness, contrast; + float rf, gf, bf; + int k; + + /* + * IMPLEMENTME: consider using XF86VidModeSetGammaRamp in the case + * of TrueColor-ed window but be careful: + * unlike the colormaps, which are private for the X client + * who created them and thus automatically destroyed on client + * disconnect, this gamma ramp is a system-wide (X-server-wide) + * setting and _must_ be restored before the process exit. + * Unforunately when the process crashes (or get killed + * for some reason) it is impossible to restore the setting, + * and such behaviour could be rather annoying for the users. + */ + if (cmap == None) return VO_NOTAVAIL; + + if (!strcasecmp(name, "brightness")) vo_brightness = value; + else if (!strcasecmp(name, "contrast")) vo_contrast = value; + else if (!strcasecmp(name, "gamma")) vo_gamma = value; + else return VO_NOTIMPL; + + brightness = 0.01*vo_brightness; + contrast = tan(0.0095*(vo_contrast+100)*M_PI/4); + gamma = pow(2, -0.02*vo_gamma); + + rf = (float)((red_mask & (red_mask - 1)) ^ red_mask)/red_mask; + gf = (float)((green_mask & (green_mask - 1)) ^ green_mask)/green_mask; + bf = (float)((blue_mask & (blue_mask - 1)) ^ blue_mask)/blue_mask; + + /* now recalculate the colormap using the newly set value */ + for (k = 0; k < cm_size; k++) { + float s; + + s = pow(rf*k, gamma); + s = (s - 0.5)*contrast + 0.5; + s += brightness; + if (s < 0) s = 0; + if (s > 1) s = 1; + cols[k].red = (unsigned short)(s * 65535); + + s = pow(gf*k, gamma); + s = (s - 0.5)*contrast + 0.5; + s += brightness; + if (s < 0) s = 0; + if (s > 1) s = 1; + cols[k].green = (unsigned short)(s * 65535); + + s = pow(bf*k, gamma); + s = (s - 0.5)*contrast + 0.5; + s += brightness; + if (s < 0) s = 0; + if (s > 1) s = 1; + cols[k].blue = (unsigned short)(s * 65535); + } + + XStoreColors(mDisplay, cmap, cols, cm_size); + XFlush(mDisplay); + return VO_TRUE; +} + +uint32_t vo_x11_get_equalizer(char *name, int *value) +{ + if (cmap == None) return VO_NOTAVAIL; + if (!strcasecmp(name, "brightness")) *value = vo_brightness; + else if (!strcasecmp(name, "contrast")) *value = vo_contrast; + else if (!strcasecmp(name, "gamma")) *value = vo_gamma; + else return VO_NOTIMPL; +} + + diff --git a/libvo/x11_common.h b/libvo/x11_common.h index c016a04de5..ad6d09b97d 100644 --- a/libvo/x11_common.h +++ b/libvo/x11_common.h @@ -36,6 +36,9 @@ extern int vo_x11_check_events(Display *mydisplay); extern void vo_x11_selectinput_witherr(Display *display, Window w, long event_mask); extern void vo_x11_fullscreen( void ); extern void vo_x11_uninit(); +extern Colormap vo_x11_create_colormap(XVisualInfo *vinfo); +extern uint32_t vo_x11_set_equalizer(char *name, int value); +extern uint32_t vo_x11_get_equalizer(char *name, int *value); #endif |