All pastes #573200 Raw Edit

Miscellany

public text v1 · immutable
·published 2007-06-18 01:07 UTC
rendered paste body
/*
 * Compiz reflection effect plugin
 *
 * mblur.c
 *
 * Copyright : (C) 2007 by Dennis Kasprzyk
 * E-mail    : onestone@beryl-project.org
 *
 *
 * 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.
 *
 */

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include <X11/Xatom.h>
#include <X11/extensions/Xrender.h>

#include <compiz.h>

#include "reflex_options.h"


static int displayPrivateIndex = 0;

typedef struct _ReflexDisplay
{
	int screenPrivateIndex;
} ReflexDisplay;


typedef struct _ReflexScreen
{
	int windowPrivateIndex;

	DrawWindowTextureProc drawWindowTexture;

	Bool imageLoaded;
	CompTexture image;
	unsigned int width;
	unsigned int height;

	int function;
} ReflexScreen;

#define GET_REFLEX_DISPLAY(d)                                  \
    ((ReflexDisplay *) (d)->privates[displayPrivateIndex].ptr)

#define REFLEX_DISPLAY(d)                                      \
    ReflexDisplay *rd = GET_REFLEX_DISPLAY (d)

#define GET_REFLEX_SCREEN(s, rd)                               \
    ((ReflexScreen *) (s)->privates[(rd)->screenPrivateIndex].ptr)

#define REFLEX_SCREEN(s)                                       \
    ReflexScreen *rs = GET_REFLEX_SCREEN (s, GET_REFLEX_DISPLAY (s->display))

static int
getReflexFragmentFunction (CompScreen * s, CompTexture * texture,
						   int param, int unit)
{
	CompFunctionData *data;

	REFLEX_SCREEN (s);

	int target;
	char *targetString;

	if (texture->target == GL_TEXTURE_2D)
	{
		target = COMP_FETCH_TARGET_2D;
	}
	else
	{
		target = COMP_FETCH_TARGET_RECT;
	}

	if (rs->image.target == GL_TEXTURE_2D)
	{
		targetString = "2D";
	}
	else
	{
		targetString = "RECT";
	}


	if (rs->function)
		return rs->function;

	data = createFunctionData ();
	if (data)
	{
		Bool ok = TRUE;
		int handle = 0;
		char str[1024];

		ok &= addTempHeaderOpToFunctionData (data, "image");
		ok &= addTempHeaderOpToFunctionData (data, "tmp");

		ok &= addFetchOpToFunctionData (data, "output", NULL, target);
		ok &= addColorOpToFunctionData (data, "output", "output");

		snprintf (str, 1024,
				  "MUL tmp, fragment.position, program.env[%d];"
				  , param);
		ok &= addDataOpToFunctionData (data, str);

		snprintf (str, 1024,
				  "TEX output, tmp, texture[%d], %s;", unit, targetString);
		ok &= addDataOpToFunctionData (data, str);

		if (!ok)
		{
			destroyFunctionData (data);
			return 0;
		}

		handle = createFragmentFunction (s, "reflex", data);

		rs->function = handle;

		destroyFunctionData (data);

		return handle;
	}

	return 0;
}

static void
reflexScreenOptionChanged (CompScreen * s,
						   CompOption * opt, ReflexScreenOptions num)
{
	REFLEX_SCREEN (s);
	switch (num)
	{
	case ReflexScreenOptionFile:
		if (rs->imageLoaded)
		{
			finiTexture (s, &rs->image);
			initTexture (s, &rs->image);
		}
		rs->imageLoaded =
			readImageToTexture (s, &rs->image, reflexGetFile (s), &rs->width,
								&rs->height);
		damageScreen (s);
		break;
	default:
		damageScreen (s);
		break;
	}
}

