Rewrite greyscale OpenGL system to use GLSL

Add ability to blend color and greyscale based on window alpha (actual window alpha currently set at 0.5 when blending is enabled)
Reenable greyscale logout effect when compositor is in use
pull/2/head
Timothy Pearson 10 years ago
parent f1baae5fff
commit d8287f9787

@ -87,6 +87,11 @@ KSMShutdownFeedback::KSMShutdownFeedback()
m_grayImage.setAlphaBuffer(false);
m_grayImage.fill(0); // Set the alpha buffer to 0 (fully transparent)
m_grayImage.setAlphaBuffer(true);
// Signal that we want a greyscale filter on the transparency
Atom kde_wm_transparent_greyscale_filter;
kde_wm_transparent_greyscale_filter = XInternAtom(tqt_xdisplay(), "_TDE_TRANSPARENCY_FILTER_GREYSCALE_BLEND", False);
XChangeProperty(tqt_xdisplay(), winId(), kde_wm_transparent_greyscale_filter, XA_INTEGER, 32, PropModeReplace, (unsigned char *) "TRUE", 1L);
}
else {
// The hacks below aren't needed any more because Qt3 supports true transparency for the fading logout screen when composition is available
@ -135,10 +140,10 @@ void KSMShutdownFeedback::slotPaintEffect()
m_root.resize( width(), height() );
TQImage blendedImage = m_grayImage;
TQPainter p;
p.begin( &m_root );
blendedImage.setAlphaBuffer(false);
p.drawImage( 0, 0, blendedImage );
p.end();
p.begin( &m_root );
blendedImage.setAlphaBuffer(false);
p.drawImage( 0, 0, blendedImage );
p.end();
setBackgroundPixmap( m_root );
setGeometry( TQApplication::desktop()->geometry() );
@ -150,7 +155,7 @@ void KSMShutdownFeedback::slotPaintEffect()
uchar * end = m_grayImage.bits() + m_grayImage.numBytes();
while ( r != end ) {
*reinterpret_cast<TQRgb*>(r) = tqRgba(0, 0, 0, 128);
*reinterpret_cast<TQRgb*>(r) = tqRgba(0, 0, 0, 255);
r += 4;
}
@ -220,7 +225,6 @@ void KSMShutdownFeedback::slotPaintEffect()
{
TQImage img( imgWidth, y2-start_y1, 32 );
memcpy( img.bits(), m_grayImage.scanLine( start_y1 ), ( y2-start_y1 ) * imgWidth * 4 );
register uchar * rs = m_unfadedImage.scanLine( start_y1 );
register uchar * rd = img.bits();
for( int y = start_y1; y < y2; ++y )
{
@ -228,8 +232,8 @@ void KSMShutdownFeedback::slotPaintEffect()
short int opac = static_cast<short int>( 128 - cosf( M_PI*(y-y1)/heightUnit )*128.0f );
for( short int x = 0; x < imgWidth; ++x )
{
*reinterpret_cast<TQRgb*>(rd) = tqRgba(0, 0, 0, ((255.0-opac)/(255.0/127.0)));
rs += 4; rd += 4;
*reinterpret_cast<TQRgb*>(rd) = tqRgba(0, 0, 0, ((255.0-opac)));
rd += 4;
}
}
bitBlt( this, 0, start_y1, &img );

@ -489,6 +489,21 @@ typedef struct {
int height;
} glx_blur_cache_t;
typedef struct {
/// Fragment shader for greyscale.
GLuint frag_shader;
/// GLSL program for greyscale.
GLuint prog;
/// Location of uniform "greyscale_weights" in greyscale GLSL program.
GLint unifm_greyscale_weights;
/// Location of uniform "enable_blend" in greyscale GLSL program.
GLint unifm_enable_blend;
/// Location of uniform "tex_scr" in greyscale GLSL program.
GLint unifm_tex_scr;
/// Location of uniform "alpha_scr" in greyscale GLSL program.
GLint unifm_alpha_scr;
} glx_greyscale_t;
typedef struct {
/// Framebuffer used for greyscale conversion.
GLuint fbo;
@ -817,6 +832,9 @@ typedef struct {
#ifdef CONFIG_VSYNC_OPENGL_GLSL
glx_blur_pass_t blur_passes[MAX_BLUR_PASS];
#endif
#ifdef CONFIG_VSYNC_OPENGL_GLSL
glx_greyscale_t greyscale_glsl;
#endif
} glx_session_t;
#define CGLX_SESSION_INIT { .context = NULL }
@ -1068,6 +1086,8 @@ typedef struct _session_t {
Atom atom_win_type_tde_transparent_to_desktop;
/// Atom of property <code>_TDE_TRANSPARENCY_FILTER_GREYSCALE</code>.
Atom atom_win_type_tde_transparency_filter_greyscale;
/// Atom of property <code>_TDE_TRANSPARENCY_FILTER_GREYSCALE_BLEND</code>.
Atom atom_win_type_tde_transparency_filter_greyscale_blend;
/// Array of atoms of all possible window types.
Atom atoms_wintypes[NUM_WINTYPES];
/// Linked list of additional atoms to track.
@ -1263,6 +1283,11 @@ typedef struct _win {
/// Background state on last paint.
bool greyscale_background_last;
/// Whether to set window background to blended greyscale.
bool greyscale_blended_background;
/// Blended greyscale alpha divisor.
int greyscale_blended_background_alpha_divisor;
/// Whether to show black background
bool show_black_background;
@ -2202,6 +2227,9 @@ glx_on_root_change(session_t *ps);
bool
glx_init_blur(session_t *ps);
bool
glx_init_greyscale(session_t *ps);
#ifdef CONFIG_VSYNC_OPENGL_GLSL
bool
glx_load_prog_main(session_t *ps,
@ -2245,7 +2273,7 @@ glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z,
bool
glx_greyscale_dst(session_t *ps, int dx, int dy, int width, int height, float z,
XserverRegion reg_tgt, const reg_data_t *pcache_reg, glx_greyscale_cache_t *pbc);
glx_texture_t *ptex, XserverRegion reg_tgt, const reg_data_t *pcache_reg, glx_greyscale_cache_t *pbc);
bool
glx_render_(session_t *ps, const glx_texture_t *ptex,
@ -2342,7 +2370,6 @@ free_glx_bc(session_t *ps, glx_blur_cache_t *pbc) {
static inline void
free_glx_gc_resize(session_t *ps, glx_greyscale_cache_t *pbc) {
free_texture_r(ps, &pbc->textures[0]);
free_texture_r(ps, &pbc->textures[1]);
pbc->width = 0;
pbc->height = 0;
}

@ -943,6 +943,9 @@ recheck_focus(session_t *ps) {
static Bool
determine_window_transparency_filter_greyscale(const session_t *ps, Window w);
static Bool
determine_window_transparency_filter_greyscale_blended(const session_t *ps, Window w);
static Bool
determine_window_transparent_to_black(const session_t *ps, Window w);
@ -1590,6 +1593,7 @@ xr_greyscale_dst(session_t *ps, Picture tgt_buffer,
XRenderComposite(ps->dpy, PictOpSrc, ps->black_picture, None,
tmp_picture, 0, 0, 0, 0, 0, 0, wid, hei);
XRenderComposite(ps->dpy, PictOpHSLLuminosity, tgt_buffer, None,
tmp_picture, x, y, 0, 0, 0, 0, wid, hei);
@ -1723,7 +1727,7 @@ win_greyscale_background(session_t *ps, win *w, Picture tgt_buffer,
#ifdef CONFIG_VSYNC_OPENGL_GLSL
case BKEND_GLX:
glx_greyscale_dst(ps, x, y, wid, hei, ps->psglx->z - 0.5,
reg_paint, pcache_reg, &w->glx_greyscale_cache);
NULL, reg_paint, pcache_reg, &w->glx_greyscale_cache);
break;
#endif
default:
@ -1821,6 +1825,71 @@ win_paint_win(session_t *ps, win *w, XserverRegion reg_paint,
Picture pict = w->paint.pict;
if (w->greyscale_blended_background) {
// Set window background to greyscale
switch (ps->o.backend) {
case BKEND_XRENDER:
case BKEND_XR_GLX_HYBRID:
{
// Blend here such that 0 window alpha is fully colored and 100 window alpha is fully greyscale
// PictOpInReverse is used to copy alpha from the source to the destination while preserving destination color
// provided that the source has alpha set to 1 (equivalent of CAIRO_OPERATOR_DEST_IN)
const int x = w->a.x;
const int y = w->a.y;
const int wid = w->widthb;
const int hei = w->heightb;
XserverRegion reg_clip = reg_paint;
Picture tgt_buffer = ps->tgt_buffer.pict;
// Apply clipping region to save some CPU
if (reg_paint) {
XserverRegion reg = copy_region(ps, reg_paint);
XFixesTranslateRegion(ps->dpy, reg, -x, -y);
XFixesSetPictureClipRegion(ps->dpy, pict, 0, 0, reg);
free_region(ps, &reg);
}
// Create greyscale version of background
Picture greyscale_picture = xr_build_picture(ps, wid, hei, w->pictfmt);
XRenderComposite(ps->dpy, PictOpSrc, tgt_buffer, None,
greyscale_picture, x, y, 0, 0, 0, 0, wid, hei);
win_greyscale_background(ps, w, greyscale_picture, reg_paint, pcache_reg);
Picture tmp_picture = xr_build_picture(ps, wid, hei, w->pictfmt);
if (!tmp_picture) {
printf_errf("(): Failed to build intermediate Picture.");
}
else {
if (reg_clip && tmp_picture)
XFixesSetPictureClipRegion(ps->dpy, tmp_picture, reg_clip, 0, 0);
// Transfer greyscale picture to temporary picture
XRenderComposite(ps->dpy, PictOpSrc, greyscale_picture, None,
tmp_picture, 0, 0, 0, 0, 0, 0, wid, hei);
// Transfer alpha of window to temporary picture
XRenderComposite(ps->dpy, PictOpInReverse, pict, None,
tmp_picture, 0, 0, 0, 0, 0, 0, wid, hei);
// Blend greyscale picture over main color buffer
XRenderComposite(ps->dpy, PictOpOver, tmp_picture, None, tgt_buffer,
0, 0, 0, 0, x, y, wid, hei);
free_picture(ps, &tmp_picture);
free_picture(ps, &greyscale_picture);
}
}
break;
#ifdef CONFIG_VSYNC_OPENGL
case BKEND_GLX:
glx_greyscale_dst(ps, x, y, wid, hei, ps->psglx->z - 0.5,
w->paint.ptex, reg_paint, pcache_reg, &w->glx_greyscale_cache);
break;
#endif
}
}
// Invert window color, if required
if (bkend_use_xrender(ps) && w->invert_color) {
Picture newpict = xr_build_picture(ps, wid, hei, w->pictfmt);
@ -1846,7 +1915,12 @@ win_paint_win(session_t *ps, win *w, XserverRegion reg_paint,
}
}
const double dopacity = get_opacity_percent(w);
double dopacity = get_opacity_percent(w);
if (w->greyscale_blended_background) {
double scaling_factor = (1.0 / w->greyscale_blended_background_alpha_divisor);
dopacity = dopacity * scaling_factor;
}
if (!w->frame_opacity) {
win_render(ps, w, 0, 0, wid, hei, dopacity, reg_paint, pcache_reg, pict);
@ -2439,6 +2513,7 @@ map_win(session_t *ps, Window id) {
/* This needs to be here since we don't get PropertyNotify when unmapped */
w->opacity = wid_get_opacity_prop(ps, w->id, OPAQUE);
w->greyscale_background = determine_window_transparency_filter_greyscale(ps, id);
w->greyscale_blended_background = determine_window_transparency_filter_greyscale_blended(ps, id);
w->show_root_tile = determine_window_transparent_to_desktop(ps, id);
w->show_black_background = determine_window_transparent_to_black(ps, id);
@ -2631,6 +2706,28 @@ get_window_transparency_filter_greyscale(const session_t *ps, Window w)
return False;
}
static Bool
get_window_transparency_filter_greyscale_blended(const session_t *ps, Window w)
{
Atom actual;
int format;
unsigned long n, left;
unsigned char *data;
int result = XGetWindowProperty (ps->dpy, w, ps->atom_win_type_tde_transparency_filter_greyscale_blend, 0L, 1L, False,
XA_ATOM, &actual, &format,
&n, &left, &data);
if (result == Success && data != None && format == 32 )
{
Atom a;
a = *(long*)data;
XFree ( (void *) data);
return True;
}
return False;
}
static Bool
get_window_transparent_to_desktop(const session_t *ps, Window w)
{
@ -2710,6 +2807,41 @@ determine_window_transparency_filter_greyscale (const session_t *ps, Window w)
return False;
}
static Bool
determine_window_transparency_filter_greyscale_blended (const session_t *ps, Window w)
{
Window root_return, parent_return;
Window *children = NULL;
unsigned int nchildren, i;
Bool type;
type = get_window_transparency_filter_greyscale_blended (ps, w);
if (type == True) {
return True;
}
if (!XQueryTree (ps->dpy, w, &root_return, &parent_return, &children,
&nchildren))
{
/* XQueryTree failed. */
if (children)
XFree ((void *)children);
return False;
}
for (i = 0;i < nchildren;i++)
{
type = determine_window_transparency_filter_greyscale_blended (ps, children[i]);
if (type == True)
return True;
}
if (children)
XFree ((void *)children);
return False;
}
static Bool
determine_window_transparent_to_desktop (const session_t *ps, Window w)
{
@ -3449,6 +3581,8 @@ add_win(session_t *ps, Window id, Window prev) {
.blur_background = false,
.greyscale_background = false,
.greyscale_blended_background = false,
.greyscale_blended_background_alpha_divisor = 2,
.show_black_background = false,
.show_root_tile = false,
@ -6696,6 +6830,7 @@ init_atoms(session_t *ps) {
ps->atom_win_type_tde_transparent_to_black = get_atom(ps, "_TDE_TRANSPARENT_TO_BLACK");
ps->atom_win_type_tde_transparent_to_desktop = get_atom(ps, "_TDE_TRANSPARENT_TO_DESKTOP");
ps->atom_win_type_tde_transparency_filter_greyscale = get_atom(ps, "_TDE_TRANSPARENCY_FILTER_GREYSCALE");
ps->atom_win_type_tde_transparency_filter_greyscale_blend = get_atom(ps, "_TDE_TRANSPARENCY_FILTER_GREYSCALE_BLEND");
}
#ifdef CONFIG_XRANDR
@ -7136,6 +7271,22 @@ init_filters(session_t *ps) {
}
}
// Greyscale filter
switch (ps->o.backend) {
case BKEND_XRENDER:
case BKEND_XR_GLX_HYBRID:
{
break;
}
#ifdef CONFIG_VSYNC_OPENGL
case BKEND_GLX:
{
if (!glx_init_greyscale(ps))
return false;
}
#endif
}
return true;
}
@ -7666,6 +7817,7 @@ session_init(session_t *ps_old, int argc, char **argv) {
.atom_win_type_tde_transparent_to_black = None,
.atom_win_type_tde_transparent_to_desktop = None,
.atom_win_type_tde_transparency_filter_greyscale = None,
.atom_win_type_tde_transparency_filter_greyscale_blend = None,
.atoms_wintypes = { 0 },
.track_atom_lst = NULL,

@ -531,6 +531,106 @@ glx_init_blur(session_t *ps) {
#endif
}
// RAJJA FIXME
/**
* Initialize GLX greyscale filter.
*/
bool
glx_init_greyscale(session_t *ps) {
#ifdef CONFIG_VSYNC_OPENGL_GLSL
{
char *lc_numeric_old = mstrcpy(setlocale(LC_NUMERIC, NULL));
// Enforce LC_NUMERIC locale "C" here to make sure decimal point is sane
setlocale(LC_NUMERIC, "C");
// Adapted from http://trac.openscenegraph.org/projects/osg//wiki/Support/Tutorials/ShadersSampleGrayingOut
static const char *FRAG_SHADER_GREYSCALE =
"#version 110\n"
"uniform sampler2D tex_scr;\n"
"uniform sampler2D alpha_scr;\n"
"uniform int enable_blend;\n"
"uniform vec4 greyscale_weights; // [0.3, 0.59, 0.11, 1.0]\n"
"\n"
"void main( void )\n"
"{\n"
" // Fetch the regular RGB texel color from the source texture\n"
" vec4 texel_color = texture2D( tex_scr, gl_TexCoord[0].xy );\n"
"\n"
" //\n"
" // Converting to grayscale:\n"
" //\n"
" // Converting an image to grayscale is done by taking a weighted average of\n"
" // the red, green and blue color components. The standard weights for this\n"
" // type of conversion are (0.30, 0.59, 0.11). Therefore, the gray component\n"
" // or luminance that we need to compute can be defined as a luminance\n"
" // filter like so:\n"
" //\n"
" // luminance = 0.30*R + 0.59*G + 0.11*B\n"
" //\n"
" // If we think of our RGB colors as vectors, we can see that this \n"
" // calculation is actually just a dot product.\n"
" //\n"
"\n"
" vec4 scaledColor = texel_color * greyscale_weights;\n"
" float luminance = scaledColor.r + scaledColor.g + scaledColor.b;\n"
"\n"
" if (enable_blend == 1) {\n"
" // Fetch the regular RGB texel color from the blend texture\n"
" vec4 blend_texel = texture2D( alpha_scr, vec2(gl_TexCoord[0].x, 1.0 - gl_TexCoord[0].y) );\n"
" vec4 grey_pixel = vec4(luminance,luminance,luminance,1);\n"
" gl_FragColor = mix(texel_color, grey_pixel, blend_texel.a);\n"
" }\n"
" else {\n"
" gl_FragColor = vec4(luminance,luminance,luminance,1);\n"
" }\n"
"\n"
"}";
glx_greyscale_t *greyscale_glsl = &ps->psglx->greyscale_glsl;
greyscale_glsl->frag_shader = glx_create_shader(GL_FRAGMENT_SHADER, FRAG_SHADER_GREYSCALE);
if (!greyscale_glsl->frag_shader) {
printf_errf("(): Failed to create fragment shader.");
return false;
}
// Build program
greyscale_glsl->prog = glx_create_program(&greyscale_glsl->frag_shader, 1);
if (!greyscale_glsl->prog) {
printf_errf("(): Failed to create GLSL program.");
return false;
}
// Get uniform addresses
#define P_GET_UNIFM_LOC(name, target) { \
greyscale_glsl->target = glGetUniformLocation(greyscale_glsl->prog, name); \
if (greyscale_glsl->target < 0) { \
printf_errf("(): Failed to get location of uniform '" name "'. Might be troublesome."); \
} \
}
P_GET_UNIFM_LOC("greyscale_weights", unifm_greyscale_weights);
P_GET_UNIFM_LOC("enable_blend", unifm_enable_blend);
P_GET_UNIFM_LOC("tex_scr", unifm_tex_scr);
P_GET_UNIFM_LOC("alpha_scr", unifm_alpha_scr);
#undef P_GET_UNIFM_LOC
// Restore LC_NUMERIC
setlocale(LC_NUMERIC, lc_numeric_old);
free(lc_numeric_old);
}
glx_check_err(ps);
return true;
#else
printf_errf("(): GLSL support not compiled in. Cannot do greyscale with GLX backend.");
return false;
#endif
}
#ifdef CONFIG_VSYNC_OPENGL_GLSL
/**
@ -1387,113 +1487,62 @@ glx_blur_dst_end:
bool
glx_greyscale_dst(session_t *ps, int dx, int dy, int width, int height, float z,
XserverRegion reg_tgt, const reg_data_t *pcache_reg, glx_greyscale_cache_t *pbc) {
glx_texture_t *ptex, XserverRegion reg_tgt, const reg_data_t *pcache_reg, glx_greyscale_cache_t *gsc) {
glx_greyscale_t *greyscale_glsl = &ps->psglx->greyscale_glsl;
assert(greyscale_glsl->prog);
bool ret = false;
// Calculate copy region size
glx_greyscale_cache_t ibc = { .width = 0, .height = 0 };
if (!pbc)
pbc = &ibc;
if (!gsc)
gsc = &ibc;
#ifdef DEBUG_GLX
printf_dbgf("(): %d, %d, %d, %d\n", dx, dy, width, height);
#endif
// Free textures if size inconsistency discovered
if (width != pbc->width || height != pbc->height)
free_glx_gc_resize(ps, pbc);
if (width != gsc->width || height != gsc->height)
free_glx_gc_resize(ps, gsc);
// Generate FBO and textures if needed
if (!pbc->textures[0])
pbc->textures[0] = glx_gen_texture(ps, GL_TEXTURE_2D, width, height);
GLuint tex_scr1 = pbc->textures[0];
pbc->width = width;
pbc->height = height;
// Generate textures
if (!gsc->textures[0])
gsc->textures[0] = glx_gen_texture(ps, GL_TEXTURE_2D, width, height);
GLuint tex_scr1 = gsc->textures[0];
gsc->width = width;
gsc->height = height;
if (!tex_scr1) {
printf_errf("(): Failed to allocate texture.");
goto glx_greyscale_dst_end;
}
// Texture scaling factor
GLfloat texfac_x = 1.0f, texfac_y = 1.0f;
texfac_x /= width;
texfac_y /= height;
// Greyscale conversion in OpenGL ES taken nearly verbatim from this answer on Stack Overflow: http://stackoverflow.com/a/9690145
// Enable texture unit 0 to divide RGB values in our texture by 2
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex_scr1);
if (ptex) {
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, ptex->texture);
}
glActiveTexture(GL_TEXTURE0);
// Read destination pixels into the GL texture
glx_copy_region_to_tex(ps, GL_TEXTURE_2D, dx, dy, dx, dy, width, height);
// Finish setting up texture
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glClientActiveTexture(GL_TEXTURE0);
// GL_MODULATE is Arg0 * Arg1
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
// Configure Arg0
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
// Configure Arg1
float multipliers[4] = {.5, .5, .5, 0.0};
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (GLfloat*)&multipliers);
// Enable texture unit 1 to increase RGB values by .5
glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tex_scr1);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glClientActiveTexture(GL_TEXTURE1);
// GL_ADD is Arg0 + Arg1
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);
// Configure Arg0
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
// Configure Arg1
GLfloat additions[4] = {.5, .5, .5, 0.0};
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (GLfloat*)&additions);
// Texture scaling factor
GLfloat texfac_x = 1.0f, texfac_y = 1.0f;
texfac_x /= width;
texfac_y /= height;
// Enable texture combiner 2 to get a DOT3_RGB product of your RGB values
glActiveTexture(GL_TEXTURE2);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tex_scr1);
glClientActiveTexture(GL_TEXTURE2);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
// GL_DOT3_RGB is 4*((Arg0r - 0.5) * (Arg1r - 0.5) + (Arg0g - 0.5) * (Arg1g - 0.5) + (Arg0b - 0.5) * (Arg1b - 0.5))
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB);
// Configure Arg0
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
// Configure Arg1
// We want this to adjust our DOT3 by R*0.3 + G*0.59 + B*0.11
// So, our actual adjustment will need to take into consideration
// the fact that OpenGL will subtract .5 from our Arg1
// and we need to also take into consideration that we have divided
// our RGB values by 2 and we are multiplying the entire
// DOT3 product by 4
// So, for Red adjustment you will get :
// .65 = (4*(0.3))/2 + 0.5 = (0.3/2) + 0.5
GLfloat weights[4] = {.65, .795, .555, 1.};
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (GLfloat*)&weights);
// glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glUseProgram(greyscale_glsl->prog);
// These coefficients exactly match the non-GL greyscale conversion which uses the XRender PictOpHSLLuminosity operation
glUniform4f(greyscale_glsl->unifm_greyscale_weights, 0.3, 0.59, 0.11, 1.0);
glUniform1i(greyscale_glsl->unifm_enable_blend, ((ptex)?1:0));
glUniform1i(greyscale_glsl->unifm_tex_scr, 0);
glUniform1i(greyscale_glsl->unifm_alpha_scr, 1);
// Render!
{
@ -1527,26 +1576,21 @@ glx_greyscale_dst(session_t *ps, int dx, int dy, int width, int height, float z,
P_PAINTREG_END();
}
glEnd();
// Clean up by disabling your texture combiners or texture units.
glActiveTexture(GL_TEXTURE2);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glDisable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE1);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glDisable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
glClientActiveTexture(GL_TEXTURE0);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glUseProgram(0);
ret = true;
glx_greyscale_dst_end:
if (&ibc == pbc) {
free_glx_gc(ps, pbc);
if (ptex) {
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 0);
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
if (&ibc == gsc) {
free_glx_gc(ps, gsc);
}
glx_check_err(ps);

Loading…
Cancel
Save