e16/src/fx.c

570 lines
13 KiB
C
Raw Normal View History

/*
2007-01-13 11:14:29 -08:00
* Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
* Copyright (C) 2004-2021 Kim Woelders
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies of the Software, its documentation and marketing & publicity
* materials, and acknowledgment shall be given in the documentation, materials
* and software packages that this Software was used.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "config.h"
#include <math.h>
#include <X11/Xlib.h>
#if USE_XRENDER
#define FX_USE_RENDER 1
#include <X11/extensions/Xrender.h>
#endif
#include "E.h"
#include "animation.h"
#include "desktops.h"
#include "dialog.h"
#include "ecompmgr.h"
2006-03-29 11:13:17 -08:00
#include "eimage.h"
#include "emodule.h"
#include "settings.h"
2013-07-05 22:38:44 -07:00
#include "util.h"
#include "xwin.h"
2013-07-05 22:38:44 -07:00
#define M_2PI_F ((float)(2 * M_PI))
#define FX_OP_ENABLE 1 /* Enable, start */
#define FX_OP_DISABLE 2 /* Disable, stop */
#define FX_OP_START 3 /* Start (if enabled) */
#define FX_OP_PAUSE 4
#define FX_OP_DESK 5
2004-12-28 15:46:49 -08:00
typedef struct {
const char *name;
2019-08-14 09:45:13 -07:00
void (*init_func)(const char *name);
void (*ops_func)(int op);
2004-12-28 15:46:49 -08:00
char enabled;
char active;
} FXHandler;
2012-12-28 08:04:35 -08:00
typedef struct {
Win win;
2021-05-06 10:24:22 -07:00
EX_Window root;
EX_Pixmap above;
2012-12-28 08:04:35 -08:00
int count;
float incv, inch, incx;
#if FX_USE_RENDER
EX_Picture pict_buf;
EX_Picture pict_win;
#if USE_COMPOSITE
EX_Picture pict_win_clip;
#endif
#else
2012-12-28 08:04:35 -08:00
GC gc1;
#endif
} FXData;
static void
_FxSetup(FXData * d, unsigned int height)
{
EObj *bgeo;
2012-12-28 08:04:35 -08:00
if (!d->above)
{
bgeo = DeskGetBackgroundObj(DesksGetCurrent());
2012-12-28 08:04:35 -08:00
d->win = EobjGetWin(bgeo);
#if USE_COMPOSITE
if (ECompMgrIsActive() && !Mode.wm.window)
d->root = ECompMgrRootWin();
else
#endif
d->root = EobjGetXwin(bgeo);
d->above = ECreatePixmap(d->win, WinGetW(VROOT), height, 0);
#if FX_USE_RENDER
XRenderPictureAttributes pa;
d->pict_buf = EPictureCreate(NULL, d->above);
d->pict_win = EPictureCreate(NULL, d->root);
#if USE_COMPOSITE
d->pict_win_clip = EPictureCreate(NULL, d->root);
#endif
pa.subwindow_mode = ClipByChildren;
XRenderChangePicture(disp, d->pict_win, CPSubwindowMode, &pa);
#else
XGCValues xgcv;
xgcv.subwindow_mode = ClipByChildren;
2012-12-28 08:04:35 -08:00
if (!d->gc1)
2021-05-06 10:24:22 -07:00
d->gc1 = EXCreateGC(d->root, GCSubwindowMode, &xgcv);
#endif
}
2005-12-06 10:55:18 -08:00
#if USE_COMPOSITE
#if FX_USE_RENDER
EPictureSetClip(d->pict_win_clip, ECompMgrChildClipRegion());
#else
/* As of composite 0.4 we need to set the clip region */
EGCSetClip(d->gc1, ECompMgrChildClipRegion());
#endif
#endif
}
static void
_FxCleanup(FXData * d, int h)
{
if (h == 0)
{
EFreePixmap(d->above);
d->above = NoXID;
d->count = 0;
}
else
{
#if FX_USE_RENDER
EPictureDestroy(d->pict_buf);
EPictureDestroy(d->pict_win);
#if USE_COMPOSITE
EPictureDestroy(d->pict_win_clip);
#endif
#else
EXFreeGC(d->gc1);
#endif
EClearArea(d->win, 0, WinGetH(VROOT) - h, WinGetW(VROOT), h);
#if USE_COMPOSITE
ECompMgrDamageArea(0, WinGetH(VROOT) - h, WinGetW(VROOT), h);
#endif
}
}
static void
_FxCopyArea(FXData * d, int out, int src_x, int src_y, int dst_x, int dst_y,
unsigned int width, unsigned int height)
{
EX_ID src, dst;
#if FX_USE_RENDER
if (out)
{
src = d->pict_buf;
#if USE_COMPOSITE
dst = d->pict_win_clip;
#else
dst = d->pict_win;
#endif
}
else
{
src = d->pict_win;
dst = d->pict_buf;
}
XRenderComposite(disp, PictOpSrc, src, NoXID, dst,
src_x, src_y, 0, 0, dst_x, dst_y, width, height);
#else
if (out)
{
src = d->above;
2021-05-06 10:24:22 -07:00
dst = d->root;
EXCopyAreaGC(src, dst, d->gc1, src_x, src_y, width, height,
dst_x, dst_y);
}
else
{
2021-05-06 10:24:22 -07:00
src = d->root;
dst = d->above;
EXCopyArea(src, dst, src_x, src_y, width, height, dst_x, dst_y);
}
#endif
}
/****************************** RIPPLES *************************************/
#define FX_RIPPLE_WATERH 64
static Animator *fx_ripple = NULL;
static int
FX_ripple_timeout(EObj * eo __UNUSED__, int run __UNUSED__, void *state)
{
FXData *d = (FXData *) state;
int y;
_FxSetup(d, FX_RIPPLE_WATERH * 2);
2012-12-28 08:04:35 -08:00
if (d->count == 0)
_FxCopyArea(d, 0, 0, WinGetH(VROOT) - (FX_RIPPLE_WATERH * 3), 0, 0,
WinGetW(VROOT), FX_RIPPLE_WATERH * 2);
2005-12-06 10:55:18 -08:00
2012-12-28 08:04:35 -08:00
d->count++;
if (d->count > 32)
d->count = 0;
2013-07-05 22:38:44 -07:00
d->incv += 0.40f;
if (d->incv > M_2PI_F)
2012-12-28 08:04:35 -08:00
d->incv = 0;
2013-07-05 22:38:44 -07:00
d->inch += 0.32f;
if (d->inch > M_2PI_F)
2012-12-28 08:04:35 -08:00
d->inch = 0;
2012-12-28 08:04:35 -08:00
for (y = 0; y < FX_RIPPLE_WATERH; y++)
{
2014-04-21 12:11:52 -07:00
float a, p;
int xoff, yoff, yy;
p = (float)(FX_RIPPLE_WATERH - y) / (float)FX_RIPPLE_WATERH;
2012-12-28 08:04:35 -08:00
a = p * p * 48 + d->incv;
2014-04-21 12:11:52 -07:00
yoff = y + (int)(sinf(a) * 7) + 8; /* 0:63 + -7:7 + 8 = 1:78 */
yy = (FX_RIPPLE_WATERH * 2) - yoff; /* 128 - 1:78 = 127:50 */
2014-04-21 12:11:52 -07:00
a = p * p * 64 + d->inch;
xoff = (int)(sinf(a) * 10 * (1 - p));
_FxCopyArea(d, 1, 0, yy, xoff, WinGetH(VROOT) - FX_RIPPLE_WATERH + y,
WinGetW(VROOT), 1);
}
2008-05-24 11:13:17 -07:00
return 4;
}
2004-12-28 15:46:49 -08:00
static void
2005-07-22 10:00:10 -07:00
FX_Ripple_Init(const char *name __UNUSED__)
{
FXData fxd;
2014-04-21 12:11:52 -07:00
memset(&fxd, 0, sizeof(fxd));
2012-12-28 08:04:35 -08:00
fx_ripple = AnimatorAdd(NULL, ANIM_FX_RIPPLES, FX_ripple_timeout, -1, 0,
sizeof(fxd), &fxd);
}
2004-12-28 15:46:49 -08:00
static void
2012-12-28 08:04:35 -08:00
FX_Ripple_Ops(int op)
{
FXData *d;
2012-12-28 08:04:35 -08:00
d = (FXData *) AnimatorGetData(fx_ripple);
2012-12-28 08:04:35 -08:00
if (!d)
return;
2012-12-28 08:04:35 -08:00
_FxCleanup(d, 0);
2012-12-28 08:04:35 -08:00
if (op != FX_OP_DISABLE)
return;
_FxCleanup(d, FX_RIPPLE_WATERH);
2012-12-28 08:04:35 -08:00
AnimatorDel(NULL, fx_ripple);
fx_ripple = NULL;
}
/****************************** WAVES ***************************************/
/* by tsade :) */
/****************************************************************************/
#define FX_WAVE_WATERH 64
#define FX_WAVE_WATERW 64
#define FX_WAVE_DEPTH 10
2013-07-05 22:38:44 -07:00
#define FX_WAVE_CROSSPERIOD 0.42f
2012-12-28 08:04:35 -08:00
static Animator *fx_waves = NULL;
static int
2012-12-28 08:04:35 -08:00
FX_Wave_timeout(EObj * eo __UNUSED__, int run __UNUSED__, void *state)
{
FXData *d = (FXData *) state;
2013-07-05 22:38:44 -07:00
float incx2;
int y;
_FxSetup(d, FX_WAVE_WATERH * 2);
/* On the zero, grab the desktop again. */
2012-12-28 08:04:35 -08:00
if (d->count == 0)
_FxCopyArea(d, 0, 0, WinGetH(VROOT) - (FX_WAVE_WATERH * 3), 0, 0,
WinGetW(VROOT), FX_WAVE_WATERH * 2);
/* Increment and roll the counter */
2012-12-28 08:04:35 -08:00
d->count++;
if (d->count > 32)
d->count = 0;
/* Increment and roll some other variables */
2013-07-05 22:38:44 -07:00
d->incv += 0.40f;
if (d->incv > M_2PI_F)
2012-12-28 08:04:35 -08:00
d->incv = 0;
2013-07-05 22:38:44 -07:00
d->inch += 0.32f;
if (d->inch > M_2PI_F)
2012-12-28 08:04:35 -08:00
d->inch = 0;
2013-07-05 22:38:44 -07:00
d->incx += 0.32f;
if (d->incx > M_2PI_F)
2012-12-28 08:04:35 -08:00
d->incx = 0;
/* Go through the bottom couple (FX_WAVE_WATERH) lines of the window */
for (y = 0; y < FX_WAVE_WATERH; y++)
{
/* Variables */
2014-04-21 12:11:52 -07:00
float a, p;
int xoff, yoff, yy;
int x;
/* Figure out the side-to-side movement */
2014-04-21 12:11:52 -07:00
p = (float)(FX_WAVE_WATERH - y) / (float)FX_WAVE_WATERH;
2012-12-28 08:04:35 -08:00
a = p * p * 48 + d->incv;
2014-04-21 12:11:52 -07:00
yoff = y + (int)(sinf(a) * 7) + 8; /* 0:63 + -7:7 + 8 = 1:78 */
yy = (FX_WAVE_WATERH * 2) - yoff; /* 128 - 1:78 = 127:50 */
2014-04-21 12:11:52 -07:00
a = p * p * 64 + d->inch;
xoff = (int)(sinf(a) * 10 * (1 - p));
/* Set up the next part */
2012-12-28 08:04:35 -08:00
incx2 = d->incx;
/* Go through the width of the screen, in block sizes */
for (x = 0; x < WinGetW(VROOT); x += FX_WAVE_WATERW)
{
/* Variables */
int sx;
/* Add something to incx2 and roll it */
incx2 += FX_WAVE_CROSSPERIOD;
2013-07-05 22:38:44 -07:00
if (incx2 > M_2PI_F)
incx2 = 0;
/* Figure it out */
2013-07-07 15:05:20 -07:00
sx = (int)(sinf(incx2) * FX_WAVE_DEPTH);
/* Display this block */
_FxCopyArea(d, 1, x, yy, xoff + x,
WinGetH(VROOT) - FX_WAVE_WATERH + y + sx,
FX_WAVE_WATERW, 1);
}
}
return 4;
}
static void
FX_Waves_Init(const char *name __UNUSED__)
{
FXData fxd;
2014-04-21 12:11:52 -07:00
memset(&fxd, 0, sizeof(fxd));
2012-12-28 08:04:35 -08:00
fx_waves = AnimatorAdd(NULL, ANIM_FX_WAVES, FX_Wave_timeout, -1, 0,
sizeof(fxd), &fxd);
}
static void
2012-12-28 08:04:35 -08:00
FX_Waves_Ops(int op)
{
FXData *d;
2012-12-28 08:04:35 -08:00
d = (FXData *) AnimatorGetData(fx_waves);
2012-12-28 08:04:35 -08:00
if (!d)
return;
_FxCleanup(d, 0);
2012-12-28 08:04:35 -08:00
if (op != FX_OP_DISABLE)
return;
2012-12-28 08:04:35 -08:00
_FxCleanup(d, 2 * FX_WAVE_WATERH + FX_WAVE_DEPTH);
2012-12-28 08:04:35 -08:00
AnimatorDel(NULL, fx_waves);
fx_waves = NULL;
}
/****************************************************************************/
2004-12-28 15:46:49 -08:00
#define fx_rip fx_handlers[0]
#define fx_wav fx_handlers[1]
2004-12-28 15:46:49 -08:00
static FXHandler fx_handlers[] = {
2012-12-28 08:04:35 -08:00
{"ripples", FX_Ripple_Init, FX_Ripple_Ops, 0, 0},
{"waves", FX_Waves_Init, FX_Waves_Ops, 0, 0},
2004-12-28 15:46:49 -08:00
};
/****************************** Effect handlers *****************************/
static void
FX_Op(FXHandler * fxh, int op)
2004-12-28 15:46:49 -08:00
{
switch (op)
{
case FX_OP_ENABLE:
if (fxh->enabled)
break;
fxh->enabled = 1;
goto do_start;
2004-12-28 15:46:49 -08:00
case FX_OP_DISABLE:
if (!fxh->enabled)
break;
fxh->enabled = 0;
goto do_stop;
2004-12-28 15:46:49 -08:00
case FX_OP_START:
if (!fxh->enabled)
2004-12-28 15:46:49 -08:00
break;
do_start:
if (fxh->active)
break;
fxh->init_func(fxh->name);
fxh->active = 1;
2004-12-28 15:46:49 -08:00
break;
case FX_OP_PAUSE:
2004-12-28 15:46:49 -08:00
if (!fxh->enabled)
break;
do_stop:
if (!fxh->active)
break;
2012-12-28 08:04:35 -08:00
fxh->ops_func(FX_OP_DISABLE);
fxh->active = 0;
2004-12-28 15:46:49 -08:00
break;
case FX_OP_DESK:
if (!fxh->enabled)
break;
2012-12-28 08:04:35 -08:00
fxh->ops_func(FX_OP_DESK);
break;
2004-12-28 15:46:49 -08:00
}
}
static void
FX_OpForEach(int op)
2004-12-28 15:46:49 -08:00
{
unsigned int i;
for (i = 0; i < E_ARRAY_SIZE(fx_handlers); i++)
FX_Op(&fx_handlers[i], op);
2004-12-28 15:46:49 -08:00
}
static void
FxCfgFunc(void *item __UNUSED__, const char *value)
2004-12-28 15:46:49 -08:00
{
FXHandler *fxh = NULL;
2004-12-28 15:46:49 -08:00
if (item == &fx_rip.enabled)
fxh = &fx_rip;
else if (item == &fx_wav.enabled)
fxh = &fx_wav;
if (!fxh)
return;
2004-12-28 15:46:49 -08:00
FX_Op(fxh, atoi(value) ? FX_OP_ENABLE : FX_OP_DISABLE);
2004-12-28 15:46:49 -08:00
}
/****************************************************************************/
/*
* Fx Module
*/
static void
FxSighan(int sig, void *prm __UNUSED__)
{
switch (sig)
{
case ESIGNAL_START:
FX_OpForEach(FX_OP_START);
2004-12-28 15:46:49 -08:00
break;
case ESIGNAL_DESK_SWITCH_START:
break;
case ESIGNAL_DESK_SWITCH_DONE:
FX_OpForEach(FX_OP_DESK);
2004-12-28 15:46:49 -08:00
break;
case ESIGNAL_ANIMATION_SUSPEND:
FX_OpForEach(FX_OP_PAUSE);
2010-06-06 03:05:35 -07:00
break;
case ESIGNAL_ANIMATION_RESUME:
FX_OpForEach(FX_OP_START);
2004-12-28 15:46:49 -08:00
break;
}
}
#if ENABLE_DIALOGS
2004-12-28 15:46:49 -08:00
static char tmp_effect_ripples;
static char tmp_effect_waves;
static void
_DlgApplyFx(Dialog * d __UNUSED__, int val __UNUSED__, void *data __UNUSED__)
2004-12-28 15:46:49 -08:00
{
FX_Op(&fx_rip, tmp_effect_ripples ? FX_OP_ENABLE : FX_OP_DISABLE);
FX_Op(&fx_wav, tmp_effect_waves ? FX_OP_ENABLE : FX_OP_DISABLE);
2004-12-28 15:46:49 -08:00
autosave();
}
static void
_DlgFillFx(Dialog * d __UNUSED__, DItem * table, void *data __UNUSED__)
2004-12-28 15:46:49 -08:00
{
DItem *di;
2004-12-28 15:46:49 -08:00
tmp_effect_ripples = fx_rip.enabled;
tmp_effect_waves = fx_wav.enabled;
2004-12-28 15:46:49 -08:00
DialogItemTableSetOptions(table, 1, 0, 0, 0);
/* Effects */
di = DialogAddItem(table, DITEM_TEXT);
DialogItemSetText(di, _("Effects"));
2004-12-28 15:46:49 -08:00
di = DialogAddItem(table, DITEM_CHECKBUTTON);
DialogItemSetText(di, _("Ripples"));
2004-12-28 15:46:49 -08:00
DialogItemCheckButtonSetPtr(di, &tmp_effect_ripples);
di = DialogAddItem(table, DITEM_CHECKBUTTON);
DialogItemSetText(di, _("Waves"));
2004-12-28 15:46:49 -08:00
DialogItemCheckButtonSetPtr(di, &tmp_effect_waves);
}
const DialogDef DlgFx = {
"CONFIGURE_FX",
2014-04-25 14:07:58 -07:00
N_("FX"), N_("Special FX Settings"),
0,
SOUND_SETTINGS_FX,
"pix/fx.png",
N_("Enlightenment Special Effects\n" "Settings Dialog"),
_DlgFillFx,
DLG_OAC, _DlgApplyFx, NULL
};
#endif /* ENABLE_DIALOGS */
#define CFR_FUNC_BOOL(conf, name, dflt, func) \
{ #name, &conf, ITEM_TYPE_BOOL, dflt, func }
2004-12-28 15:46:49 -08:00
static const CfgItem FxCfgItems[] = {
CFR_FUNC_BOOL(fx_handlers[0].enabled, ripples.enabled, 0, FxCfgFunc),
CFR_FUNC_BOOL(fx_handlers[1].enabled, waves.enabled, 0, FxCfgFunc),
2004-12-28 15:46:49 -08:00
};
/*
* Module descriptor
*/
extern const EModule ModEffects;
const EModule ModEffects = {
"effects", "fx",
2004-12-28 15:46:49 -08:00
FxSighan,
{0, NULL},
MOD_ITEMS(FxCfgItems)
2004-12-28 15:46:49 -08:00
};