static void
reflexDrawWindowTexture (CompWindow * w,
						 CompTexture * texture,
						 const FragmentAttrib * attrib, unsigned int mask)
{
	CompScreen *s = w->screen;
	REFLEX_SCREEN (s);

	Bool enabled = (texture == w->texture) ?
		reflexGetWindow (s) : reflexGetDecoration (s);

	if (enabled && matchEval (reflexGetMatch (s), w) && rs->imageLoaded &&
		w->screen->fragmentProgram)
	{
		FragmentAttrib fa = *attrib;
		int function;
		int unit = 0;
		int param;
		float tx, ty, dx, mx;

		mx = w->attrib.x + (w->width / 2);
		mx /= s->width / 2.0;
		mx -= 1.0;
		mx *= -0.065;

		if (rs->image.target == GL_TEXTURE_2D)
		{
			tx = 1.0 / s->width;
			ty = 1.0 / s->height;
			dx = mx;
		}
		else
		{
			tx = 1.0 / s->width * rs->width;
			ty = 1.0 / s->height * rs->height;
			dx = mx * rs->width;
		}



		unit = allocFragmentTextureUnits (&fa, 1);
		param = allocFragmentParameters (&fa, 1);

		function =
			getReflexFragmentFunction (w->screen, texture, param, unit);
		if (function)
		{
			addFragmentFunction (&fa, function);
			(*s->activeTexture) (GL_TEXTURE0_ARB + unit);
			enableTexture (s, &rs->image, COMP_TEXTURE_FILTER_GOOD);
			(*s->activeTexture) (GL_TEXTURE0_ARB);
			(*s->programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB, param,
										 1.0, 1.0, 0.0f, 0.0f);
			
		}
		UNWRAP (rs, w->screen, drawWindowTexture);
		(*w->screen->drawWindowTexture) (w, texture, &fa, mask);
		WRAP (rs, w->screen, drawWindowTexture, reflexDrawWindowTexture);


		if (unit)
		{
			(*s->activeTexture) (GL_TEXTURE0_ARB + unit);
			disableTexture (s, &rs->image);
			(*s->activeTexture) (GL_TEXTURE0_ARB);
		}
	}
	else
	{
		UNWRAP (rs, w->screen, drawWindowTexture);
		(*w->screen->drawWindowTexture) (w, texture, attrib, mask);
		WRAP (rs, w->screen, drawWindowTexture, reflexDrawWindowTexture);
	}
}



static Bool
reflexInitDisplay (CompPlugin * p, CompDisplay * d)
{
	ReflexDisplay *rd;

	rd = malloc (sizeof (ReflexDisplay));
	if (!rd)
		return FALSE;

	rd->screenPrivateIndex = allocateScreenPrivateIndex (d);
	if (rd->screenPrivateIndex < 0)
	{
		free (rd);
		return FALSE;
	}

	d->privates[displayPrivateIndex].ptr = rd;

	return TRUE;
}

static void
reflexFiniDisplay (CompPlugin * p, CompDisplay * d)
{
	REFLEX_DISPLAY (d);
	freeScreenPrivateIndex (d, rd->screenPrivateIndex);

	free (rd);
}


static Bool
reflexInitScreen (CompPlugin * p, CompScreen * s)
{
	ReflexScreen *rs;

	REFLEX_DISPLAY (s->display);

	rs = malloc (sizeof (ReflexScreen));
	if (!rs)
		return FALSE;

	rs->windowPrivateIndex = allocateWindowPrivateIndex (s);
	if (rs->windowPrivateIndex < 0)
	{
		free (rs);
		return FALSE;
	}

	initTexture (s, &rs->image);

	rs->imageLoaded = readImageToTexture (s, &rs->image, reflexGetFile (s),
										  &rs->width, &rs->height);
	reflexSetFileNotify (s, reflexScreenOptionChanged);

	s->privates[rd->screenPrivateIndex].ptr = rs;

	rs->function = 0;

	WRAP (rs, s, drawWindowTexture, reflexDrawWindowTexture);

	return TRUE;
}


static void
reflexFiniScreen (CompPlugin * p, CompScreen * s)
{
	REFLEX_SCREEN (s);

	freeWindowPrivateIndex (s, rs->windowPrivateIndex);

	UNWRAP (rs, s, drawWindowTexture);

	if (rs->function)
		destroyFragmentFunction (s, rs->function);

	free (rs);
}

static Bool
reflexInit (CompPlugin * p)
{
	displayPrivateIndex = allocateDisplayPrivateIndex ();
	if (displayPrivateIndex < 0)
		return FALSE;

	return TRUE;
}

static void
reflexFini (CompPlugin * p)
{
	if (displayPrivateIndex >= 0)
		freeDisplayPrivateIndex (displayPrivateIndex);
}

static int
reflexGetVersion (CompPlugin * plugin, int version)
{
	return ABIVERSION;
}

CompPluginVTable reflexVTable = {
	"reflex",
	reflexGetVersion,
	0,
	reflexInit,
	reflexFini,
	reflexInitDisplay,
	reflexFiniDisplay,
	reflexInitScreen,
	reflexFiniScreen,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0
};

CompPluginVTable *
getCompPluginInfo (void)
{
	return &reflexVTable;
}