You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1825 lines
37 KiB
1825 lines
37 KiB
4 years ago
|
/*
|
||
|
* Copyright © 2006 Novell, Inc.
|
||
|
*
|
||
|
* Permission to use, copy, modify, distribute, and sell this software
|
||
|
* and its documentation for any purpose is hereby granted without
|
||
|
* fee, provided that the above copyright notice appear in all copies
|
||
|
* and that both that copyright notice and this permission notice
|
||
|
* appear in supporting documentation, and that the name of
|
||
|
* Novell, Inc. not be used in advertising or publicity pertaining to
|
||
|
* distribution of the software without specific, written prior permission.
|
||
|
* Novell, Inc. makes no representations about the suitability of this
|
||
|
* software for any purpose. It is provided "as is" without express or
|
||
|
* implied warranty.
|
||
|
*
|
||
|
* NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
|
||
|
* NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||
|
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||
|
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||
|
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||
|
*
|
||
|
* Author: David Reveman <davidr@novell.com>
|
||
|
*/
|
||
|
|
||
|
#ifdef HAVE_CONFIG_H
|
||
|
# include "../config.h"
|
||
|
#endif
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <stdio.h>
|
||
|
#include <string.h>
|
||
|
#include <math.h>
|
||
|
|
||
|
#include <compiz-core.h>
|
||
|
|
||
|
#define TEXTURE_SIZE 256
|
||
|
|
||
|
#define K 0.1964f
|
||
|
|
||
|
#define TEXTURE_NUM 3
|
||
|
|
||
|
typedef struct _WaterFunction {
|
||
|
struct _WaterFunction *next;
|
||
|
|
||
|
int handle;
|
||
|
int target;
|
||
|
int param;
|
||
|
int unit;
|
||
|
} WaterFunction;
|
||
|
|
||
|
#define TINDEX(ws, i) (((ws)->tIndex + (i)) % TEXTURE_NUM)
|
||
|
|
||
|
#define CLAMP(v, min, max) \
|
||
|
if ((v) > (max)) \
|
||
|
(v) = (max); \
|
||
|
else if ((v) < (min)) \
|
||
|
(v) = (min)
|
||
|
|
||
|
#define WATER_INITIATE_MODIFIERS_DEFAULT (ControlMask | CompSuperMask)
|
||
|
|
||
|
static CompMetadata waterMetadata;
|
||
|
|
||
|
static int displayPrivateIndex;
|
||
|
|
||
|
static int waterLastPointerX = 0;
|
||
|
static int waterLastPointerY = 0;
|
||
|
|
||
|
#define WATER_DISPLAY_OPTION_INITIATE_KEY 0
|
||
|
#define WATER_DISPLAY_OPTION_TOGGLE_RAIN_KEY 1
|
||
|
#define WATER_DISPLAY_OPTION_TOGGLE_WIPER_KEY 2
|
||
|
#define WATER_DISPLAY_OPTION_OFFSET_SCALE 3
|
||
|
#define WATER_DISPLAY_OPTION_RAIN_DELAY 4
|
||
|
#define WATER_DISPLAY_OPTION_TITLE_WAVE 5
|
||
|
#define WATER_DISPLAY_OPTION_POINT 6
|
||
|
#define WATER_DISPLAY_OPTION_LINE 7
|
||
|
#define WATER_DISPLAY_OPTION_NUM 8
|
||
|
|
||
|
typedef struct _WaterDisplay {
|
||
|
int screenPrivateIndex;
|
||
|
|
||
|
CompOption opt[WATER_DISPLAY_OPTION_NUM];
|
||
|
|
||
|
HandleEventProc handleEvent;
|
||
|
|
||
|
float offsetScale;
|
||
|
} WaterDisplay;
|
||
|
|
||
|
typedef struct _WaterScreen {
|
||
|
PreparePaintScreenProc preparePaintScreen;
|
||
|
DonePaintScreenProc donePaintScreen;
|
||
|
DrawWindowTextureProc drawWindowTexture;
|
||
|
|
||
|
int grabIndex;
|
||
|
int width, height;
|
||
|
|
||
|
GLuint program;
|
||
|
GLuint texture[TEXTURE_NUM];
|
||
|
|
||
|
int tIndex;
|
||
|
GLenum target;
|
||
|
GLfloat tx, ty;
|
||
|
|
||
|
int count;
|
||
|
|
||
|
GLuint fbo;
|
||
|
GLint fboStatus;
|
||
|
|
||
|
void *data;
|
||
|
float *d0;
|
||
|
float *d1;
|
||
|
unsigned char *t0;
|
||
|
|
||
|
CompTimeoutHandle rainHandle;
|
||
|
CompTimeoutHandle wiperHandle;
|
||
|
|
||
|
float wiperAngle;
|
||
|
float wiperSpeed;
|
||
|
|
||
|
WaterFunction *bumpMapFunctions;
|
||
|
} WaterScreen;
|
||
|
|
||
|
#define GET_WATER_DISPLAY(d) \
|
||
|
((WaterDisplay *) (d)->base.privates[displayPrivateIndex].ptr)
|
||
|
|
||
|
#define WATER_DISPLAY(d) \
|
||
|
WaterDisplay *wd = GET_WATER_DISPLAY (d)
|
||
|
|
||
|
#define GET_WATER_SCREEN(s, wd) \
|
||
|
((WaterScreen *) (s)->base.privates[(wd)->screenPrivateIndex].ptr)
|
||
|
|
||
|
#define WATER_SCREEN(s) \
|
||
|
WaterScreen *ws = GET_WATER_SCREEN (s, GET_WATER_DISPLAY (s->display))
|
||
|
|
||
|
#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
|
||
|
|
||
|
static Bool
|
||
|
waterRainTimeout (void *closure);
|
||
|
|
||
|
static Bool
|
||
|
waterWiperTimeout (void *closure);
|
||
|
|
||
|
static const char *waterFpString =
|
||
|
"!!ARBfp1.0"
|
||
|
|
||
|
"PARAM param = program.local[0];"
|
||
|
"ATTRIB t11 = fragment.texcoord[0];"
|
||
|
|
||
|
"TEMP t01, t21, t10, t12;"
|
||
|
"TEMP c11, c01, c21, c10, c12;"
|
||
|
"TEMP prev, v, temp, accel;"
|
||
|
|
||
|
"TEX prev, t11, texture[0], %s;"
|
||
|
"TEX c11, t11, texture[1], %s;"
|
||
|
|
||
|
/* sample offsets */
|
||
|
"ADD t01, t11, { - %f, 0.0, 0.0, 0.0 };"
|
||
|
"ADD t21, t11, { %f, 0.0, 0.0, 0.0 };"
|
||
|
"ADD t10, t11, { 0.0, - %f, 0.0, 0.0 };"
|
||
|
"ADD t12, t11, { 0.0, %f, 0.0, 0.0 };"
|
||
|
|
||
|
/* fetch nesseccary samples */
|
||
|
"TEX c01, t01, texture[1], %s;"
|
||
|
"TEX c21, t21, texture[1], %s;"
|
||
|
"TEX c10, t10, texture[1], %s;"
|
||
|
"TEX c12, t12, texture[1], %s;"
|
||
|
|
||
|
/* x/y normals from height */
|
||
|
"MOV v, { 0.0, 0.0, 0.75, 0.0 };"
|
||
|
"SUB v.x, c12.w, c10.w;"
|
||
|
"SUB v.y, c01.w, c21.w;"
|
||
|
|
||
|
/* bumpiness */
|
||
|
"MUL v, v, 1.5;"
|
||
|
|
||
|
/* normalize */
|
||
|
"MAD temp, v.x, v.x, 1.0;"
|
||
|
"MAD temp, v.y, v.y, temp;"
|
||
|
"RSQ temp, temp.x;"
|
||
|
"MUL v, v, temp;"
|
||
|
|
||
|
/* add scale and bias to normal */
|
||
|
"MAD v, v, 0.5, 0.5;"
|
||
|
|
||
|
/* done with computing the normal, continue with computing the next
|
||
|
height value */
|
||
|
"ADD accel, c10, c12;"
|
||
|
"ADD accel, c01, accel;"
|
||
|
"ADD accel, c21, accel;"
|
||
|
"MAD accel, -4.0, c11, accel;"
|
||
|
|
||
|
/* store new height in alpha component */
|
||
|
"MAD v.w, 2.0, c11, -prev.w;"
|
||
|
"MAD v.w, accel, param.x, v.w;"
|
||
|
|
||
|
/* fade out height */
|
||
|
"MUL v.w, v.w, param.y;"
|
||
|
|
||
|
"MOV result.color, v;"
|
||
|
|
||
|
"END";
|
||
|
|
||
|
static int
|
||
|
loadFragmentProgram (CompScreen *s,
|
||
|
GLuint *program,
|
||
|
const char *string)
|
||
|
{
|
||
|
GLint errorPos;
|
||
|
|
||
|
/* clear errors */
|
||
|
glGetError ();
|
||
|
|
||
|
if (!*program)
|
||
|
(*s->genPrograms) (1, program);
|
||
|
|
||
|
(*s->bindProgram) (GL_FRAGMENT_PROGRAM_ARB, *program);
|
||
|
(*s->programString) (GL_FRAGMENT_PROGRAM_ARB,
|
||
|
GL_PROGRAM_FORMAT_ASCII_ARB,
|
||
|
strlen (string), string);
|
||
|
|
||
|
glGetIntegerv (GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
|
||
|
if (glGetError () != GL_NO_ERROR || errorPos != -1)
|
||
|
{
|
||
|
compLogMessage ("water", CompLogLevelError,
|
||
|
"failed to load bump map program");
|
||
|
|
||
|
(*s->deletePrograms) (1, program);
|
||
|
*program = 0;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
loadWaterProgram (CompScreen *s)
|
||
|
{
|
||
|
char buffer[1024];
|
||
|
|
||
|
WATER_SCREEN (s);
|
||
|
|
||
|
if (ws->target == GL_TEXTURE_2D)
|
||
|
sprintf (buffer, waterFpString,
|
||
|
"2D", "2D",
|
||
|
1.0f / ws->width, 1.0f / ws->width,
|
||
|
1.0f / ws->height, 1.0f / ws->height,
|
||
|
"2D", "2D", "2D", "2D");
|
||
|
else
|
||
|
sprintf (buffer, waterFpString,
|
||
|
"RECT", "RECT",
|
||
|
1.0f, 1.0f, 1.0f, 1.0f,
|
||
|
"RECT", "RECT", "RECT", "RECT");
|
||
|
|
||
|
return loadFragmentProgram (s, &ws->program, buffer);
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
getBumpMapFragmentFunction (CompScreen *s,
|
||
|
CompTexture *texture,
|
||
|
int unit,
|
||
|
int param)
|
||
|
{
|
||
|
WaterFunction *function;
|
||
|
CompFunctionData *data;
|
||
|
int target;
|
||
|
|
||
|
WATER_SCREEN (s);
|
||
|
|
||
|
if (texture->target == GL_TEXTURE_2D)
|
||
|
target = COMP_FETCH_TARGET_2D;
|
||
|
else
|
||
|
target = COMP_FETCH_TARGET_RECT;
|
||
|
|
||
|
for (function = ws->bumpMapFunctions; function; function = function->next)
|
||
|
{
|
||
|
if (function->param == param &&
|
||
|
function->unit == unit &&
|
||
|
function->target == target)
|
||
|
return function->handle;
|
||
|
}
|
||
|
|
||
|
data = createFunctionData ();
|
||
|
if (data)
|
||
|
{
|
||
|
static char *temp[] = { "normal", "temp", "total", "bump", "offset" };
|
||
|
int i, handle = 0;
|
||
|
char str[1024];
|
||
|
|
||
|
for (i = 0; i < sizeof (temp) / sizeof (temp[0]); i++)
|
||
|
{
|
||
|
if (!addTempHeaderOpToFunctionData (data, temp[i]))
|
||
|
{
|
||
|
destroyFunctionData (data);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
snprintf (str, 1024,
|
||
|
|
||
|
/* get normal from normal map */
|
||
|
"TEX normal, fragment.texcoord[%d], texture[%d], %s;"
|
||
|
|
||
|
/* save height */
|
||
|
"MOV offset, normal;"
|
||
|
|
||
|
/* remove scale and bias from normal */
|
||
|
"MAD normal, normal, 2.0, -1.0;"
|
||
|
|
||
|
/* normalize the normal map */
|
||
|
"DP3 temp, normal, normal;"
|
||
|
"RSQ temp, temp.x;"
|
||
|
"MUL normal, normal, temp;"
|
||
|
|
||
|
/* scale down normal by height and constant and use as
|
||
|
offset in texture */
|
||
|
"MUL offset, normal, offset.w;"
|
||
|
"MUL offset, offset, program.env[%d];",
|
||
|
|
||
|
unit, unit,
|
||
|
(ws->target == GL_TEXTURE_2D) ? "2D" : "RECT",
|
||
|
param);
|
||
|
|
||
|
if (!addDataOpToFunctionData (data, str))
|
||
|
{
|
||
|
destroyFunctionData (data);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (!addFetchOpToFunctionData (data, "output", "offset.yxzz", target))
|
||
|
{
|
||
|
destroyFunctionData (data);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
snprintf (str, 1024,
|
||
|
|
||
|
/* normal dot lightdir, this should eventually be
|
||
|
changed to a real light vector */
|
||
|
"DP3 bump, normal, { 0.707, 0.707, 0.0, 0.0 };"
|
||
|
"MUL bump, bump, state.light[0].diffuse;");
|
||
|
|
||
|
if (!addDataOpToFunctionData (data, str))
|
||
|
{
|
||
|
destroyFunctionData (data);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (!addColorOpToFunctionData (data, "output", "output"))
|
||
|
{
|
||
|
destroyFunctionData (data);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
snprintf (str, 1024,
|
||
|
|
||
|
/* diffuse per-vertex lighting, opacity and brightness
|
||
|
and add lightsource bump color */
|
||
|
"ADD output, output, bump;");
|
||
|
|
||
|
if (!addDataOpToFunctionData (data, str))
|
||
|
{
|
||
|
destroyFunctionData (data);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
function = malloc (sizeof (WaterFunction));
|
||
|
if (function)
|
||
|
{
|
||
|
handle = createFragmentFunction (s, "water", data);
|
||
|
|
||
|
function->handle = handle;
|
||
|
function->target = target;
|
||
|
function->param = param;
|
||
|
function->unit = unit;
|
||
|
|
||
|
function->next = ws->bumpMapFunctions;
|
||
|
ws->bumpMapFunctions = function;
|
||
|
}
|
||
|
|
||
|
destroyFunctionData (data);
|
||
|
|
||
|
return handle;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
allocTexture (CompScreen *s,
|
||
|
int index)
|
||
|
{
|
||
|
WATER_SCREEN (s);
|
||
|
|
||
|
glGenTextures (1, &ws->texture[index]);
|
||
|
glBindTexture (ws->target, ws->texture[index]);
|
||
|
|
||
|
glTexParameteri (ws->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||
|
glTexParameteri (ws->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||
|
glTexParameteri (ws->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||
|
glTexParameteri (ws->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||
|
|
||
|
glTexImage2D (ws->target,
|
||
|
0,
|
||
|
GL_RGBA,
|
||
|
ws->width,
|
||
|
ws->height,
|
||
|
0,
|
||
|
GL_BGRA,
|
||
|
|
||
|
#if IMAGE_BYTE_ORDER == MSBFirst
|
||
|
GL_UNSIGNED_INT_8_8_8_8_REV,
|
||
|
#else
|
||
|
GL_UNSIGNED_BYTE,
|
||
|
#endif
|
||
|
|
||
|
ws->t0);
|
||
|
|
||
|
glBindTexture (ws->target, 0);
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
fboPrologue (CompScreen *s,
|
||
|
int tIndex)
|
||
|
{
|
||
|
WATER_SCREEN (s);
|
||
|
|
||
|
if (!ws->fbo)
|
||
|
return 0;
|
||
|
|
||
|
if (!ws->texture[tIndex])
|
||
|
allocTexture (s, tIndex);
|
||
|
|
||
|
(*s->bindFramebuffer) (GL_FRAMEBUFFER_EXT, ws->fbo);
|
||
|
|
||
|
(*s->framebufferTexture2D) (GL_FRAMEBUFFER_EXT,
|
||
|
GL_COLOR_ATTACHMENT0_EXT,
|
||
|
ws->target, ws->texture[tIndex],
|
||
|
0);
|
||
|
|
||
|
glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT);
|
||
|
glReadBuffer (GL_COLOR_ATTACHMENT0_EXT);
|
||
|
|
||
|
/* check status the first time */
|
||
|
if (!ws->fboStatus)
|
||
|
{
|
||
|
ws->fboStatus = (*s->checkFramebufferStatus) (GL_FRAMEBUFFER_EXT);
|
||
|
if (ws->fboStatus != GL_FRAMEBUFFER_COMPLETE_EXT)
|
||
|
{
|
||
|
compLogMessage ("water", CompLogLevelError,
|
||
|
"framebuffer incomplete");
|
||
|
|
||
|
(*s->bindFramebuffer) (GL_FRAMEBUFFER_EXT, 0);
|
||
|
(*s->deleteFramebuffers) (1, &ws->fbo);
|
||
|
|
||
|
glDrawBuffer (GL_BACK);
|
||
|
glReadBuffer (GL_BACK);
|
||
|
|
||
|
ws->fbo = 0;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
glViewport (0, 0, ws->width, ws->height);
|
||
|
glMatrixMode (GL_PROJECTION);
|
||
|
glPushMatrix ();
|
||
|
glLoadIdentity ();
|
||
|
glOrtho (0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
|
||
|
glMatrixMode (GL_MODELVIEW);
|
||
|
glPushMatrix ();
|
||
|
glLoadIdentity ();
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
fboEpilogue (CompScreen *s)
|
||
|
{
|
||
|
(*s->bindFramebuffer) (GL_FRAMEBUFFER_EXT, 0);
|
||
|
|
||
|
glMatrixMode (GL_PROJECTION);
|
||
|
glLoadIdentity ();
|
||
|
glMatrixMode (GL_MODELVIEW);
|
||
|
glLoadIdentity ();
|
||
|
glDepthRange (0, 1);
|
||
|
glViewport (-1, -1, 2, 2);
|
||
|
glRasterPos2f (0, 0);
|
||
|
|
||
|
s->rasterX = s->rasterY = 0;
|
||
|
|
||
|
setDefaultViewport (s);
|
||
|
|
||
|
glMatrixMode (GL_PROJECTION);
|
||
|
glPopMatrix ();
|
||
|
glMatrixMode (GL_MODELVIEW);
|
||
|
glPopMatrix ();
|
||
|
|
||
|
glDrawBuffer (GL_BACK);
|
||
|
glReadBuffer (GL_BACK);
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
fboUpdate (CompScreen *s,
|
||
|
float dt,
|
||
|
float fade)
|
||
|
{
|
||
|
WATER_SCREEN (s);
|
||
|
|
||
|
if (!fboPrologue (s, TINDEX (ws, 1)))
|
||
|
return 0;
|
||
|
|
||
|
if (!ws->texture[TINDEX (ws, 2)])
|
||
|
allocTexture (s, TINDEX (ws, 2));
|
||
|
|
||
|
if (!ws->texture[TINDEX (ws, 0)])
|
||
|
allocTexture (s, TINDEX (ws, 0));
|
||
|
|
||
|
glEnable (ws->target);
|
||
|
|
||
|
(*s->activeTexture) (GL_TEXTURE0_ARB);
|
||
|
glBindTexture (ws->target, ws->texture[TINDEX (ws, 2)]);
|
||
|
|
||
|
glTexParameteri (ws->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||
|
glTexParameteri (ws->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||
|
(*s->activeTexture) (GL_TEXTURE1_ARB);
|
||
|
glBindTexture (ws->target, ws->texture[TINDEX (ws, 0)]);
|
||
|
glTexParameteri (ws->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||
|
glTexParameteri (ws->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||
|
|
||
|
glEnable (GL_FRAGMENT_PROGRAM_ARB);
|
||
|
(*s->bindProgram) (GL_FRAGMENT_PROGRAM_ARB, ws->program);
|
||
|
|
||
|
(*s->programLocalParameter4f) (GL_FRAGMENT_PROGRAM_ARB, 0,
|
||
|
dt * K, fade, 1.0f, 1.0f);
|
||
|
|
||
|
glBegin (GL_QUADS);
|
||
|
|
||
|
glTexCoord2f (0.0f, 0.0f);
|
||
|
glVertex2f (0.0f, 0.0f);
|
||
|
glTexCoord2f (ws->tx, 0.0f);
|
||
|
glVertex2f (1.0f, 0.0f);
|
||
|
glTexCoord2f (ws->tx, ws->ty);
|
||
|
glVertex2f (1.0f, 1.0f);
|
||
|
glTexCoord2f (0.0f, ws->ty);
|
||
|
glVertex2f (0.0f, 1.0f);
|
||
|
|
||
|
glEnd ();
|
||
|
|
||
|
glDisable (GL_FRAGMENT_PROGRAM_ARB);
|
||
|
|
||
|
glTexParameteri (ws->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||
|
glTexParameteri (ws->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||
|
glBindTexture (ws->target, 0);
|
||
|
(*s->activeTexture) (GL_TEXTURE0_ARB);
|
||
|
glTexParameteri (ws->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||
|
glTexParameteri (ws->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||
|
glBindTexture (ws->target, 0);
|
||
|
|
||
|
glDisable (ws->target);
|
||
|
|
||
|
fboEpilogue (s);
|
||
|
|
||
|
/* increment texture index */
|
||
|
ws->tIndex = TINDEX (ws, 1);
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
fboVertices (CompScreen *s,
|
||
|
GLenum type,
|
||
|
XPoint *p,
|
||
|
int n,
|
||
|
float v)
|
||
|
{
|
||
|
WATER_SCREEN (s);
|
||
|
|
||
|
if (!fboPrologue (s, TINDEX (ws, 0)))
|
||
|
return 0;
|
||
|
|
||
|
glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
|
||
|
glColor4f (0.0f, 0.0f, 0.0f, v);
|
||
|
|
||
|
glPointSize (3.0f);
|
||
|
glLineWidth (1.0f);
|
||
|
|
||
|
glScalef (1.0f / ws->width, 1.0f / ws->height, 1.0);
|
||
|
glTranslatef (0.5f, 0.5f, 0.0f);
|
||
|
|
||
|
glBegin (type);
|
||
|
|
||
|
while (n--)
|
||
|
{
|
||
|
glVertex2i (p->x, p->y);
|
||
|
p++;
|
||
|
}
|
||
|
|
||
|
glEnd ();
|
||
|
|
||
|
glColor4usv (defaultColor);
|
||
|
glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||
|
|
||
|
fboEpilogue (s);
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
softwareUpdate (CompScreen *s,
|
||
|
float dt,
|
||
|
float fade)
|
||
|
{
|
||
|
float *dTmp;
|
||
|
int i, j;
|
||
|
float v0, v1, inv;
|
||
|
float accel, value;
|
||
|
unsigned char *t0, *t;
|
||
|
int dWidth, dHeight;
|
||
|
float *d01, *d10, *d11, *d12;
|
||
|
|
||
|
WATER_SCREEN (s);
|
||
|
|
||
|
if (!ws->texture[TINDEX (ws, 0)])
|
||
|
allocTexture (s, TINDEX (ws, 0));
|
||
|
|
||
|
dt *= K * 2.0f;
|
||
|
fade *= 0.99f;
|
||
|
|
||
|
dWidth = ws->width + 2;
|
||
|
dHeight = ws->height + 2;
|
||
|
|
||
|
#define D(d, j) (*((d) + (j)))
|
||
|
|
||
|
d01 = ws->d0 + dWidth;
|
||
|
d10 = ws->d1;
|
||
|
d11 = d10 + dWidth;
|
||
|
d12 = d11 + dWidth;
|
||
|
|
||
|
for (i = 1; i < dHeight - 1; i++)
|
||
|
{
|
||
|
for (j = 1; j < dWidth - 1; j++)
|
||
|
{
|
||
|
accel = dt * (D (d10, j) +
|
||
|
D (d12, j) +
|
||
|
D (d11, j - 1) +
|
||
|
D (d11, j + 1) - 4.0f * D (d11, j));
|
||
|
|
||
|
value = (2.0f * D (d11, j) - D (d01, j) + accel) * fade;
|
||
|
|
||
|
CLAMP (value, 0.0f, 1.0f);
|
||
|
|
||
|
D (d01, j) = value;
|
||
|
}
|
||
|
|
||
|
d01 += dWidth;
|
||
|
d10 += dWidth;
|
||
|
d11 += dWidth;
|
||
|
d12 += dWidth;
|
||
|
}
|
||
|
|
||
|
/* update border */
|
||
|
memcpy (ws->d0, ws->d0 + dWidth, dWidth * sizeof (GLfloat));
|
||
|
memcpy (ws->d0 + dWidth * (dHeight - 1),
|
||
|
ws->d0 + dWidth * (dHeight - 2),
|
||
|
dWidth * sizeof (GLfloat));
|
||
|
|
||
|
d01 = ws->d0 + dWidth;
|
||
|
|
||
|
for (i = 1; i < dHeight - 1; i++)
|
||
|
{
|
||
|
D (d01, 0) = D (d01, 1);
|
||
|
D (d01, dWidth - 1) = D (d01, dWidth - 2);
|
||
|
|
||
|
d01 += dWidth;
|
||
|
}
|
||
|
|
||
|
d10 = ws->d1;
|
||
|
d11 = d10 + dWidth;
|
||
|
d12 = d11 + dWidth;
|
||
|
|
||
|
t0 = ws->t0;
|
||
|
|
||
|
/* update texture */
|
||
|
for (i = 0; i < ws->height; i++)
|
||
|
{
|
||
|
for (j = 0; j < ws->width; j++)
|
||
|
{
|
||
|
v0 = (D (d12, j) - D (d10, j)) * 1.5f;
|
||
|
v1 = (D (d11, j - 1) - D (d11, j + 1)) * 1.5f;
|
||
|
|
||
|
/* 0.5 for scale */
|
||
|
inv = 0.5f / sqrtf (v0 * v0 + v1 * v1 + 1.0f);
|
||
|
|
||
|
/* add scale and bias to normal */
|
||
|
v0 = v0 * inv + 0.5f;
|
||
|
v1 = v1 * inv + 0.5f;
|
||
|
|
||
|
/* store normal map in RGB components */
|
||
|
t = t0 + (j * 4);
|
||
|
t[0] = (unsigned char) ((inv + 0.5f) * 255.0f);
|
||
|
t[1] = (unsigned char) (v1 * 255.0f);
|
||
|
t[2] = (unsigned char) (v0 * 255.0f);
|
||
|
|
||
|
/* store height in A component */
|
||
|
t[3] = (unsigned char) (D (d11, j) * 255.0f);
|
||
|
}
|
||
|
|
||
|
d10 += dWidth;
|
||
|
d11 += dWidth;
|
||
|
d12 += dWidth;
|
||
|
|
||
|
t0 += ws->width * 4;
|
||
|
}
|
||
|
|
||
|
#undef D
|
||
|
|
||
|
/* swap height maps */
|
||
|
dTmp = ws->d0;
|
||
|
ws->d0 = ws->d1;
|
||
|
ws->d1 = dTmp;
|
||
|
|
||
|
if (ws->texture[TINDEX (ws, 0)])
|
||
|
{
|
||
|
glBindTexture (ws->target, ws->texture[TINDEX (ws, 0)]);
|
||
|
glTexImage2D (ws->target,
|
||
|
0,
|
||
|
GL_RGBA,
|
||
|
ws->width,
|
||
|
ws->height,
|
||
|
0,
|
||
|
GL_BGRA,
|
||
|
|
||
|
#if IMAGE_BYTE_ORDER == MSBFirst
|
||
|
GL_UNSIGNED_INT_8_8_8_8_REV,
|
||
|
#else
|
||
|
GL_UNSIGNED_BYTE,
|
||
|
#endif
|
||
|
|
||
|
ws->t0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
#define SET(x, y, v) *((ws->d1) + (ws->width + 2) * (y + 1) + (x + 1)) = (v)
|
||
|
|
||
|
static void
|
||
|
softwarePoints (CompScreen *s,
|
||
|
XPoint *p,
|
||
|
int n,
|
||
|
float add)
|
||
|
{
|
||
|
WATER_SCREEN (s);
|
||
|
|
||
|
while (n--)
|
||
|
{
|
||
|
SET (p->x - 1, p->y - 1, add);
|
||
|
SET (p->x, p->y - 1, add);
|
||
|
SET (p->x + 1, p->y - 1, add);
|
||
|
|
||
|
SET (p->x - 1, p->y, add);
|
||
|
SET (p->x, p->y, add);
|
||
|
SET (p->x + 1, p->y, add);
|
||
|
|
||
|
SET (p->x - 1, p->y + 1, add);
|
||
|
SET (p->x, p->y + 1, add);
|
||
|
SET (p->x + 1, p->y + 1, add);
|
||
|
|
||
|
p++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* bresenham */
|
||
|
static void
|
||
|
softwareLines (CompScreen *s,
|
||
|
XPoint *p,
|
||
|
int n,
|
||
|
float v)
|
||
|
{
|
||
|
int x1, y1, x2, y2;
|
||
|
Bool steep;
|
||
|
int tmp;
|
||
|
int deltaX, deltaY;
|
||
|
int error = 0;
|
||
|
int yStep;
|
||
|
int x, y;
|
||
|
|
||
|
WATER_SCREEN (s);
|
||
|
|
||
|
#define SWAP(v0, v1) \
|
||
|
tmp = v0; \
|
||
|
v0 = v1; \
|
||
|
v1 = tmp
|
||
|
|
||
|
while (n > 1)
|
||
|
{
|
||
|
x1 = p->x;
|
||
|
y1 = p->y;
|
||
|
|
||
|
p++;
|
||
|
n--;
|
||
|
|
||
|
x2 = p->x;
|
||
|
y2 = p->y;
|
||
|
|
||
|
p++;
|
||
|
n--;
|
||
|
|
||
|
steep = abs (y2 - y1) > abs (x2 - x1);
|
||
|
if (steep)
|
||
|
{
|
||
|
SWAP (x1, y1);
|
||
|
SWAP (x2, y2);
|
||
|
}
|
||
|
|
||
|
if (x1 > x2)
|
||
|
{
|
||
|
SWAP (x1, x2);
|
||
|
SWAP (y1, y2);
|
||
|
}
|
||
|
|
||
|
#undef SWAP
|
||
|
|
||
|
deltaX = x2 - x1;
|
||
|
deltaY = abs (y2 - y1);
|
||
|
|
||
|
y = y1;
|
||
|
if (y1 < y2)
|
||
|
yStep = 1;
|
||
|
else
|
||
|
yStep = -1;
|
||
|
|
||
|
for (x = x1; x <= x2; x++)
|
||
|
{
|
||
|
if (steep)
|
||
|
{
|
||
|
SET (y, x, v);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SET (x, y, v);
|
||
|
}
|
||
|
|
||
|
error += deltaY;
|
||
|
if (2 * error >= deltaX)
|
||
|
{
|
||
|
y += yStep;
|
||
|
error -= deltaX;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#undef SET
|
||
|
|
||
|
static void
|
||
|
softwareVertices (CompScreen *s,
|
||
|
GLenum type,
|
||
|
XPoint *p,
|
||
|
int n,
|
||
|
float v)
|
||
|
{
|
||
|
switch (type) {
|
||
|
case GL_POINTS:
|
||
|
softwarePoints (s, p, n, v);
|
||
|
break;
|
||
|
case GL_LINES:
|
||
|
softwareLines (s, p, n, v);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
waterUpdate (CompScreen *s,
|
||
|
float dt)
|
||
|
{
|
||
|
GLfloat fade = 1.0f;
|
||
|
|
||
|
WATER_SCREEN (s);
|
||
|
|
||
|
if (ws->count < 1000)
|
||
|
{
|
||
|
if (ws->count > 1)
|
||
|
fade = 0.90f + ws->count / 10000.0f;
|
||
|
else
|
||
|
fade = 0.0f;
|
||
|
}
|
||
|
|
||
|
if (!fboUpdate (s, dt, fade))
|
||
|
softwareUpdate (s, dt, fade);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
scaleVertices (CompScreen *s,
|
||
|
XPoint *p,
|
||
|
int n)
|
||
|
{
|
||
|
WATER_SCREEN (s);
|
||
|
|
||
|
while (n--)
|
||
|
{
|
||
|
p[n].x = (ws->width * p[n].x) / s->width;
|
||
|
p[n].y = (ws->height * p[n].y) / s->height;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
waterVertices (CompScreen *s,
|
||
|
GLenum type,
|
||
|
XPoint *p,
|
||
|
int n,
|
||
|
float v)
|
||
|
{
|
||
|
WATER_SCREEN (s);
|
||
|
|
||
|
if (!s->fragmentProgram)
|
||
|
return;
|
||
|
|
||
|
scaleVertices (s, p, n);
|
||
|
|
||
|
if (!fboVertices (s, type, p, n, v))
|
||
|
softwareVertices (s, type, p, n, v);
|
||
|
|
||
|
if (ws->count < 3000)
|
||
|
ws->count = 3000;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
waterRainTimeout (void *closure)
|
||
|
{
|
||
|
CompScreen *s = closure;
|
||
|
XPoint p;
|
||
|
|
||
|
p.x = (int) (s->width * (rand () / (float) RAND_MAX));
|
||
|
p.y = (int) (s->height * (rand () / (float) RAND_MAX));
|
||
|
|
||
|
waterVertices (s, GL_POINTS, &p, 1, 0.8f * (rand () / (float) RAND_MAX));
|
||
|
|
||
|
damageScreen (s);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
waterWiperTimeout (void *closure)
|
||
|
{
|
||
|
CompScreen *s = closure;
|
||
|
|
||
|
WATER_SCREEN (s);
|
||
|
|
||
|
if (ws->count)
|
||
|
{
|
||
|
if (ws->wiperAngle == 0.0f)
|
||
|
ws->wiperSpeed = 2.5f;
|
||
|
else if (ws->wiperAngle == 180.0f)
|
||
|
ws->wiperSpeed = -2.5f;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
waterReset (CompScreen *s)
|
||
|
{
|
||
|
int size, i, j;
|
||
|
|
||
|
WATER_SCREEN (s);
|
||
|
|
||
|
ws->height = TEXTURE_SIZE;
|
||
|
ws->width = (ws->height * s->width) / s->height;
|
||
|
|
||
|
if (s->textureNonPowerOfTwo ||
|
||
|
(POWER_OF_TWO (ws->width) && POWER_OF_TWO (ws->height)))
|
||
|
{
|
||
|
ws->target = GL_TEXTURE_2D;
|
||
|
ws->tx = ws->ty = 1.0f;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ws->target = GL_TEXTURE_RECTANGLE_NV;
|
||
|
ws->tx = ws->width;
|
||
|
ws->ty = ws->height;
|
||
|
}
|
||
|
|
||
|
if (!s->fragmentProgram)
|
||
|
return;
|
||
|
|
||
|
if (s->fbo)
|
||
|
{
|
||
|
loadWaterProgram (s);
|
||
|
if (!ws->fbo)
|
||
|
(*s->genFramebuffers) (1, &ws->fbo);
|
||
|
}
|
||
|
|
||
|
ws->fboStatus = 0;
|
||
|
|
||
|
for (i = 0; i < TEXTURE_NUM; i++)
|
||
|
{
|
||
|
if (ws->texture[i])
|
||
|
{
|
||
|
glDeleteTextures (1, &ws->texture[i]);
|
||
|
ws->texture[i] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (ws->data)
|
||
|
free (ws->data);
|
||
|
|
||
|
size = (ws->width + 2) * (ws->height + 2);
|
||
|
|
||
|
ws->data = calloc (1, (sizeof (float) * size * 2) +
|
||
|
(sizeof (GLubyte) * ws->width * ws->height * 4));
|
||
|
if (!ws->data)
|
||
|
return;
|
||
|
|
||
|
ws->d0 = ws->data;
|
||
|
ws->d1 = (ws->d0 + (size));
|
||
|
ws->t0 = (unsigned char *) (ws->d1 + (size));
|
||
|
|
||
|
for (i = 0; i < ws->height; i++)
|
||
|
{
|
||
|
for (j = 0; j < ws->width; j++)
|
||
|
{
|
||
|
(ws->t0 + (ws->width * 4 * i + j * 4))[0] = 0xff;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
waterDrawWindowTexture (CompWindow *w,
|
||
|
CompTexture *texture,
|
||
|
const FragmentAttrib *attrib,
|
||
|
unsigned int mask)
|
||
|
{
|
||
|
WATER_SCREEN (w->screen);
|
||
|
|
||
|
if (ws->count)
|
||
|
{
|
||
|
FragmentAttrib fa = *attrib;
|
||
|
Bool lighting = w->screen->lighting;
|
||
|
int param, function, unit;
|
||
|
GLfloat plane[4];
|
||
|
|
||
|
WATER_DISPLAY (w->screen->display);
|
||
|
|
||
|
param = allocFragmentParameters (&fa, 1);
|
||
|
unit = allocFragmentTextureUnits (&fa, 1);
|
||
|
|
||
|
function = getBumpMapFragmentFunction (w->screen, texture, unit, param);
|
||
|
if (function)
|
||
|
{
|
||
|
addFragmentFunction (&fa, function);
|
||
|
|
||
|
screenLighting (w->screen, TRUE);
|
||
|
|
||
|
(*w->screen->activeTexture) (GL_TEXTURE0_ARB + unit);
|
||
|
|
||
|
glBindTexture (ws->target, ws->texture[TINDEX (ws, 0)]);
|
||
|
|
||
|
plane[1] = plane[2] = 0.0f;
|
||
|
plane[0] = ws->tx / (GLfloat) w->screen->width;
|
||
|
plane[3] = 0.0f;
|
||
|
|
||
|
glTexGeni (GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
|
||
|
glTexGenfv (GL_S, GL_EYE_PLANE, plane);
|
||
|
glEnable (GL_TEXTURE_GEN_S);
|
||
|
|
||
|
plane[0] = plane[2] = 0.0f;
|
||
|
plane[1] = ws->ty / (GLfloat) w->screen->height;
|
||
|
plane[3] = 0.0f;
|
||
|
|
||
|
glTexGeni (GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
|
||
|
glTexGenfv (GL_T, GL_EYE_PLANE, plane);
|
||
|
glEnable (GL_TEXTURE_GEN_T);
|
||
|
|
||
|
(*w->screen->activeTexture) (GL_TEXTURE0_ARB);
|
||
|
|
||
|
(*w->screen->programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB, param,
|
||
|
texture->matrix.yy *
|
||
|
wd->offsetScale,
|
||
|
-texture->matrix.xx *
|
||
|
wd->offsetScale,
|
||
|
0.0f, 0.0f);
|
||
|
}
|
||
|
|
||
|
/* to get appropriate filtering of texture */
|
||
|
mask |= PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK;
|
||
|
|
||
|
UNWRAP (ws, w->screen, drawWindowTexture);
|
||
|
(*w->screen->drawWindowTexture) (w, texture, &fa, mask);
|
||
|
WRAP (ws, w->screen, drawWindowTexture, waterDrawWindowTexture);
|
||
|
|
||
|
if (function)
|
||
|
{
|
||
|
(*w->screen->activeTexture) (GL_TEXTURE0_ARB + unit);
|
||
|
glDisable (GL_TEXTURE_GEN_T);
|
||
|
glDisable (GL_TEXTURE_GEN_S);
|
||
|
glBindTexture (ws->target, 0);
|
||
|
(*w->screen->activeTexture) (GL_TEXTURE0_ARB);
|
||
|
|
||
|
screenLighting (w->screen, lighting);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
UNWRAP (ws, w->screen, drawWindowTexture);
|
||
|
(*w->screen->drawWindowTexture) (w, texture, attrib, mask);
|
||
|
WRAP (ws, w->screen, drawWindowTexture, waterDrawWindowTexture);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* TODO: a way to control the speed */
|
||
|
static void
|
||
|
waterPreparePaintScreen (CompScreen *s,
|
||
|
int msSinceLastPaint)
|
||
|
{
|
||
|
WATER_SCREEN (s);
|
||
|
|
||
|
if (ws->count)
|
||
|
{
|
||
|
ws->count -= 10;
|
||
|
if (ws->count < 0)
|
||
|
ws->count = 0;
|
||
|
|
||
|
if (ws->wiperHandle)
|
||
|
{
|
||
|
float step, angle0, angle1;
|
||
|
Bool wipe = FALSE;
|
||
|
XPoint p[3];
|
||
|
|
||
|
p[1].x = s->width / 2;
|
||
|
p[1].y = s->height;
|
||
|
|
||
|
step = ws->wiperSpeed * msSinceLastPaint / 20.0f;
|
||
|
|
||
|
if (ws->wiperSpeed > 0.0f)
|
||
|
{
|
||
|
if (ws->wiperAngle < 180.0f)
|
||
|
{
|
||
|
angle0 = ws->wiperAngle;
|
||
|
|
||
|
ws->wiperAngle += step;
|
||
|
ws->wiperAngle = MIN (ws->wiperAngle, 180.0f);
|
||
|
|
||
|
angle1 = ws->wiperAngle;
|
||
|
|
||
|
wipe = TRUE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (ws->wiperAngle > 0.0f)
|
||
|
{
|
||
|
angle1 = ws->wiperAngle;
|
||
|
|
||
|
ws->wiperAngle += step;
|
||
|
ws->wiperAngle = MAX (ws->wiperAngle, 0.0f);
|
||
|
|
||
|
angle0 = ws->wiperAngle;
|
||
|
|
||
|
wipe = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#define TAN(a) (tanf ((a) * (M_PI / 180.0f)))
|
||
|
|
||
|
if (wipe)
|
||
|
{
|
||
|
if (angle0 > 0.0f)
|
||
|
{
|
||
|
p[2].x = s->width / 2 - s->height / TAN (angle0);
|
||
|
p[2].y = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
p[2].x = 0;
|
||
|
p[2].y = s->height;
|
||
|
}
|
||
|
|
||
|
if (angle1 < 180.0f)
|
||
|
{
|
||
|
p[0].x = s->width / 2 - s->height / TAN (angle1);
|
||
|
p[0].y = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
p[0].x = s->width;
|
||
|
p[0].y = s->height;
|
||
|
}
|
||
|
|
||
|
/* software rasterizer doesn't support triangles yet so wiper
|
||
|
effect will only work with FBOs right now */
|
||
|
waterVertices (s, GL_TRIANGLES, p, 3, 0.0f);
|
||
|
}
|
||
|
|
||
|
#undef TAN
|
||
|
|
||
|
}
|
||
|
|
||
|
waterUpdate (s, 0.8f);
|
||
|
}
|
||
|
|
||
|
UNWRAP (ws, s, preparePaintScreen);
|
||
|
(*s->preparePaintScreen) (s, msSinceLastPaint);
|
||
|
WRAP (ws, s, preparePaintScreen, waterPreparePaintScreen);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
waterDonePaintScreen (CompScreen *s)
|
||
|
{
|
||
|
WATER_SCREEN (s);
|
||
|
|
||
|
if (ws->count)
|
||
|
damageScreen (s);
|
||
|
|
||
|
UNWRAP (ws, s, donePaintScreen);
|
||
|
(*s->donePaintScreen) (s);
|
||
|
WRAP (ws, s, donePaintScreen, waterDonePaintScreen);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
waterHandleMotionEvent (CompDisplay *d,
|
||
|
Window root)
|
||
|
{
|
||
|
CompScreen *s;
|
||
|
|
||
|
s = findScreenAtDisplay (d, root);
|
||
|
if (s)
|
||
|
{
|
||
|
WATER_SCREEN (s);
|
||
|
|
||
|
if (ws->grabIndex)
|
||
|
{
|
||
|
XPoint p[2];
|
||
|
|
||
|
p[0].x = waterLastPointerX;
|
||
|
p[0].y = waterLastPointerY;
|
||
|
|
||
|
p[1].x = waterLastPointerX = pointerX;
|
||
|
p[1].y = waterLastPointerY = pointerY;
|
||
|
|
||
|
waterVertices (s, GL_LINES, p, 2, 0.2f);
|
||
|
|
||
|
damageScreen (s);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
waterInitiate (CompDisplay *d,
|
||
|
CompAction *action,
|
||
|
CompActionState state,
|
||
|
CompOption *option,
|
||
|
int nOption)
|
||
|
{
|
||
|
CompScreen *s;
|
||
|
unsigned int ui;
|
||
|
Window root, child;
|
||
|
int xRoot, yRoot, i;
|
||
|
|
||
|
for (s = d->screens; s; s = s->next)
|
||
|
{
|
||
|
WATER_SCREEN (s);
|
||
|
|
||
|
if (otherScreenGrabExist (s, "water", NULL))
|
||
|
continue;
|
||
|
|
||
|
if (!ws->grabIndex)
|
||
|
ws->grabIndex = pushScreenGrab (s, None, "water");
|
||
|
|
||
|
if (XQueryPointer (d->display, s->root, &root, &child, &xRoot, &yRoot,
|
||
|
&i, &i, &ui))
|
||
|
{
|
||
|
XPoint p;
|
||
|
|
||
|
p.x = waterLastPointerX = xRoot;
|
||
|
p.y = waterLastPointerY = yRoot;
|
||
|
|
||
|
waterVertices (s, GL_POINTS, &p, 1, 0.8f);
|
||
|
|
||
|
damageScreen (s);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (state & CompActionStateInitButton)
|
||
|
action->state |= CompActionStateTermButton;
|
||
|
|
||
|
if (state & CompActionStateInitKey)
|
||
|
action->state |= CompActionStateTermKey;
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
waterTerminate (CompDisplay *d,
|
||
|
CompAction *action,
|
||
|
CompActionState state,
|
||
|
CompOption *option,
|
||
|
int nOption)
|
||
|
{
|
||
|
CompScreen *s;
|
||
|
|
||
|
for (s = d->screens; s; s = s->next)
|
||
|
{
|
||
|
WATER_SCREEN (s);
|
||
|
|
||
|
if (ws->grabIndex)
|
||
|
{
|
||
|
removeScreenGrab (s, ws->grabIndex, 0);
|
||
|
ws->grabIndex = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
waterToggleRain (CompDisplay *d,
|
||
|
CompAction *action,
|
||
|
CompActionState state,
|
||
|
CompOption *option,
|
||
|
int nOption)
|
||
|
{
|
||
|
CompScreen *s;
|
||
|
|
||
|
WATER_DISPLAY (d);
|
||
|
|
||
|
s = findScreenAtDisplay (d, getIntOptionNamed (option, nOption, "root", 0));
|
||
|
if (s)
|
||
|
{
|
||
|
WATER_SCREEN (s);
|
||
|
|
||
|
if (!ws->rainHandle)
|
||
|
{
|
||
|
int delay;
|
||
|
|
||
|
delay = wd->opt[WATER_DISPLAY_OPTION_RAIN_DELAY].value.i;
|
||
|
ws->rainHandle = compAddTimeout (delay, (float) delay * 1.2,
|
||
|
waterRainTimeout, s);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
compRemoveTimeout (ws->rainHandle);
|
||
|
ws->rainHandle = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
waterToggleWiper (CompDisplay *d,
|
||
|
CompAction *action,
|
||
|
CompActionState state,
|
||
|
CompOption *option,
|
||
|
int nOption)
|
||
|
{
|
||
|
CompScreen *s;
|
||
|
|
||
|
s = findScreenAtDisplay (d, getIntOptionNamed (option, nOption, "root", 0));
|
||
|
if (s)
|
||
|
{
|
||
|
WATER_SCREEN (s);
|
||
|
|
||
|
if (!ws->wiperHandle)
|
||
|
{
|
||
|
ws->wiperHandle = compAddTimeout (2000, 2400, waterWiperTimeout, s);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
compRemoveTimeout (ws->wiperHandle);
|
||
|
ws->wiperHandle = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
waterTitleWave (CompDisplay *d,
|
||
|
CompAction *action,
|
||
|
CompActionState state,
|
||
|
CompOption *option,
|
||
|
int nOption)
|
||
|
{
|
||
|
CompWindow *w;
|
||
|
int xid;
|
||
|
|
||
|
xid = getIntOptionNamed (option, nOption, "window", d->activeWindow);
|
||
|
|
||
|
w = findWindowAtDisplay (d, xid);
|
||
|
if (w)
|
||
|
{
|
||
|
XPoint p[2];
|
||
|
|
||
|
p[0].x = w->attrib.x - w->input.left;
|
||
|
p[0].y = w->attrib.y - w->input.top / 2;
|
||
|
|
||
|
p[1].x = w->attrib.x + w->width + w->input.right;
|
||
|
p[1].y = p[0].y;
|
||
|
|
||
|
waterVertices (w->screen, GL_LINES, p, 2, 0.15f);
|
||
|
|
||
|
damageScreen (w->screen);
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
waterPoint (CompDisplay *d,
|
||
|
CompAction *action,
|
||
|
CompActionState state,
|
||
|
CompOption *option,
|
||
|
int nOption)
|
||
|
{
|
||
|
CompScreen *s;
|
||
|
int xid;
|
||
|
|
||
|
xid = getIntOptionNamed (option, nOption, "root", 0);
|
||
|
|
||
|
s = findScreenAtDisplay (d, xid);
|
||
|
if (s)
|
||
|
{
|
||
|
XPoint p;
|
||
|
float amp;
|
||
|
|
||
|
p.x = getIntOptionNamed (option, nOption, "x", s->width / 2);
|
||
|
p.y = getIntOptionNamed (option, nOption, "y", s->height / 2);
|
||
|
|
||
|
amp = getFloatOptionNamed (option, nOption, "amplitude", 0.5f);
|
||
|
|
||
|
waterVertices (s, GL_POINTS, &p, 1, amp);
|
||
|
|
||
|
damageScreen (s);
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
waterLine (CompDisplay *d,
|
||
|
CompAction *action,
|
||
|
CompActionState state,
|
||
|
CompOption *option,
|
||
|
int nOption)
|
||
|
{
|
||
|
CompScreen *s;
|
||
|
int xid;
|
||
|
|
||
|
xid = getIntOptionNamed (option, nOption, "root", 0);
|
||
|
|
||
|
s = findScreenAtDisplay (d, xid);
|
||
|
if (s)
|
||
|
{
|
||
|
XPoint p[2];
|
||
|
float amp;
|
||
|
|
||
|
p[0].x = getIntOptionNamed (option, nOption, "x0", s->width / 4);
|
||
|
p[0].y = getIntOptionNamed (option, nOption, "y0", s->height / 2);
|
||
|
|
||
|
p[1].x = getIntOptionNamed (option, nOption, "x1",
|
||
|
s->width - s->width / 4);
|
||
|
p[1].y = getIntOptionNamed (option, nOption, "y1", s->height / 2);
|
||
|
|
||
|
|
||
|
amp = getFloatOptionNamed (option, nOption, "amplitude", 0.25f);
|
||
|
|
||
|
waterVertices (s, GL_LINES, p, 2, amp);
|
||
|
|
||
|
damageScreen (s);
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
waterHandleEvent (CompDisplay *d,
|
||
|
XEvent *event)
|
||
|
{
|
||
|
CompScreen *s;
|
||
|
|
||
|
WATER_DISPLAY (d);
|
||
|
|
||
|
switch (event->type) {
|
||
|
case ButtonPress:
|
||
|
s = findScreenAtDisplay (d, event->xbutton.root);
|
||
|
if (s)
|
||
|
{
|
||
|
WATER_SCREEN (s);
|
||
|
|
||
|
if (ws->grabIndex)
|
||
|
{
|
||
|
XPoint p;
|
||
|
|
||
|
p.x = pointerX;
|
||
|
p.y = pointerY;
|
||
|
|
||
|
waterVertices (s, GL_POINTS, &p, 1, 0.8f);
|
||
|
damageScreen (s);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case EnterNotify:
|
||
|
case LeaveNotify:
|
||
|
waterHandleMotionEvent (d, event->xcrossing.root);
|
||
|
break;
|
||
|
case MotionNotify:
|
||
|
waterHandleMotionEvent (d, event->xmotion.root);
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
UNWRAP (wd, d, handleEvent);
|
||
|
(*d->handleEvent) (d, event);
|
||
|
WRAP (wd, d, handleEvent, waterHandleEvent);
|
||
|
}
|
||
|
|
||
|
static CompOption *
|
||
|
waterGetDisplayOptions (CompPlugin *plugin,
|
||
|
CompDisplay *display,
|
||
|
int *count)
|
||
|
{
|
||
|
WATER_DISPLAY (display);
|
||
|
|
||
|
*count = NUM_OPTIONS (wd);
|
||
|
return wd->opt;
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
waterSetDisplayOption (CompPlugin *plugin,
|
||
|
CompDisplay *display,
|
||
|
const char *name,
|
||
|
CompOptionValue *value)
|
||
|
{
|
||
|
CompOption *o;
|
||
|
int index;
|
||
|
|
||
|
WATER_DISPLAY (display);
|
||
|
|
||
|
o = compFindOption (wd->opt, NUM_OPTIONS (wd), name, &index);
|
||
|
if (!o)
|
||
|
return FALSE;
|
||
|
|
||
|
switch (index) {
|
||
|
case WATER_DISPLAY_OPTION_OFFSET_SCALE:
|
||
|
if (compSetFloatOption (o, value))
|
||
|
{
|
||
|
wd->offsetScale = o->value.f * 50.0f;
|
||
|
return TRUE;
|
||
|
}
|
||
|
break;
|
||
|
case WATER_DISPLAY_OPTION_RAIN_DELAY:
|
||
|
if (compSetIntOption (o, value))
|
||
|
{
|
||
|
CompScreen *s;
|
||
|
|
||
|
for (s = display->screens; s; s = s->next)
|
||
|
{
|
||
|
WATER_SCREEN (s);
|
||
|
|
||
|
if (!ws->rainHandle)
|
||
|
continue;
|
||
|
|
||
|
compRemoveTimeout (ws->rainHandle);
|
||
|
ws->rainHandle = compAddTimeout (value->i,
|
||
|
(float)value->i * 1.2,
|
||
|
waterRainTimeout, s);
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
return compSetDisplayOption (display, o, value);
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static const CompMetadataOptionInfo waterDisplayOptionInfo[] = {
|
||
|
{ "initiate_key", "key", 0, waterInitiate, waterTerminate },
|
||
|
{ "toggle_rain_key", "key", 0, waterToggleRain, 0 },
|
||
|
{ "toggle_wiper_key", "key", 0, waterToggleWiper, 0 },
|
||
|
{ "offset_scale", "float", "<min>0</min>", 0, 0 },
|
||
|
{ "rain_delay", "int", "<min>1</min>", 0, 0 },
|
||
|
{ "title_wave", "bell", 0, waterTitleWave, 0 },
|
||
|
{ "point", "action", 0, waterPoint, 0 },
|
||
|
{ "line", "action", 0, waterLine, 0 }
|
||
|
};
|
||
|
|
||
|
static Bool
|
||
|
waterInitDisplay (CompPlugin *p,
|
||
|
CompDisplay *d)
|
||
|
{
|
||
|
WaterDisplay *wd;
|
||
|
|
||
|
if (!checkPluginABI ("core", CORE_ABIVERSION))
|
||
|
return FALSE;
|
||
|
|
||
|
wd = malloc (sizeof (WaterDisplay));
|
||
|
if (!wd)
|
||
|
return FALSE;
|
||
|
|
||
|
if (!compInitDisplayOptionsFromMetadata (d,
|
||
|
&waterMetadata,
|
||
|
waterDisplayOptionInfo,
|
||
|
wd->opt,
|
||
|
WATER_DISPLAY_OPTION_NUM))
|
||
|
{
|
||
|
free (wd);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
wd->screenPrivateIndex = allocateScreenPrivateIndex (d);
|
||
|
if (wd->screenPrivateIndex < 0)
|
||
|
{
|
||
|
compFiniDisplayOptions (d, wd->opt, WATER_DISPLAY_OPTION_NUM);
|
||
|
free (wd);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
wd->offsetScale = wd->opt[WATER_DISPLAY_OPTION_OFFSET_SCALE].value.f * 50.0f;
|
||
|
|
||
|
WRAP (wd, d, handleEvent, waterHandleEvent);
|
||
|
|
||
|
d->base.privates[displayPrivateIndex].ptr = wd;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
waterFiniDisplay (CompPlugin *p,
|
||
|
CompDisplay *d)
|
||
|
{
|
||
|
WATER_DISPLAY (d);
|
||
|
|
||
|
freeScreenPrivateIndex (d, wd->screenPrivateIndex);
|
||
|
|
||
|
UNWRAP (wd, d, handleEvent);
|
||
|
|
||
|
compFiniDisplayOptions (d, wd->opt, WATER_DISPLAY_OPTION_NUM);
|
||
|
|
||
|
free (wd);
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
waterInitScreen (CompPlugin *p,
|
||
|
CompScreen *s)
|
||
|
{
|
||
|
WaterScreen *ws;
|
||
|
|
||
|
WATER_DISPLAY (s->display);
|
||
|
|
||
|
ws = calloc (1, sizeof (WaterScreen));
|
||
|
if (!ws)
|
||
|
return FALSE;
|
||
|
|
||
|
ws->grabIndex = 0;
|
||
|
|
||
|
WRAP (ws, s, preparePaintScreen, waterPreparePaintScreen);
|
||
|
WRAP (ws, s, donePaintScreen, waterDonePaintScreen);
|
||
|
WRAP (ws, s, drawWindowTexture, waterDrawWindowTexture);
|
||
|
|
||
|
s->base.privates[wd->screenPrivateIndex].ptr = ws;
|
||
|
|
||
|
waterReset (s);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
waterFiniScreen (CompPlugin *p,
|
||
|
CompScreen *s)
|
||
|
{
|
||
|
WaterFunction *function, *next;
|
||
|
int i;
|
||
|
|
||
|
WATER_SCREEN (s);
|
||
|
|
||
|
if (ws->rainHandle)
|
||
|
compRemoveTimeout (ws->rainHandle);
|
||
|
|
||
|
if (ws->wiperHandle)
|
||
|
compRemoveTimeout (ws->wiperHandle);
|
||
|
|
||
|
if (ws->fbo)
|
||
|
(*s->deleteFramebuffers) (1, &ws->fbo);
|
||
|
|
||
|
for (i = 0; i < TEXTURE_NUM; i++)
|
||
|
{
|
||
|
if (ws->texture[i])
|
||
|
glDeleteTextures (1, &ws->texture[i]);
|
||
|
}
|
||
|
|
||
|
if (ws->program)
|
||
|
(*s->deletePrograms) (1, &ws->program);
|
||
|
|
||
|
if (ws->data)
|
||
|
free (ws->data);
|
||
|
|
||
|
function = ws->bumpMapFunctions;
|
||
|
while (function)
|
||
|
{
|
||
|
destroyFragmentFunction (s, function->handle);
|
||
|
|
||
|
next = function->next;
|
||
|
free (function);
|
||
|
function = next;
|
||
|
}
|
||
|
|
||
|
UNWRAP (ws, s, preparePaintScreen);
|
||
|
UNWRAP (ws, s, donePaintScreen);
|
||
|
UNWRAP (ws, s, drawWindowTexture);
|
||
|
|
||
|
free (ws);
|
||
|
}
|
||
|
|
||
|
static CompBool
|
||
|
waterInitObject (CompPlugin *p,
|
||
|
CompObject *o)
|
||
|
{
|
||
|
static InitPluginObjectProc dispTab[] = {
|
||
|
(InitPluginObjectProc) 0, /* InitCore */
|
||
|
(InitPluginObjectProc) waterInitDisplay,
|
||
|
(InitPluginObjectProc) waterInitScreen
|
||
|
};
|
||
|
|
||
|
RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
waterFiniObject (CompPlugin *p,
|
||
|
CompObject *o)
|
||
|
{
|
||
|
static FiniPluginObjectProc dispTab[] = {
|
||
|
(FiniPluginObjectProc) 0, /* FiniCore */
|
||
|
(FiniPluginObjectProc) waterFiniDisplay,
|
||
|
(FiniPluginObjectProc) waterFiniScreen
|
||
|
};
|
||
|
|
||
|
DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
|
||
|
}
|
||
|
|
||
|
static CompOption *
|
||
|
waterGetObjectOptions (CompPlugin *plugin,
|
||
|
CompObject *object,
|
||
|
int *count)
|
||
|
{
|
||
|
static GetPluginObjectOptionsProc dispTab[] = {
|
||
|
(GetPluginObjectOptionsProc) 0, /* GetCoreOptions */
|
||
|
(GetPluginObjectOptionsProc) waterGetDisplayOptions
|
||
|
};
|
||
|
|
||
|
*count = 0;
|
||
|
RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab),
|
||
|
(void *) count, (plugin, object, count));
|
||
|
}
|
||
|
|
||
|
static CompBool
|
||
|
waterSetObjectOption (CompPlugin *plugin,
|
||
|
CompObject *object,
|
||
|
const char *name,
|
||
|
CompOptionValue *value)
|
||
|
{
|
||
|
static SetPluginObjectOptionProc dispTab[] = {
|
||
|
(SetPluginObjectOptionProc) 0, /* SetCoreOption */
|
||
|
(SetPluginObjectOptionProc) waterSetDisplayOption
|
||
|
};
|
||
|
|
||
|
RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab), FALSE,
|
||
|
(plugin, object, name, value));
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
waterInit (CompPlugin *p)
|
||
|
{
|
||
|
if (!compInitPluginMetadataFromInfo (&waterMetadata,
|
||
|
p->vTable->name,
|
||
|
waterDisplayOptionInfo,
|
||
|
WATER_DISPLAY_OPTION_NUM,
|
||
|
0, 0))
|
||
|
return FALSE;
|
||
|
|
||
|
displayPrivateIndex = allocateDisplayPrivateIndex ();
|
||
|
if (displayPrivateIndex < 0)
|
||
|
{
|
||
|
compFiniMetadata (&waterMetadata);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
compAddMetadataFromFile (&waterMetadata, p->vTable->name);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
waterFini (CompPlugin *p)
|
||
|
{
|
||
|
freeDisplayPrivateIndex (displayPrivateIndex);
|
||
|
compFiniMetadata (&waterMetadata);
|
||
|
}
|
||
|
|
||
|
static CompMetadata *
|
||
|
waterGetMetadata (CompPlugin *plugin)
|
||
|
{
|
||
|
return &waterMetadata;
|
||
|
}
|
||
|
|
||
|
static CompPluginVTable waterVTable = {
|
||
|
"water",
|
||
|
waterGetMetadata,
|
||
|
waterInit,
|
||
|
waterFini,
|
||
|
waterInitObject,
|
||
|
waterFiniObject,
|
||
|
waterGetObjectOptions,
|
||
|
waterSetObjectOption
|
||
|
};
|
||
|
|
||
|
CompPluginVTable *
|
||
|
getCompPluginInfo20070830 (void)
|
||
|
{
|
||
|
return &waterVTable;
|
||
|
}
|