summaryrefslogtreecommitdiff
path: root/plugins/opengl/src
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/opengl/src')
-rw-r--r--plugins/opengl/src/fragment.cpp1105
-rw-r--r--plugins/opengl/src/matrix.cpp439
-rw-r--r--plugins/opengl/src/opengl.cpp101
-rw-r--r--plugins/opengl/src/paint.cpp1262
-rw-r--r--plugins/opengl/src/privatefragment.h54
-rw-r--r--plugins/opengl/src/privates.h172
-rw-r--r--plugins/opengl/src/privatetexture.h85
-rw-r--r--plugins/opengl/src/screen.cpp1193
-rw-r--r--plugins/opengl/src/texture.cpp615
-rw-r--r--plugins/opengl/src/vector.cpp276
-rw-r--r--plugins/opengl/src/window.cpp363
11 files changed, 5665 insertions, 0 deletions
diff --git a/plugins/opengl/src/fragment.cpp b/plugins/opengl/src/fragment.cpp
new file mode 100644
index 0000000..ad9643e
--- /dev/null
+++ b/plugins/opengl/src/fragment.cpp
@@ -0,0 +1,1105 @@
+/*
+ * Copyright © 2007 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>
+ */
+
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+#include <boost/foreach.hpp>
+#define foreach BOOST_FOREACH
+
+#include <core/core.h>
+#include <opengl/texture.h>
+#include <opengl/fragment.h>
+#include "privatefragment.h"
+#include "privates.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#define COMP_FUNCTION_TYPE_ARB 0
+#define COMP_FUNCTION_TYPE_NUM 1
+
+#define COMP_FUNCTION_ARB_MASK (1 << 0)
+#define COMP_FUNCTION_MASK (COMP_FUNCTION_ARB_MASK)
+
+namespace GLFragment {
+
+ class Program {
+ public:
+ Program () :
+ signature (0),
+ blending (false),
+ name (0),
+ type (GL_FRAGMENT_PROGRAM_ARB)
+ {};
+ ~Program ()
+ {
+ if (name)
+ (*GL::deletePrograms) (1, &name);
+ };
+
+ public:
+ std::vector<FunctionId> signature;
+
+ bool blending;
+
+ GLuint name;
+ GLenum type;
+ };
+
+ typedef enum {
+ OpTypeData,
+ OpTypeDataStore,
+ OpTypeDataOffset,
+ OpTypeDataBlend,
+ OpTypeHeaderTemp,
+ OpTypeHeaderParam,
+ OpTypeHeaderAttrib,
+ OpTypeColor,
+ OpTypeFetch,
+ OpTypeLoad
+ } OpType;
+
+ class HeaderOp {
+ public:
+ HeaderOp () : type (OpTypeHeaderTemp), name ("") {};
+ public:
+ OpType type;
+ CompString name;
+ };
+
+ class BodyOp {
+ public:
+ BodyOp () :
+ type (OpTypeData),
+ data (""),
+ dst (""),
+ src (""),
+ target (0)
+ {
+ foreach (CompString &str, noOffset)
+ str = "";
+ foreach (CompString &str, offset)
+ str = "";
+ };
+
+ public:
+ OpType type;
+ CompString data;
+ CompString dst;
+ CompString src;
+ unsigned int target;
+ CompString noOffset[COMP_FETCH_TARGET_NUM];
+ CompString offset[COMP_FETCH_TARGET_NUM];
+
+ };
+
+ class PrivateFunctionData {
+ public:
+ PrivateFunctionData () : header (0), body (0), status (true) {};
+ PrivateFunctionData (const PrivateFunctionData&, CompString);
+
+ public:
+ std::vector<HeaderOp> header;
+ std::vector<BodyOp> body;
+ bool status;
+ };
+
+ class Function {
+ public:
+ Function ():
+ id (0),
+ name (""),
+ mask (0)
+ {};
+
+ public:
+ FunctionId id;
+ CompString name;
+ PrivateFunctionData data[COMP_FUNCTION_TYPE_NUM];
+ unsigned int mask;
+ };
+
+ class PrivateAttrib {
+ public:
+ PrivateAttrib () :
+ opacity (0xffff),
+ brightness (0xffff),
+ saturation (0xffff),
+ nTexture (0),
+ nFunction (0),
+ nParam (0)
+ {}
+
+ PrivateAttrib (const PrivateAttrib &pa) :
+ opacity (pa.opacity),
+ brightness (pa.brightness),
+ saturation (pa.saturation),
+ nTexture (pa.nTexture),
+ nFunction (pa.nFunction),
+ nParam (pa.nParam)
+ {
+ for (int i = 0; i < MAX_FRAGMENT_FUNCTIONS; i++)
+ function[i] = pa.function[i];
+ }
+
+ public:
+ GLushort opacity;
+ GLushort brightness;
+ GLushort saturation;
+ int nTexture;
+ FunctionId function[MAX_FRAGMENT_FUNCTIONS];
+ int nFunction;
+ int nParam;
+ };
+
+ typedef boost::function<void (BodyOp *, int)> DataOpCallBack;
+
+ class InitialLoadFunction : public Function {
+ public:
+ InitialLoadFunction ()
+ {
+ id = 0;
+ name = "__core_load";
+ mask = COMP_FUNCTION_MASK;
+
+ BodyOp b;
+ b.type = OpTypeLoad;
+ b.noOffset[0] = "TEX output, fragment.texcoord[0], texture[0], 2D;";
+ b.noOffset[1] = "TEX output, fragment.texcoord[0], texture[0], RECT;";
+ b.offset[0] = "TEX output, __tmp_texcoord0, texture[0], 2D;";
+ b.offset[1] = "TEX output, __tmp_texcoord0, texture[0], RECT;";
+ data[0].body.push_back (b);
+ };
+ };
+
+ static InitialLoadFunction initialLoadFunction;
+
+ static Function *
+ findFragmentFunction (GLScreen *s,
+ FunctionId id)
+ {
+ foreach (Function *f, s->fragmentStorage ()->functions)
+ if (f->id == id)
+ return f;
+ return NULL;
+ }
+
+ static Function *
+ findFragmentFunctionWithName (GLScreen *s,
+ CompString name)
+ {
+ foreach (Function *f, s->fragmentStorage ()->functions)
+ if (f->name.compare (name) == 0)
+ return f;
+ return NULL;
+ }
+
+ static Program *
+ findFragmentProgram (GLScreen *s,
+ FunctionId *signature,
+ unsigned int nSignature)
+ {
+ unsigned int i;
+
+ foreach (Program *p, s->fragmentStorage ()->programs)
+ {
+ if (p->signature.size () != nSignature)
+ continue;
+
+ for (i = 0; i < nSignature; i++)
+ if (signature[i] != p->signature[i])
+ break;
+
+ if (i == nSignature)
+ return p;
+ }
+ return NULL;
+ }
+
+ static unsigned int
+ functionMaskToType (int mask)
+ {
+ static struct {
+ unsigned int type;
+ unsigned int mask;
+ } maskToType[] = {
+ { COMP_FUNCTION_TYPE_ARB, COMP_FUNCTION_ARB_MASK }
+ };
+
+ unsigned int i;
+
+ for (i = 0; i < sizeof (maskToType) / sizeof (maskToType[0]); i++)
+ if (mask & maskToType[i].mask)
+ return maskToType[i].type;
+
+ return 0;
+ }
+
+ static void
+ forEachDataOpInFunction (std::vector<Function *> list,
+ int index,
+ int type,
+ int loadTarget,
+ CompString loadOffset,
+ bool *color,
+ bool *blend,
+ DataOpCallBack callBack)
+ {
+ Function *f = list[index];
+ BodyOp dataOp;
+ bool colorDone = false;
+ bool blendDone = false;
+
+ *color = false;
+ *blend = false;
+
+ foreach (BodyOp &bodyOp, f->data[type].body)
+ {
+ switch (bodyOp.type) {
+ case OpTypeFetch: {
+ CompString offset = loadOffset;
+
+ /* add offset */
+ if (bodyOp.data.size ())
+ {
+ if (loadOffset.size ())
+ {
+ dataOp.type = OpTypeDataOffset;
+ dataOp.data =
+ compPrintf ("ADD __tmp_texcoord%d, %s, %s;",
+ index, loadOffset.c_str (),
+ bodyOp.data.c_str ());
+
+ callBack (&dataOp, index);
+
+ offset = compPrintf ("__tmp_texcoord%d", index);
+ }
+ else
+ {
+ offset = bodyOp.data;
+ }
+ }
+
+ forEachDataOpInFunction (list, index - 1, type,
+ bodyOp.target,
+ offset, &colorDone, &blendDone,
+ callBack);
+
+ if (bodyOp.dst.compare ("output"))
+ {
+ dataOp.type = OpTypeDataStore;
+ dataOp.data =
+ compPrintf ("MOV %s, output;", bodyOp.dst.c_str ());
+
+ /* move to destination */
+ callBack (&dataOp, index);
+ }
+ } break;
+ case OpTypeLoad:
+ if (loadOffset.size ())
+ {
+ dataOp.type = OpTypeDataOffset;
+ dataOp.data =
+ compPrintf ("ADD __tmp_texcoord0, fragment.texcoord[0], %s;",
+ loadOffset.c_str ());
+
+ callBack (&dataOp, index);
+
+ dataOp.data = bodyOp.offset[loadTarget];
+ }
+ else
+ {
+ dataOp.data = bodyOp.noOffset[loadTarget];
+ }
+
+ dataOp.type = OpTypeData;
+
+ callBack (&dataOp, index);
+
+ break;
+ case OpTypeColor:
+ if (!colorDone)
+ {
+ dataOp.type = OpTypeData;
+ dataOp.data =
+ compPrintf ("MUL %s, fragment.color, %s;",
+ bodyOp.dst.c_str (),
+ bodyOp.src.c_str ());
+
+ callBack (&dataOp, index);
+ }
+ else if (bodyOp.dst.compare (bodyOp.src))
+ {
+ dataOp.type = OpTypeData;
+ dataOp.data =
+ compPrintf ("MOV %s, %s;",
+ bodyOp.dst.c_str (),
+ bodyOp.src.c_str ());
+
+ callBack (&dataOp, index);
+ }
+ *color = true;
+ break;
+ case OpTypeDataBlend:
+ *blend = true;
+ /* fall-through */
+ case OpTypeData:
+ callBack (&bodyOp, index);
+ break;
+ case OpTypeDataStore:
+ case OpTypeDataOffset:
+ case OpTypeHeaderTemp:
+ case OpTypeHeaderParam:
+ case OpTypeHeaderAttrib:
+ break;
+ }
+ }
+
+ if (colorDone)
+ *color = true;
+
+ if (blendDone)
+ *blend = true;
+ }
+
+ static int
+ forEachHeaderOpWithType (std::vector<HeaderOp> list,
+ int index,
+ OpType type,
+ CompString prefix,
+ CompString functionPrefix,
+ int count,
+ DataOpCallBack callBack)
+ {
+ BodyOp dataOp;
+
+ dataOp.type = OpTypeData;
+
+ foreach (HeaderOp &header, list)
+ {
+ if (header.type == type)
+ {
+ if (count)
+ {
+ dataOp.data = ", ";
+ }
+ else
+ {
+ dataOp.data = prefix;
+ }
+
+ dataOp.data += functionPrefix;
+ dataOp.data += "_";
+ dataOp.data += header.name;
+ callBack (&dataOp, index);
+
+ count++;
+ }
+ }
+
+ return count;
+ }
+
+ static bool
+ forEachDataOp (std::vector<Function *> list,
+ int type,
+ DataOpCallBack callBack)
+ {
+ BodyOp dataOp;
+ bool colorDone;
+ bool blendDone;
+ int count, nList = list.size ();
+
+ dataOp.type = OpTypeData;
+
+ count = 1;
+
+ dataOp.data = "TEMP output";
+
+ callBack (&dataOp, nList);
+
+ foreach (Function *f, list)
+ count = forEachHeaderOpWithType (f->data[type].header,
+ nList, OpTypeHeaderTemp,
+ "", f->name, count, callBack);
+
+ dataOp.data = ";";
+
+ callBack (&dataOp, nList);
+
+ count = 0;
+
+ foreach (Function *f, list)
+ count = forEachHeaderOpWithType (f->data[type].header,
+ nList, OpTypeHeaderParam,
+ "PARAM ", f->name, count,
+ callBack);
+
+ if (count)
+ {
+ dataOp.data = ";";
+
+ callBack (&dataOp, nList);
+ }
+
+ count = 0;
+
+ foreach (Function *f, list)
+ count = forEachHeaderOpWithType (f->data[type].header,
+ nList, OpTypeHeaderAttrib,
+ "ATTRIB ", f->name, count,
+ callBack);
+
+ if (count)
+ {
+ dataOp.data = ";";
+
+ callBack (&dataOp, nList);
+ }
+
+ forEachDataOpInFunction (list, nList - 1, type, 0, "",
+ &colorDone, &blendDone,
+ callBack);
+
+ if (colorDone)
+ dataOp.data = "MOV result.color, output;END";
+ else
+ dataOp.data = "MUL result.color, fragment.color, output;END";
+
+ callBack (&dataOp, nList);
+
+ return blendDone;
+ }
+
+ static void
+ addFetchOffsetVariables (BodyOp *op,
+ int index,
+ bool *indices,
+ CompString *data)
+ {
+ if (op->type == OpTypeDataOffset)
+ {
+ if (!indices[index])
+ {
+ data->append (compPrintf ("TEMP __tmp_texcoord%d;", index));
+ indices[index] = true;
+ }
+ }
+ }
+
+ static void
+ addData (BodyOp *op,
+ CompString *data)
+ {
+ data->append (op->data);
+ }
+
+ static Program *
+ buildFragmentProgram (GLScreen *s,
+ PrivateAttrib *attrib)
+ {
+ Program *program;
+ std::vector<Function *> functionList (1);
+ int mask = COMP_FUNCTION_MASK;
+ int type;
+ GLint errorPos;
+ CompString fetchData;
+ bool indices[MAX_FRAGMENT_FUNCTIONS];
+ int i;
+
+ program = new Program ();
+ if (!program)
+ return NULL;
+
+ functionList[0] = &initialLoadFunction;
+
+ for (i = 0; i < attrib->nFunction; i++)
+ {
+ Function *f = findFragmentFunction (s, attrib->function[i]);
+
+ if (f)
+ functionList.push_back (f);
+ }
+
+ foreach (Function *f, functionList)
+ mask &= f->mask;
+
+ if (!mask)
+ {
+ compLogMessage ("opengl", CompLogLevelWarn,
+ "fragment functions can't be linked together "
+ "because a common type doesn't exist");
+ }
+
+ if (!mask || functionList.size () == 1)
+ {
+ delete program;
+ return NULL;
+ }
+
+ for (i = 0; i < attrib->nFunction; i++)
+ program->signature.push_back (attrib->function[i]);
+
+ type = functionMaskToType (mask);
+
+ fetchData = "!!ARBfp1.0";
+
+ foreach (bool &val, indices)
+ val = false;
+
+ forEachDataOp (functionList, type,
+ boost::bind (addFetchOffsetVariables, _1, _2, indices, &fetchData));
+
+ program->blending = forEachDataOp (functionList, type,
+ boost::bind (addData, _1, &fetchData));
+
+ program->type = GL_FRAGMENT_PROGRAM_ARB;
+
+ glGetError ();
+
+ (*GL::genPrograms) (1, &program->name);
+ (*GL::bindProgram) (GL_FRAGMENT_PROGRAM_ARB, program->name);
+ (*GL::programString) (GL_FRAGMENT_PROGRAM_ARB,
+ GL_PROGRAM_FORMAT_ASCII_ARB,
+ fetchData.size (), fetchData.c_str ());
+
+ glGetIntegerv (GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
+ if (glGetError () != GL_NO_ERROR || errorPos != -1)
+ {
+ compLogMessage ("opengl", CompLogLevelError,
+ "failed to load fragment program");
+
+ (*GL::deletePrograms) (1, &program->name);
+
+ program->name = 0;
+ program->type = 0;
+ }
+
+ return program;
+ }
+
+ static GLuint
+ getFragmentProgram (GLScreen *s,
+ PrivateAttrib *attrib,
+ GLenum *type,
+ bool *blending)
+ {
+ Program *program;
+
+ if (!attrib->nFunction)
+ return 0;
+
+ program = findFragmentProgram (s, attrib->function, attrib->nFunction);
+ if (!program)
+ {
+ program = buildFragmentProgram (s, attrib);
+ if (program)
+ {
+ s->fragmentStorage ()->programs.push_back (program);
+ }
+ }
+
+ if (program)
+ {
+ *type = program->type;
+ *blending = program->blending;
+
+ return program->name;
+ }
+
+ return 0;
+ }
+
+
+ /* performs simple variable substitution */
+ static CompString
+ copyData (std::vector<HeaderOp> header,
+ const CompString prefix,
+ CompString data)
+ {
+ CompString inPrefix (prefix);
+ inPrefix += "_";
+
+ foreach (HeaderOp &h, header)
+ {
+ size_t pos = data.find (h.name);
+ while (pos != std::string::npos)
+ {
+ data.insert (pos,inPrefix);
+ pos += inPrefix.size () + h.name.size ();
+ pos = data.find (h.name, pos);
+ }
+ }
+
+ return data;
+ }
+
+ PrivateFunctionData::PrivateFunctionData (const PrivateFunctionData& src,
+ CompString dstPrefix) :
+ header (src.header),
+ body (0),
+ status (src.status)
+ {
+
+ foreach (BodyOp b, src.body)
+ {
+ BodyOp dst;
+ dst.type = b.type;
+
+ switch (b.type) {
+ case OpTypeFetch:
+ dst.dst = copyData (header, dstPrefix, b.dst);
+ if (b.data.size ())
+ dst.data = copyData (header, dstPrefix, b.data);
+ else
+ dst.data = "";
+
+ dst.target = b.target;
+ break;
+ case OpTypeLoad:
+ case OpTypeHeaderTemp:
+ case OpTypeHeaderParam:
+ case OpTypeHeaderAttrib:
+ break;
+ case OpTypeData:
+ case OpTypeDataBlend:
+ case OpTypeDataStore:
+ case OpTypeDataOffset:
+ dst.data = copyData (header, dstPrefix, b.data);
+ break;
+ case OpTypeColor:
+ dst.dst = copyData (header, dstPrefix, b.dst);
+ dst.src = copyData (header, dstPrefix, b.src);
+ break;
+ }
+ body.push_back (dst);
+ }
+ }
+
+ static bool
+ addHeaderOpToFunctionData (PrivateFunctionData *data,
+ const char *name,
+ OpType type)
+ {
+ static const char *reserved[] = {
+ "output",
+ "__tmp_texcoord",
+ "fragment",
+ "program",
+ "result",
+ "state",
+ "texture"
+ };
+ HeaderOp header;
+ CompString n (name);
+
+ foreach (const char *word, reserved)
+ {
+ if (n.find (word) != std::string::npos)
+ {
+ compLogMessage ("opengl", CompLogLevelWarn,
+ "%s is a reserved word", word);
+ return false;
+ }
+ }
+
+
+ header.type = type;
+ header.name = n;
+ data->header.push_back (header);
+
+ return true;
+ }
+
+ FunctionData::FunctionData () :
+ priv (new PrivateFunctionData ())
+ {
+ }
+
+ FunctionData::~FunctionData ()
+ {
+ delete priv;
+ }
+
+ bool
+ FunctionData::status ()
+ {
+ return priv->status;
+ }
+
+ void
+ FunctionData::addTempHeaderOp (const char *name)
+ {
+ priv->status &=
+ addHeaderOpToFunctionData (priv, name, OpTypeHeaderTemp);
+ }
+
+ void
+ FunctionData::addParamHeaderOp (const char *name)
+ {
+ priv->status &=
+ addHeaderOpToFunctionData (priv, name, OpTypeHeaderParam);
+ }
+
+ void
+ FunctionData::addAttribHeaderOp (const char *name)
+ {
+ priv->status &=
+ addHeaderOpToFunctionData (priv, name, OpTypeHeaderAttrib);
+ }
+
+
+ void
+ FunctionData::addFetchOp (const char *dst, const char *offset, int target)
+ {
+ BodyOp b;
+
+ b.type = OpTypeFetch;
+ b.dst = CompString (dst);
+ b.target = target;
+
+ if (offset)
+ b.data = CompString (offset);
+ else
+ b.data = CompString ("");
+
+ priv->body.push_back (b);
+ }
+
+ void
+ FunctionData::addColorOp (const char *dst, const char *src)
+ {
+ BodyOp b;
+
+ b.type = OpTypeColor;
+ b.dst = CompString (dst);
+ b.src = CompString (src);
+
+ priv->body.push_back (b);
+ }
+
+ void
+ FunctionData::addDataOp (const char *str, ...)
+ {
+ BodyOp b;
+ va_list ap;
+
+ b.type = OpTypeData;
+ va_start (ap, str);
+ b.data = compPrintf (str, ap);
+ va_end (ap);
+
+ priv->body.push_back (b);
+ }
+
+ void
+ FunctionData::addBlendOp (const char *str, ...)
+ {
+ BodyOp b;
+ va_list ap;
+
+ b.type = OpTypeDataBlend;
+ va_start (ap, str);
+ b.data = compPrintf (str, ap);
+ va_end (ap);
+
+ priv->body.push_back (b);
+ }
+
+ FunctionId
+ FunctionData::createFragmentFunction (const char *name)
+ {
+ GLScreen *s = GLScreen::get (screen);
+ Function *function = new Function ();
+ CompString validName = name;
+ unsigned int i = 0;
+
+ while (findFragmentFunctionWithName (s, validName))
+ {
+ validName = compPrintf ("%s%d", name, i++);
+ }
+
+ function->data[COMP_FUNCTION_TYPE_ARB] =
+ PrivateFunctionData (*priv, validName);
+
+ function->name = validName;
+ function->mask = COMP_FUNCTION_ARB_MASK;
+ function->id = s->fragmentStorage ()->lastFunctionId++;
+
+ s->fragmentStorage ()->functions.push_back (function);
+
+ return function->id;
+ }
+
+ Attrib::Attrib (const GLWindowPaintAttrib &paint) :
+ priv (new PrivateAttrib ())
+ {
+ priv->opacity = paint.opacity;
+ priv->brightness = paint.brightness;
+ priv->saturation = paint.saturation;
+ priv->nTexture = 0;
+ priv->nFunction = 0;
+ priv->nParam = 0;
+
+ foreach (FunctionId &f, priv->function)
+ f = 0;
+ }
+
+ Attrib::Attrib (const Attrib &fa) :
+ priv (new PrivateAttrib (*fa.priv))
+ {
+ }
+
+ Attrib::~Attrib ()
+ {
+ delete priv;
+ }
+
+ Attrib &
+ Attrib::operator= (const Attrib &rhs)
+ {
+ if (this == &rhs) // Check for self-assignment
+ return *this;
+
+ delete priv;
+ priv = new PrivateAttrib (*rhs.priv);
+
+ return *this;
+ }
+
+ unsigned int
+ Attrib::allocTextureUnits (unsigned int nTexture)
+ {
+ unsigned int first = priv->nTexture;
+
+ priv->nTexture += nTexture;
+
+ /* 0 is reserved for source texture */
+ return 1 + first;
+ }
+
+ unsigned int
+ Attrib::allocParameters (unsigned int nParam)
+ {
+ unsigned int first = priv->nParam;
+
+ priv->nParam += nParam;
+
+ return first;
+ }
+
+ void
+ Attrib::addFunction (FunctionId function)
+ {
+ if (priv->nFunction < MAX_FRAGMENT_FUNCTIONS)
+ priv->function[priv->nFunction++] = function;
+ }
+
+ bool
+ Attrib::enable (bool *blending)
+ {
+ GLuint name;
+ GLenum type;
+ bool programBlending;
+
+ if (!GL::fragmentProgram)
+ return false;
+
+ name = getFragmentProgram (GLScreen::get (screen), priv, &type,
+ &programBlending);
+ if (!name)
+ return false;
+
+ *blending = !programBlending;
+
+ glEnable (GL_FRAGMENT_PROGRAM_ARB);
+
+ (*GL::bindProgram) (type, name);
+
+ return true;
+ }
+
+ void
+ Attrib::disable ()
+ {
+ glDisable (GL_FRAGMENT_PROGRAM_ARB);
+ }
+
+ unsigned short
+ Attrib::getSaturation ()
+ {
+ return priv->saturation;
+ }
+
+ unsigned short
+ Attrib::getBrightness ()
+ {
+ return priv->brightness;
+ }
+
+ unsigned short
+ Attrib::getOpacity ()
+ {
+ return priv->opacity;
+ }
+
+ void
+ Attrib::setSaturation (unsigned short value)
+ {
+ priv->saturation = value;
+ }
+
+ void
+ Attrib::setBrightness (unsigned short value)
+ {
+ priv->brightness = value;
+ }
+
+
+ void
+ Attrib::setOpacity (unsigned short value)
+ {
+ priv->opacity = value;
+ }
+
+ bool
+ Attrib::hasFunctions ()
+ {
+ return priv->nFunction > 0;
+ }
+
+ void destroyFragmentFunction (FunctionId id)
+ {
+ GLScreen *s = GLScreen::get (screen);
+ Function *function;
+ Program *program;
+
+ function = findFragmentFunction (s, id);
+
+ if (!function)
+ return;
+
+ std::vector<Program *>::iterator it;
+
+ do {
+ program = NULL;
+
+ it = s->fragmentStorage ()->programs.begin ();
+
+ for (; it != s->fragmentStorage ()->programs.end (); it++)
+ {
+ foreach (FunctionId i, (*it)->signature)
+ if (i == id)
+ {
+ program = (*it);
+ break;
+ }
+
+ if (program)
+ break;
+ }
+
+ if (program)
+ {
+ delete program;
+ s->fragmentStorage ()->programs.erase (it);
+ }
+
+ } while (program);
+
+ std::vector<Function *>::iterator fi =
+ std::find (s->fragmentStorage ()->functions.begin (),
+ s->fragmentStorage ()->functions.end (),
+ function);
+ if (fi != s->fragmentStorage ()->functions.end ())
+ s->fragmentStorage ()->functions.erase (fi);
+
+ delete (function);
+ }
+
+ FunctionId
+ getSaturateFragmentFunction (GLTexture *texture,
+ int param)
+ {
+ int target;
+ GLScreen *s = GLScreen::get (screen);
+
+ if (param >= 64)
+ return 0;
+
+ if (texture->target () == GL_TEXTURE_2D)
+ target = COMP_FETCH_TARGET_2D;
+ else
+ target = COMP_FETCH_TARGET_RECT;
+
+ if (!s->fragmentStorage ()->saturateFunction [target][param])
+ {
+ static const char *saturateData =
+ "MUL temp, output, { 1.0, 1.0, 1.0, 0.0 };"
+ "DP3 temp, temp, program.env[%d];"
+ "LRP output.xyz, program.env[%d].w, output, temp;";
+ FunctionData data;
+
+ data.addTempHeaderOp ("temp");
+ data.addFetchOp ("output", NULL, target);
+ data.addColorOp ("output", "output");
+
+ data.addDataOp (saturateData, param, param);
+
+ if (!data.status ())
+ return 0;
+
+ s->fragmentStorage ()->saturateFunction [target][param] =
+ data.createFragmentFunction ("__core_saturate");
+
+ }
+
+ return s->fragmentStorage ()->saturateFunction [target][param];
+ }
+
+ Storage::Storage () :
+ lastFunctionId (1),
+ functions (0),
+ programs (0)
+ {
+ for (int i = 0; i < 64; i++)
+ {
+ saturateFunction[0][i] = 0;
+ saturateFunction[1][i] = 0;
+ }
+ }
+
+ Storage::~Storage ()
+ {
+ foreach (Program *p, programs)
+ delete p;
+ programs.clear ();
+ foreach (Function *f, functions)
+ delete f;
+ functions.clear ();
+ }
+
+};
diff --git a/plugins/opengl/src/matrix.cpp b/plugins/opengl/src/matrix.cpp
new file mode 100644
index 0000000..738fa50
--- /dev/null
+++ b/plugins/opengl/src/matrix.cpp
@@ -0,0 +1,439 @@
+/*
+ * Copyright © 2008 Danny Baumann
+ *
+ * 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
+ * Dennis Kasprzyk not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Dennis Kasprzyk makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * DENNIS KASPRZYK DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL DENNIS KASPRZYK 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.
+ *
+ * Authors: Danny Baumann <maniac@compiz-fusion.org>
+ */
+
+/*
+ * Copyright (C) 1999-2005 Brian Paul All Rights Reserved.
+ *
+ * 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 or substantial portions of the Software.
+ *
+ * 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
+ * BRIAN PAUL 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.
+ *
+ * From Mesa 3-D graphics library.
+ */
+
+#include <compiz.h>
+#include <string.h>
+#include <math.h>
+#include <core/core.h>
+#include <opengl/matrix.h>
+
+/**
+ * Identity matrix.
+ */
+static const float identity[16] = {
+ 1.0, 0.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0, 0.0,
+ 0.0, 0.0, 1.0, 0.0,
+ 0.0, 0.0, 0.0, 1.0
+};
+
+#define A(row, col) a[(col << 2) + row]
+#define B(row, col) b[(col << 2) + row]
+#define P(row, col) product[(col << 2) + row]
+
+/**
+ * Perform a full 4x4 matrix multiplication.
+ *
+ * \param a matrix.
+ * \param b matrix.
+ * \param product will receive the product of \p a and \p b.
+ *
+ * \warning Is assumed that \p product != \p b. \p product == \p a is allowed.
+ *
+ * \note KW: 4*16 = 64 multiplications
+ *
+ * \author This \c matmul was contributed by Thomas Malik
+ */
+static void
+matmul4 (float *product,
+ const float *a,
+ const float *b)
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ const float ai0 = A(i,0), ai1 = A(i,1), ai2 = A(i,2), ai3 = A(i,3);
+
+ P(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0) + ai3 * B(3,0);
+ P(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1) + ai3 * B(3,1);
+ P(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2) + ai3 * B(3,2);
+ P(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3 * B(3,3);
+ }
+}
+
+GLMatrix::GLMatrix ()
+{
+ memcpy (m, identity, sizeof (m));
+}
+
+GLMatrix::GLMatrix (const float *mat)
+{
+ memcpy (m, mat, sizeof (m));
+}
+
+void
+GLMatrix::reset ()
+{
+ memcpy (m, identity, sizeof (m));
+}
+
+const float *
+GLMatrix::getMatrix () const
+{
+ return m;
+}
+
+GLMatrix&
+GLMatrix::operator*= (const GLMatrix& rhs)
+{
+ *this = *this * rhs;
+
+ return *this;
+}
+
+GLMatrix
+operator* (const GLMatrix& lhs,
+ const GLMatrix& rhs)
+{
+ GLMatrix result;
+
+ matmul4 (result.m, lhs.m, rhs.m);
+
+ return result;
+}
+
+GLVector
+operator* (const GLMatrix& lhs,
+ const GLVector& rhs)
+{
+ GLVector result;
+ const float *a = lhs.m;
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ result[i] = A(i,0) * rhs[0] + A(i,1) * rhs[1] +
+ A(i,2) * rhs[2] + A(i,3) * rhs[3];
+ }
+
+ return result;
+}
+
+#undef A
+#undef B
+#undef P
+
+/**
+ * Generate a 4x4 transformation matrix from glRotate parameters, and
+ * post-multiply the input matrix by it.
+ *
+ * \author
+ * This function was contributed by Erich Boleyn (erich@uruk.org).
+ * Optimizations contributed by Rudolf Opalla (rudi@khm.de).
+ */
+void
+GLMatrix::rotate (const float angle,
+ const float xRot,
+ const float yRot,
+ const float zRot)
+{
+ float x = xRot, y = yRot, z = zRot;
+ float xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c, s, c;
+ float matrix[16];
+ bool optimized;
+
+ s = (float) sin (angle * DEG2RAD);
+ c = (float) cos (angle * DEG2RAD);
+
+ memcpy (matrix, identity, sizeof (matrix));
+ optimized = false;
+
+#define M(row, col) matrix[col * 4 + row]
+
+ if (x == 0.0f)
+ {
+ if (y == 0.0f)
+ {
+ if (z != 0.0f)
+ {
+ optimized = true;
+ /* rotate only around z-axis */
+ M(0,0) = c;
+ M(1,1) = c;
+ if (z < 0.0f)
+ {
+ M(0,1) = s;
+ M(1,0) = -s;
+ }
+ else
+ {
+ M(0,1) = -s;
+ M(1,0) = s;
+ }
+ }
+ }
+ else if (z == 0.0f)
+ {
+ optimized = true;
+ /* rotate only around y-axis */
+ M(0,0) = c;
+ M(2,2) = c;
+ if (y < 0.0f)
+ {
+ M(0,2) = -s;
+ M(2,0) = s;
+ }
+ else
+ {
+ M(0,2) = s;
+ M(2,0) = -s;
+ }
+ }
+ }
+ else if (y == 0.0f)
+ {
+ if (z == 0.0f)
+ {
+ optimized = true;
+ /* rotate only around x-axis */
+ M(1,1) = c;
+ M(2,2) = c;
+ if (x < 0.0f)
+ {
+ M(1,2) = s;
+ M(2,1) = -s;
+ }
+ else
+ {
+ M(1,2) = -s;
+ M(2,1) = s;
+ }
+ }
+ }
+
+ if (!optimized)
+ {
+ const float mag = sqrtf (x * x + y * y + z * z);
+
+ if (mag <= 1.0e-4)
+ {
+ /* no rotation, leave mat as-is */
+ return;
+ }
+
+ x /= mag;
+ y /= mag;
+ z /= mag;
+
+
+ /*
+ * Arbitrary axis rotation matrix.
+ *
+ * This is composed of 5 matrices, Rz, Ry, T, Ry', Rz', multiplied
+ * like so: Rz * Ry * T * Ry' * Rz'. T is the final rotation
+ * (which is about the X-axis), and the two composite transforms
+ * Ry' * Rz' and Rz * Ry are (respectively) the rotations necessary
+ * from the arbitrary axis to the X-axis then back. They are
+ * all elementary rotations.
+ *
+ * Rz' is a rotation about the Z-axis, to bring the axis vector
+ * into the x-z plane. Then Ry' is applied, rotating about the
+ * Y-axis to bring the axis vector parallel with the X-axis. The
+ * rotation about the X-axis is then performed. Ry and Rz are
+ * simply the respective inverse transforms to bring the arbitrary
+ * axis back to it's original orientation. The first transforms
+ * Rz' and Ry' are considered inverses, since the data from the
+ * arbitrary axis gives you info on how to get to it, not how
+ * to get away from it, and an inverse must be applied.
+ *
+ * The basic calculation used is to recognize that the arbitrary
+ * axis vector (x, y, z), since it is of unit length, actually
+ * represents the sines and cosines of the angles to rotate the
+ * X-axis to the same orientation, with theta being the angle about
+ * Z and phi the angle about Y (in the order described above)
+ * as follows:
+ *
+ * cos ( theta ) = x / sqrt ( 1 - z^2 )
+ * sin ( theta ) = y / sqrt ( 1 - z^2 )
+ *
+ * cos ( phi ) = sqrt ( 1 - z^2 )
+ * sin ( phi ) = z
+ *
+ * Note that cos ( phi ) can further be inserted to the above
+ * formulas:
+ *
+ * cos ( theta ) = x / cos ( phi )
+ * sin ( theta ) = y / sin ( phi )
+ *
+ * ...etc. Because of those relations and the standard trigonometric
+ * relations, it is pssible to reduce the transforms down to what
+ * is used below. It may be that any primary axis chosen will give the
+ * same results (modulo a sign convention) using thie method.
+ *
+ * Particularly nice is to notice that all divisions that might
+ * have caused trouble when parallel to certain planes or
+ * axis go away with care paid to reducing the expressions.
+ * After checking, it does perform correctly under all cases, since
+ * in all the cases of division where the denominator would have
+ * been zero, the numerator would have been zero as well, giving
+ * the expected result.
+ */
+
+ xx = x * x;
+ yy = y * y;
+ zz = z * z;
+ xy = x * y;
+ yz = y * z;
+ zx = z * x;
+ xs = x * s;
+ ys = y * s;
+ zs = z * s;
+ one_c = 1.0f - c;
+
+ /* We already hold the identity-matrix so we can skip some statements */
+ M(0,0) = (one_c * xx) + c;
+ M(0,1) = (one_c * xy) - zs;
+ M(0,2) = (one_c * zx) + ys;
+/* M(0,3) = 0.0F; */
+
+ M(1,0) = (one_c * xy) + zs;
+ M(1,1) = (one_c * yy) + c;
+ M(1,2) = (one_c * yz) - xs;
+/* M(1,3) = 0.0F; */
+
+ M(2,0) = (one_c * zx) - ys;
+ M(2,1) = (one_c * yz) + xs;
+ M(2,2) = (one_c * zz) + c;
+/* M(2,3) = 0.0F; */
+
+/*
+ M(3,0) = 0.0F;
+ M(3,1) = 0.0F;
+ M(3,2) = 0.0F;
+ M(3,3) = 1.0F;
+*/
+ }
+#undef M
+
+ matmul4 (m, m, matrix);
+}
+
+void
+GLMatrix::rotate (const float angle,
+ const GLVector& vector)
+{
+ rotate (angle,
+ vector[GLVector::x],
+ vector[GLVector::y],
+ vector[GLVector::z]);
+}
+
+/**
+ * Multiply a matrix with a general scaling matrix.
+ *
+ * \param matrix matrix.
+ * \param x x axis scale factor.
+ * \param y y axis scale factor.
+ * \param z z axis scale factor.
+ *
+ * Multiplies in-place the elements of \p matrix by the scale factors.
+ */
+void
+GLMatrix::scale (const float x,
+ const float y,
+ const float z)
+{
+ m[0] *= x; m[4] *= y; m[8] *= z;
+ m[1] *= x; m[5] *= y; m[9] *= z;
+ m[2] *= x; m[6] *= y; m[10] *= z;
+ m[3] *= x; m[7] *= y; m[11] *= z;
+}
+
+void
+GLMatrix::scale (const GLVector& vector)
+{
+ scale (vector[GLVector::x],
+ vector[GLVector::y],
+ vector[GLVector::z]);
+}
+
+/**
+ * Multiply a matrix with a translation matrix.
+ *
+ * \param matrix matrix.
+ * \param x translation vector x coordinate.
+ * \param y translation vector y coordinate.
+ * \param z translation vector z coordinate.
+ *
+ * Adds the translation coordinates to the elements of \p matrix in-place.
+ */
+void
+GLMatrix::translate (const float x,
+ const float y,
+ const float z)
+{
+ m[12] = m[0] * x + m[4] * y + m[8] * z + m[12];
+ m[13] = m[1] * x + m[5] * y + m[9] * z + m[13];
+ m[14] = m[2] * x + m[6] * y + m[10] * z + m[14];
+ m[15] = m[3] * x + m[7] * y + m[11] * z + m[15];
+}
+
+void
+GLMatrix::translate (const GLVector& vector)
+{
+ translate (vector[GLVector::x],
+ vector[GLVector::y],
+ vector[GLVector::z]);
+}
+
+void
+GLMatrix::toScreenSpace (const CompOutput *output,
+ float z)
+{
+ translate (-0.5f, -0.5f, z);
+ scale (1.0f / output->width (), -1.0f / output->height (), 1.0f);
+ translate (-output->x1 (), -output->y2 (), 0.0f);
+}
+
+float&
+GLMatrix::operator[] (unsigned int pos)
+{
+ assert (pos <= 15);
+ return m[pos];
+}
diff --git a/plugins/opengl/src/opengl.cpp b/plugins/opengl/src/opengl.cpp
new file mode 100644
index 0000000..58c3d4c
--- /dev/null
+++ b/plugins/opengl/src/opengl.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright © 2008 Dennis Kasprzyk
+ * Copyright © 2007 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
+ * Dennis Kasprzyk not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Dennis Kasprzyk makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * DENNIS KASPRZYK DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL DENNIS KASPRZYK 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.
+ *
+ * Authors: Dennis Kasprzyk <onestone@compiz-fusion.org>
+ * David Reveman <davidr@novell.com>
+ */
+
+#include <core/core.h>
+#include <core/pluginclasshandler.h>
+#include "privates.h"
+
+CompOption::Vector &
+GLScreen::getOptions ()
+{
+ return priv->getOptions ();
+}
+
+bool
+GLScreen::setOption (const CompString &name,
+ CompOption::Value &value)
+{
+ return priv->setOption (name, value);
+}
+
+bool
+PrivateGLScreen::setOption (const CompString &name,
+ CompOption::Value &value)
+{
+ unsigned int index;
+
+ bool rv = OpenglOptions::setOption (name, value);
+
+ if (!rv || !CompOption::findOption (getOptions (), name, &index))
+ return false;
+
+ switch (index) {
+ case OpenglOptions::TextureFilter:
+ cScreen->damageScreen ();
+
+ if (!optionGetTextureFilter ())
+ textureFilter = GL_NEAREST;
+ else
+ textureFilter = GL_LINEAR;
+ break;
+ default:
+ break;
+ }
+
+ return rv;
+}
+
+class OpenglPluginVTable :
+ public CompPlugin::VTableForScreenAndWindow<GLScreen, GLWindow>
+{
+ public:
+
+ bool init ();
+ void fini ();
+};
+
+COMPIZ_PLUGIN_20090315 (opengl, OpenglPluginVTable)
+
+bool
+OpenglPluginVTable::init ()
+{
+ if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION) ||
+ !CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI))
+ return false;
+
+ CompPrivate p;
+ p.uval = COMPIZ_OPENGL_ABI;
+ screen->storeValue ("opengl_ABI", p);
+
+ return true;
+}
+
+void
+OpenglPluginVTable::fini ()
+{
+ screen->eraseValue ("opengl_ABI");
+}
diff --git a/plugins/opengl/src/paint.cpp b/plugins/opengl/src/paint.cpp
new file mode 100644
index 0000000..e11b737
--- /dev/null
+++ b/plugins/opengl/src/paint.cpp
@@ -0,0 +1,1262 @@
+/*
+ * Copyright © 2005 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>
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include <boost/foreach.hpp>
+#define foreach BOOST_FOREACH
+
+#include <core/core.h>
+#include <opengl/opengl.h>
+
+#include "privates.h"
+
+
+GLScreenPaintAttrib defaultScreenPaintAttrib = {
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -DEFAULT_Z_CAMERA
+};
+
+GLWindowPaintAttrib GLWindow::defaultPaintAttrib = {
+ OPAQUE, BRIGHT, COLOR, 1.0f, 1.0f, 0.0f, 0.0f
+};
+
+void
+GLScreen::glApplyTransform (const GLScreenPaintAttrib &sAttrib,
+ CompOutput *output,
+ GLMatrix *transform)
+{
+ WRAPABLE_HND_FUNC (2, glApplyTransform, sAttrib, output, transform)
+
+ transform->translate (sAttrib.xTranslate,
+ sAttrib.yTranslate,
+ sAttrib.zTranslate + sAttrib.zCamera);
+ transform->rotate (sAttrib.xRotate, 0.0f, 1.0f, 0.0f);
+ transform->rotate (sAttrib.vRotate,
+ cosf (sAttrib.xRotate * DEG2RAD),
+ 0.0f,
+ sinf (sAttrib.xRotate * DEG2RAD));
+ transform->rotate (sAttrib.yRotate, 0.0f, 1.0f, 0.0f);
+}
+
+void
+PrivateGLScreen::paintBackground (const CompRegion &region,
+ bool transformed)
+{
+ BoxPtr pBox = const_cast <Region> (region.handle ())->rects;
+ int n, nBox = const_cast <Region> (region.handle ())->numRects;
+ GLfloat *d, *data;
+
+ if (!nBox)
+ return;
+
+ if (screen->desktopWindowCount ())
+ {
+ if (!backgroundTextures.empty ())
+ {
+ backgroundTextures.clear ();
+ }
+
+ backgroundLoaded = false;
+
+ return;
+ }
+ else
+ {
+ if (!backgroundLoaded)
+ updateScreenBackground ();
+
+ backgroundLoaded = true;
+ }
+
+ data = new GLfloat [nBox * 16];
+ if (!data)
+ return;
+
+ d = data;
+ n = nBox;
+
+ if (backgroundTextures.empty ())
+ {
+ while (n--)
+ {
+ *d++ = pBox->x1;
+ *d++ = pBox->y2;
+
+ *d++ = pBox->x2;
+ *d++ = pBox->y2;
+
+ *d++ = pBox->x2;
+ *d++ = pBox->y1;
+
+ *d++ = pBox->x1;
+ *d++ = pBox->y1;
+
+ pBox++;
+ }
+
+ glVertexPointer (2, GL_FLOAT, sizeof (GLfloat) * 2, data + 2);
+
+ glColor4us (0, 0, 0, 0);
+ glDrawArrays (GL_QUADS, 0, nBox * 4);
+ glColor4usv (defaultColor);
+ }
+ else
+ {
+ for (unsigned int i = 0; i < backgroundTextures.size (); i++)
+ {
+ GLTexture *bg = backgroundTextures[i];
+ CompRegion r = region & *bg;
+
+ pBox = const_cast <Region> (r.handle ())->rects;
+ nBox = const_cast <Region> (r.handle ())->numRects;
+ d = data;
+ n = nBox;
+
+ while (n--)
+ {
+ *d++ = COMP_TEX_COORD_X (bg->matrix (), pBox->x1);
+ *d++ = COMP_TEX_COORD_Y (bg->matrix (), pBox->y2);
+
+ *d++ = pBox->x1;
+ *d++ = pBox->y2;
+
+ *d++ = COMP_TEX_COORD_X (bg->matrix (), pBox->x2);
+ *d++ = COMP_TEX_COORD_Y (bg->matrix (), pBox->y2);
+
+ *d++ = pBox->x2;
+ *d++ = pBox->y2;
+
+ *d++ = COMP_TEX_COORD_X (bg->matrix (), pBox->x2);
+ *d++ = COMP_TEX_COORD_Y (bg->matrix (), pBox->y1);
+
+ *d++ = pBox->x2;
+ *d++ = pBox->y1;
+
+ *d++ = COMP_TEX_COORD_X (bg->matrix (), pBox->x1);
+ *d++ = COMP_TEX_COORD_Y (bg->matrix (), pBox->y1);
+
+ *d++ = pBox->x1;
+ *d++ = pBox->y1;
+
+ pBox++;
+ }
+
+ glTexCoordPointer (2, GL_FLOAT, sizeof (GLfloat) * 4, data);
+ glVertexPointer (2, GL_FLOAT, sizeof (GLfloat) * 4, data + 2);
+
+ if (bg->name ())
+ {
+ if (transformed)
+ bg->enable (GLTexture::Good);
+ else
+ bg->enable (GLTexture::Fast);
+
+ glDrawArrays (GL_QUADS, 0, nBox * 4);
+
+ bg->disable ();
+ }
+ }
+ }
+
+ delete [] data;
+}
+
+
+/* This function currently always performs occlusion detection to
+ minimize paint regions. OpenGL precision requirements are no good
+ enough to guarantee that the results from using occlusion detection
+ is the same as without. It's likely not possible to see any
+ difference with most hardware but occlusion detection in the
+ transformed screen case should be made optional for those who do
+ see a difference. */
+void
+PrivateGLScreen::paintOutputRegion (const GLMatrix &transform,
+ const CompRegion &region,
+ CompOutput *output,
+ unsigned int mask)
+{
+ CompRegion tmpRegion (region);
+ CompWindow *w;
+ GLWindow *gw;
+ int count, windowMask, odMask;
+ CompWindow *fullscreenWindow = NULL;
+ bool status, unredirectFS;
+ bool withOffset = false;
+ GLMatrix vTransform;
+ CompPoint offXY;
+
+ CompWindowList pl;
+ CompWindowList::reverse_iterator rit;
+
+ unredirectFS = CompositeScreen::get (screen)->
+ getOption ("unredirect_fullscreen_windows")->value ().b ();
+
+ if (mask & PAINT_SCREEN_TRANSFORMED_MASK)
+ {
+ windowMask = PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK;
+ count = 1;
+ }
+ else
+ {
+ windowMask = 0;
+ count = 0;
+ }
+
+ pl = cScreen->getWindowPaintList ();
+
+ if (!(mask & PAINT_SCREEN_NO_OCCLUSION_DETECTION_MASK))
+ {
+ /* detect occlusions */
+ for (rit = pl.rbegin (); rit != pl.rend (); rit++)
+ {
+ w = (*rit);
+ gw = GLWindow::get (w);
+
+ if (w->destroyed ())
+ continue;
+
+ if (!w->shaded ())
+ {
+ if (!w->isViewable () ||
+ !CompositeWindow::get (w)->damaged ())
+ continue;
+ }
+
+ /* copy region */
+ gw->priv->clip = tmpRegion;
+
+ odMask = PAINT_WINDOW_OCCLUSION_DETECTION_MASK;
+
+ if ((cScreen->windowPaintOffset ().x () != 0 ||
+ cScreen->windowPaintOffset ().y () != 0) &&
+ !w->onAllViewports ())
+ {
+ withOffset = true;
+
+ offXY = w->getMovementForOffset (cScreen->windowPaintOffset ());
+
+ vTransform = transform;
+ vTransform.translate (offXY.x (), offXY.y (), 0);
+
+ gw->priv->clip.translate (-offXY.x (), -offXY. y ());
+
+ odMask |= PAINT_WINDOW_WITH_OFFSET_MASK;
+ status = gw->glPaint (gw->paintAttrib (), vTransform,
+ tmpRegion, odMask);
+ }
+ else
+ {
+ withOffset = false;
+ status = gw->glPaint (gw->paintAttrib (), transform, tmpRegion,
+ odMask);
+ }
+
+ if (status)
+ {
+ if (withOffset)
+ {
+ tmpRegion -= w->region ().translated (offXY);
+ }
+ else
+ tmpRegion -= w->region ();
+
+ /* unredirect top most fullscreen windows. */
+ if (count == 0 && unredirectFS)
+ {
+ if (w->region () == screen->region () &&
+ tmpRegion.isEmpty ())
+ {
+ fullscreenWindow = w;
+ }
+ else
+ {
+ foreach (CompOutput &o, screen->outputDevs ())
+ if (w->region () == CompRegion (o))
+ fullscreenWindow = w;
+ }
+ }
+ }
+
+ count++;
+ }
+ }
+
+ if (fullscreenWindow)
+ CompositeWindow::get (fullscreenWindow)->unredirect ();
+
+ if (!(mask & PAINT_SCREEN_NO_BACKGROUND_MASK))
+ paintBackground (tmpRegion, (mask & PAINT_SCREEN_TRANSFORMED_MASK));
+
+ /* paint all windows from bottom to top */
+ foreach (w, pl)
+ {
+ if (w->destroyed ())
+ continue;
+
+ if (w == fullscreenWindow)
+ continue;
+
+ if (!w->shaded ())
+ {
+ if (!w->isViewable () ||
+ !CompositeWindow::get (w)->damaged ())
+ continue;
+ }
+
+ gw = GLWindow::get (w);
+
+ const CompRegion &clip =
+ (!(mask & PAINT_SCREEN_NO_OCCLUSION_DETECTION_MASK)) ?
+ gw->clip () : region;
+
+ if ((cScreen->windowPaintOffset ().x () != 0 ||
+ cScreen->windowPaintOffset ().y () != 0) &&
+ !w->onAllViewports ())
+ {
+ offXY = w->getMovementForOffset (cScreen->windowPaintOffset ());
+
+ vTransform = transform;
+ vTransform.translate (offXY.x (), offXY.y (), 0);
+ gw->glPaint (gw->paintAttrib (), vTransform, clip,
+ windowMask | PAINT_WINDOW_WITH_OFFSET_MASK);
+ }
+ else
+ {
+ gw->glPaint (gw->paintAttrib (), transform, clip, windowMask);
+ }
+ }
+}
+
+void
+GLScreen::glEnableOutputClipping (const GLMatrix &transform,
+ const CompRegion &region,
+ CompOutput *output)
+{
+ WRAPABLE_HND_FUNC (3, glEnableOutputClipping, transform, region, output)
+
+ GLdouble h = screen->height ();
+
+ GLdouble p1[2] = { region.handle ()->extents.x1,
+ h - region.handle ()->extents.y2 };
+ GLdouble p2[2] = { region.handle ()->extents.x2,
+ h - region.handle ()->extents.y1 };
+
+ GLdouble halfW = output->width () / 2.0;
+ GLdouble halfH = output->height () / 2.0;
+
+ GLdouble cx = output->x1 () + halfW;
+ GLdouble cy = (h - output->y2 ()) + halfH;
+
+ GLdouble top[4] = { 0.0, halfH / (cy - p1[1]), 0.0, 0.5 };
+ GLdouble bottom[4] = { 0.0, halfH / (cy - p2[1]), 0.0, 0.5 };
+ GLdouble left[4] = { halfW / (cx - p1[0]), 0.0, 0.0, 0.5 };
+ GLdouble right[4] = { halfW / (cx - p2[0]), 0.0, 0.0, 0.5 };
+
+ glPushMatrix ();
+ glLoadMatrixf (transform.getMatrix ());
+
+ glClipPlane (GL_CLIP_PLANE0, top);
+ glClipPlane (GL_CLIP_PLANE1, bottom);
+ glClipPlane (GL_CLIP_PLANE2, left);
+ glClipPlane (GL_CLIP_PLANE3, right);
+
+ glEnable (GL_CLIP_PLANE0);
+ glEnable (GL_CLIP_PLANE1);
+ glEnable (GL_CLIP_PLANE2);
+ glEnable (GL_CLIP_PLANE3);
+
+ glPopMatrix ();
+}
+
+void
+GLScreen::glDisableOutputClipping ()
+{
+ WRAPABLE_HND_FUNC (4, glDisableOutputClipping)
+
+ glDisable (GL_CLIP_PLANE0);
+ glDisable (GL_CLIP_PLANE1);
+ glDisable (GL_CLIP_PLANE2);
+ glDisable (GL_CLIP_PLANE3);
+}
+
+#define CLIP_PLANE_MASK (PAINT_SCREEN_TRANSFORMED_MASK | \
+ PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK)
+
+void
+GLScreen::glPaintTransformedOutput (const GLScreenPaintAttrib &sAttrib,
+ const GLMatrix &transform,
+ const CompRegion &region,
+ CompOutput *output,
+ unsigned int mask)
+{
+ WRAPABLE_HND_FUNC (1, glPaintTransformedOutput, sAttrib, transform,
+ region, output, mask)
+
+ GLMatrix sTransform = transform;
+
+ if (mask & PAINT_SCREEN_CLEAR_MASK)
+ clearTargetOutput (GL_COLOR_BUFFER_BIT);
+
+ setLighting (true);
+
+ glApplyTransform (sAttrib, output, &sTransform);
+
+ if ((mask & CLIP_PLANE_MASK) == CLIP_PLANE_MASK)
+ {
+ glEnableOutputClipping (sTransform, region, output);
+
+ sTransform.toScreenSpace (output, -sAttrib.zTranslate);
+
+ glPushMatrix ();
+ glLoadMatrixf (sTransform.getMatrix ());
+
+ priv->paintOutputRegion (sTransform, region, output, mask);
+
+ glPopMatrix ();
+
+ glDisableOutputClipping ();
+ }
+ else
+ {
+ sTransform.toScreenSpace (output, -sAttrib.zTranslate);
+
+ glPushMatrix ();
+ glLoadMatrixf (sTransform.getMatrix ());
+
+ priv->paintOutputRegion (sTransform, region, output, mask);
+
+ glPopMatrix ();
+ }
+}
+
+bool
+GLScreen::glPaintOutput (const GLScreenPaintAttrib &sAttrib,
+ const GLMatrix &transform,
+ const CompRegion &region,
+ CompOutput *output,
+ unsigned int mask)
+{
+ WRAPABLE_HND_FUNC_RETURN (0, bool, glPaintOutput, sAttrib, transform,
+ region, output, mask)
+
+ GLMatrix sTransform = transform;
+
+ if (mask & PAINT_SCREEN_REGION_MASK)
+ {
+ if (mask & PAINT_SCREEN_TRANSFORMED_MASK)
+ {
+ if (mask & PAINT_SCREEN_FULL_MASK)
+ {
+ glPaintTransformedOutput (sAttrib, sTransform,
+ CompRegion (*output), output, mask);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /* fall through and redraw region */
+ }
+ else if (mask & PAINT_SCREEN_FULL_MASK)
+ {
+ glPaintTransformedOutput (sAttrib, sTransform, CompRegion (*output),
+ output, mask);
+
+ return true;
+ }
+ else
+ return false;
+
+ setLighting (false);
+
+ sTransform.toScreenSpace (output, -DEFAULT_Z_CAMERA);
+
+ glPushMatrix ();
+ glLoadMatrixf (sTransform.getMatrix ());
+
+ priv->paintOutputRegion (sTransform, region, output, mask);
+
+ glPopMatrix ();
+
+ return true;
+}
+
+#define ADD_RECT(data, m, n, x1, y1, x2, y2) \
+ for (it = 0; it < n; it++) \
+ { \
+ const GLTexture::Matrix &mat = m[it]; \
+ *(data)++ = COMP_TEX_COORD_X (mat, x1); \
+ *(data)++ = COMP_TEX_COORD_Y (mat, y1); \
+ } \
+ *(data)++ = (x1); \
+ *(data)++ = (y1); \
+ *(data)++ = 0.0; \
+ for (it = 0; it < n; it++) \
+ { \
+ const GLTexture::Matrix &mat = m[it]; \
+ *(data)++ = COMP_TEX_COORD_X (mat, x1); \
+ *(data)++ = COMP_TEX_COORD_Y (mat, y2); \
+ } \
+ *(data)++ = (x1); \
+ *(data)++ = (y2); \
+ *(data)++ = 0.0; \
+ for (it = 0; it < n; it++) \
+ { \
+ const GLTexture::Matrix &mat = m[it]; \
+ *(data)++ = COMP_TEX_COORD_X (mat, x2); \
+ *(data)++ = COMP_TEX_COORD_Y (mat, y2); \
+ } \
+ *(data)++ = (x2); \
+ *(data)++ = (y2); \
+ *(data)++ = 0.0; \
+ for (it = 0; it < n; it++) \
+ { \
+ const GLTexture::Matrix &mat = m[it]; \
+ *(data)++ = COMP_TEX_COORD_X (mat, x2); \
+ *(data)++ = COMP_TEX_COORD_Y (mat, y1); \
+ } \
+ *(data)++ = (x2); \
+ *(data)++ = (y1); \
+ *(data)++ = 0.0
+
+#define ADD_QUAD(data, m, n, x1, y1, x2, y2) \
+ for (it = 0; it < n; it++) \
+ { \
+ const GLTexture::Matrix &mat = m[it]; \
+ *(data)++ = COMP_TEX_COORD_XY (mat, x1, y1); \
+ *(data)++ = COMP_TEX_COORD_YX (mat, x1, y1); \
+ } \
+ *(data)++ = (x1); \
+ *(data)++ = (y1); \
+ *(data)++ = 0.0; \
+ for (it = 0; it < n; it++) \
+ { \
+ const GLTexture::Matrix &mat = m[it]; \
+ *(data)++ = COMP_TEX_COORD_XY (mat, x1, y2); \
+ *(data)++ = COMP_TEX_COORD_YX (mat, x1, y2); \
+ } \
+ *(data)++ = (x1); \
+ *(data)++ = (y2); \
+ *(data)++ = 0.0; \
+ for (it = 0; it < n; it++) \
+ { \
+ const GLTexture::Matrix &mat = m[it]; \
+ *(data)++ = COMP_TEX_COORD_XY (mat, x2, y2); \
+ *(data)++ = COMP_TEX_COORD_YX (mat, x2, y2); \
+ } \
+ *(data)++ = (x2); \
+ *(data)++ = (y2); \
+ *(data)++ = 0.0; \
+ for (it = 0; it < n; it++) \
+ { \
+ const GLTexture::Matrix &mat = m[it]; \
+ *(data)++ = COMP_TEX_COORD_XY (mat, x2, y1); \
+ *(data)++ = COMP_TEX_COORD_YX (mat, x2, y1); \
+ } \
+ *(data)++ = (x2); \
+ *(data)++ = (y1); \
+ *(data)++ = 0.0;
+
+void
+GLWindow::glDrawGeometry ()
+{
+ WRAPABLE_HND_FUNC (4, glDrawGeometry)
+
+ int texUnit = priv->geometry.texUnits;
+ int currentTexUnit = 0;
+ int stride = priv->geometry.vertexStride;
+ GLfloat *vertices = priv->geometry.vertices + (stride - 3);
+
+ stride *= sizeof (GLfloat);
+
+ glVertexPointer (3, GL_FLOAT, stride, vertices);
+
+ while (texUnit--)
+ {
+ if (texUnit != currentTexUnit)
+ {
+ (*GL::clientActiveTexture) (GL_TEXTURE0_ARB + texUnit);
+ glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+ currentTexUnit = texUnit;
+ }
+ vertices -= priv->geometry.texCoordSize;
+ glTexCoordPointer (priv->geometry.texCoordSize,
+ GL_FLOAT, stride, vertices);
+ }
+
+ glDrawArrays (GL_QUADS, 0, priv->geometry.vCount);
+
+ /* disable all texture coordinate arrays except 0 */
+ texUnit = priv->geometry.texUnits;
+ if (texUnit > 1)
+ {
+ while (--texUnit)
+ {
+ (*GL::clientActiveTexture) (GL_TEXTURE0_ARB + texUnit);
+ glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+ }
+
+ (*GL::clientActiveTexture) (GL_TEXTURE0_ARB);
+ }
+}
+
+static inline void
+addSingleQuad (GLfloat *&d,
+ const GLTexture::MatrixList &matrix,
+ unsigned int nMatrix,
+ int x1,
+ int y1,
+ int x2,
+ int y2,
+ int &n,
+ bool rect)
+{
+ unsigned int it;
+
+ if (rect)
+ {
+ ADD_RECT (d, matrix, nMatrix, x1, y1, x2, y2);
+ }
+ else
+ {
+ ADD_QUAD (d, matrix, nMatrix, x1, y1, x2, y2);
+ }
+ n++;
+}
+
+static inline void
+addQuads (GLfloat *&d,
+ const GLTexture::MatrixList &matrix,
+ unsigned int nMatrix,
+ int x1,
+ int y1,
+ int x2,
+ int y2,
+ int &n,
+ int vSize,
+ bool rect,
+ GLWindow::Geometry &geometry,
+ unsigned int maxGridWidth,
+ unsigned int maxGridHeight)
+{
+ int nQuadsX = (maxGridWidth == MAXSHORT) ? 1 :
+ 1 + (x2 - x1 - 1) / (int) maxGridWidth; // ceil. division
+ int nQuadsY = (maxGridHeight == MAXSHORT) ? 1 :
+ 1 + (y2 - y1 - 1) / (int) maxGridHeight;
+ int newVertexSize = (n + nQuadsX * nQuadsY) * vSize * 4;
+
+ // Make sure enough vertices are allocated for nQuadsX * nQuadsY more quads
+ if (newVertexSize > geometry.vertexSize)
+ {
+ if (!geometry.moreVertices (newVertexSize))
+ return;
+
+ d = geometry.vertices + (n * vSize * 4);
+ }
+
+ if (nQuadsX == 1 && nQuadsY == 1)
+ {
+ addSingleQuad (d, matrix, nMatrix, x1, y1, x2, y2, n, rect);
+ }
+ else
+ {
+ int quadWidth = 1 + (x2 - x1 - 1) / nQuadsX; // ceil. division
+ int quadHeight = 1 + (y2 - y1 - 1) / nQuadsY;
+ int nx1, ny1, nx2, ny2;
+
+ for (ny1 = y1; ny1 < y2; ny1 = ny2)
+ {
+ ny2 = MIN (ny1 + (int) quadHeight, y2);
+
+ for (nx1 = x1; nx1 < x2; nx1 = nx2)
+ {
+ nx2 = MIN (nx1 + (int) quadWidth, x2);
+
+ addSingleQuad (d, matrix, nMatrix, nx1, ny1, nx2, ny2, n, rect);
+ }
+ }
+ }
+}
+
+void
+GLWindow::glAddGeometry (const GLTexture::MatrixList &matrix,
+ const CompRegion &region,
+ const CompRegion &clip,
+ unsigned int maxGridWidth,
+ unsigned int maxGridHeight)
+{
+ WRAPABLE_HND_FUNC (2, glAddGeometry, matrix, region, clip)
+
+ BoxRec full;
+ int nMatrix = matrix.size ();
+
+ priv->geometry.texUnits = nMatrix;
+
+ full = clip.handle ()->extents;
+ if (region.handle ()->extents.x1 > full.x1)
+ full.x1 = region.handle ()->extents.x1;
+ if (region.handle ()->extents.y1 > full.y1)
+ full.y1 = region.handle ()->extents.y1;
+ if (region.handle ()->extents.x2 < full.x2)
+ full.x2 = region.handle ()->extents.x2;
+ if (region.handle ()->extents.y2 < full.y2)
+ full.y2 = region.handle ()->extents.y2;
+
+ if (full.x1 < full.x2 && full.y1 < full.y2)
+ {
+ BoxPtr pBox;
+ int nBox;
+ BoxPtr pClip;
+ int nClip;
+ BoxRec cbox;
+ int vSize;
+ int n, it, x1, y1, x2, y2;
+ GLfloat *d;
+ bool rect = true;
+
+ for (it = 0; it < nMatrix; it++)
+ {
+ if (matrix[it].xy != 0.0f || matrix[it].yx != 0.0f)
+ {
+ rect = false;
+ break;
+ }
+ }
+
+ pBox = const_cast <Region> (region.handle ())->rects;
+ nBox = const_cast <Region> (region.handle ())->numRects;
+
+ vSize = 3 + nMatrix * 2;
+
+ n = priv->geometry.vCount / 4;
+
+ if ((n + nBox) * vSize * 4 > priv->geometry.vertexSize)
+ {
+ if (!priv->geometry.moreVertices ((n + nBox) * vSize * 4))
+ return;
+ }
+
+ d = priv->geometry.vertices + (priv->geometry.vCount * vSize);
+
+ while (nBox--)
+ {
+ x1 = pBox->x1;
+ y1 = pBox->y1;
+ x2 = pBox->x2;
+ y2 = pBox->y2;
+
+ pBox++;
+
+ if (x1 < full.x1)
+ x1 = full.x1;
+ if (y1 < full.y1)
+ y1 = full.y1;
+ if (x2 > full.x2)
+ x2 = full.x2;
+ if (y2 > full.y2)
+ y2 = full.y2;
+
+ if (x1 < x2 && y1 < y2)
+ {
+ nClip = const_cast <Region> (clip.handle ())->numRects;
+
+ if (nClip == 1)
+ {
+ addQuads (d, matrix, nMatrix,
+ x1, y1, x2, y2,
+ n, vSize, rect, priv->geometry,
+ maxGridWidth, maxGridHeight);
+ }
+ else
+ {
+ pClip = const_cast <Region> (clip.handle ())->rects;
+
+ if (((n + nClip) * vSize * 4) > priv->geometry.vertexSize)
+ {
+ if (!priv->geometry.moreVertices ((n + nClip) *
+ vSize * 4))
+ return;
+
+ d = priv->geometry.vertices + (n * vSize * 4);
+ }
+
+ while (nClip--)
+ {
+ cbox = *pClip;
+
+ pClip++;
+
+ if (cbox.x1 < x1)
+ cbox.x1 = x1;
+ if (cbox.y1 < y1)
+ cbox.y1 = y1;
+ if (cbox.x2 > x2)
+ cbox.x2 = x2;
+ if (cbox.y2 > y2)
+ cbox.y2 = y2;
+
+ if (cbox.x1 < cbox.x2 && cbox.y1 < cbox.y2)
+ {
+ addQuads (d, matrix, nMatrix,
+ cbox.x1, cbox.y1, cbox.x2, cbox.y2,
+ n, vSize, rect, priv->geometry,
+ maxGridWidth, maxGridHeight);
+ }
+ }
+ }
+ }
+ }
+
+ priv->geometry.vCount = n * 4;
+ priv->geometry.vertexStride = vSize;
+ priv->geometry.texCoordSize = 2;
+ }
+}
+
+static bool
+enableFragmentProgramAndDrawGeometry (GLScreen *gs,
+ GLWindow *w,
+ GLTexture *texture,
+ GLFragment::Attrib &attrib,
+ GLTexture::Filter filter,
+ unsigned int mask)
+{
+ GLFragment::Attrib fa (attrib);
+ bool blending;
+
+ if (GL::canDoSaturated && attrib.getSaturation () != COLOR)
+ {
+ int param, function;
+
+ param = fa.allocParameters (1);
+ function =
+ GLFragment::getSaturateFragmentFunction (texture, param);
+
+ fa.addFunction (function);
+
+ (*GL::programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB, param,
+ RED_SATURATION_WEIGHT,
+ GREEN_SATURATION_WEIGHT,
+ BLUE_SATURATION_WEIGHT,
+ attrib.getSaturation () / 65535.0f);
+ }
+
+ if (!fa.enable (&blending))
+ return false;
+
+ texture->enable (filter);
+
+ if (mask & PAINT_WINDOW_BLEND_MASK)
+ {
+ if (blending)
+ glEnable (GL_BLEND);
+
+ if (attrib.getOpacity () != OPAQUE || attrib.getBrightness () != BRIGHT)
+ {
+ GLushort color;
+
+ color = (attrib.getOpacity () * attrib.getBrightness ()) >> 16;
+
+ gs->setTexEnvMode (GL_MODULATE);
+ glColor4us (color, color, color, attrib.getOpacity ());
+
+ w->glDrawGeometry ();
+
+ glColor4usv (defaultColor);
+ gs->setTexEnvMode (GL_REPLACE);
+ }
+ else
+ {
+ w->glDrawGeometry ();
+ }
+
+ if (blending)
+ glDisable (GL_BLEND);
+ }
+ else if (attrib.getBrightness () != BRIGHT)
+ {
+ gs->setTexEnvMode (GL_MODULATE);
+ glColor4us (attrib.getBrightness (), attrib.getBrightness (),
+ attrib.getBrightness (), BRIGHT);
+
+ w->glDrawGeometry ();
+
+ glColor4usv (defaultColor);
+ gs->setTexEnvMode (GL_REPLACE);
+ }
+ else
+ {
+ w->glDrawGeometry ();
+ }
+
+ texture->disable ();
+
+ fa.disable ();
+
+ return true;
+}
+
+static void
+enableFragmentOperationsAndDrawGeometry (GLScreen *gs,
+ GLWindow *w,
+ GLTexture *texture,
+ GLFragment::Attrib &attrib,
+ GLTexture::Filter filter,
+ unsigned int mask)
+{
+ if (GL::canDoSaturated && attrib.getSaturation () != COLOR)
+ {
+ GLfloat constant[4];
+
+ if (mask & PAINT_WINDOW_BLEND_MASK)
+ glEnable (GL_BLEND);
+
+ texture->enable (filter);
+
+ glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+
+ glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_PRIMARY_COLOR);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
+
+ glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+
+ glColor4f (1.0f, 1.0f, 1.0f, 0.5f);
+
+ GL::activeTexture (GL_TEXTURE1_ARB);
+
+ texture->enable (filter);
+
+ glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+
+ glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+
+ if (GL::canDoSlightlySaturated && attrib.getSaturation () > 0)
+ {
+ glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+
+ constant[0] = 0.5f + 0.5f * RED_SATURATION_WEIGHT;
+ constant[1] = 0.5f + 0.5f * GREEN_SATURATION_WEIGHT;
+ constant[2] = 0.5f + 0.5f * BLUE_SATURATION_WEIGHT;
+ constant[3] = 1.0;
+
+ glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant);
+
+ GL::activeTexture (GL_TEXTURE2_ARB);
+
+ texture->enable (filter);
+
+ glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+
+ glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE0);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_CONSTANT);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
+
+ glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+
+ constant[3] = attrib.getSaturation () / 65535.0f;
+
+ glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant);
+
+ if (attrib.getOpacity () < OPAQUE ||
+ attrib.getBrightness () != BRIGHT)
+ {
+ GL::activeTexture (GL_TEXTURE3_ARB);
+
+ texture->enable (filter);
+
+ constant[3] = attrib.getOpacity () / 65535.0f;
+ constant[0] = constant[1] = constant[2] = constant[3] *
+ attrib.getBrightness () / 65535.0f;
+
+ glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant);
+
+ glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+
+ glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+
+ glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_CONSTANT);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+
+ w->glDrawGeometry ();
+
+ texture->disable ();
+
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+ GL::activeTexture (GL_TEXTURE2_ARB);
+ }
+ else
+ {
+ w->glDrawGeometry ();
+ }
+
+ texture->disable ();
+
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+ GL::activeTexture (GL_TEXTURE1_ARB);
+ }
+ else
+ {
+ glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_CONSTANT);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+
+ constant[3] = attrib.getOpacity () / 65535.0f;
+ constant[0] = constant[1] = constant[2] = constant[3] *
+ attrib.getBrightness ()/ 65535.0f;
+
+ constant[0] = 0.5f + 0.5f * RED_SATURATION_WEIGHT * constant[0];
+ constant[1] = 0.5f + 0.5f * GREEN_SATURATION_WEIGHT * constant[1];
+ constant[2] = 0.5f + 0.5f * BLUE_SATURATION_WEIGHT * constant[2];
+
+ glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant);
+
+ w->glDrawGeometry ();
+ }
+
+ texture->disable ();
+
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+ GL::activeTexture (GL_TEXTURE0_ARB);
+
+ texture->disable ();
+
+ glColor4usv (defaultColor);
+ gs->setTexEnvMode (GL_REPLACE);
+
+ if (mask & PAINT_WINDOW_BLEND_MASK)
+ glDisable (GL_BLEND);
+ }
+ else
+ {
+ texture->enable (filter);
+
+ if (mask & PAINT_WINDOW_BLEND_MASK)
+ {
+ glEnable (GL_BLEND);
+ if (attrib.getOpacity ()!= OPAQUE ||
+ attrib.getBrightness () != BRIGHT)
+ {
+ GLushort color;
+
+ color = (attrib.getOpacity () * attrib.getBrightness ()) >> 16;
+
+ gs->setTexEnvMode (GL_MODULATE);
+ glColor4us (color, color, color, attrib.getOpacity ());
+
+ w->glDrawGeometry ();
+
+ glColor4usv (defaultColor);
+ gs->setTexEnvMode (GL_REPLACE);
+ }
+ else
+ {
+ w->glDrawGeometry ();
+ }
+
+ glDisable (GL_BLEND);
+ }
+ else if (attrib.getBrightness () != BRIGHT)
+ {
+ gs->setTexEnvMode (GL_MODULATE);
+ glColor4us (attrib.getBrightness (), attrib.getBrightness (),
+ attrib.getBrightness (), BRIGHT);
+
+ w->glDrawGeometry ();
+
+ glColor4usv (defaultColor);
+ gs->setTexEnvMode (GL_REPLACE);
+ }
+ else
+ {
+ w->glDrawGeometry ();
+ }
+
+ texture->disable ();
+ }
+}
+
+void
+GLWindow::glDrawTexture (GLTexture *texture,
+ GLFragment::Attrib &attrib,
+ unsigned int mask)
+{
+ WRAPABLE_HND_FUNC (3, glDrawTexture, texture, attrib, mask)
+
+ GLTexture::Filter filter;
+
+ if (mask & (PAINT_WINDOW_TRANSFORMED_MASK |
+ PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK))
+ filter = priv->gScreen->filter (SCREEN_TRANS_FILTER);
+ else
+ filter = priv->gScreen->filter (NOTHING_TRANS_FILTER);
+
+ if ((!attrib.hasFunctions () && (!priv->gScreen->lighting () ||
+ attrib.getSaturation () == COLOR || attrib.getSaturation () == 0)) ||
+ !enableFragmentProgramAndDrawGeometry (priv->gScreen, this, texture,
+ attrib, filter, mask))
+ {
+ enableFragmentOperationsAndDrawGeometry (priv->gScreen, this, texture,
+ attrib, filter, mask);
+ }
+}
+
+bool
+GLWindow::glDraw (const GLMatrix &transform,
+ GLFragment::Attrib &fragment,
+ const CompRegion &region,
+ unsigned int mask)
+{
+ WRAPABLE_HND_FUNC_RETURN (1, bool, glDraw, transform,
+ fragment, region, mask)
+
+ const CompRegion reg = (mask & PAINT_WINDOW_TRANSFORMED_MASK) ?
+ infiniteRegion : region;
+
+ if (reg.isEmpty ())
+ return true;
+
+ if (!priv->window->isViewable ())
+ return true;
+
+ if (priv->textures.empty () && !bind ())
+ return false;
+
+ if (mask & PAINT_WINDOW_TRANSLUCENT_MASK)
+ mask |= PAINT_WINDOW_BLEND_MASK;
+
+ GLTexture::MatrixList ml (1);
+
+ if (priv->textures.size () == 1)
+ {
+ ml[0] = priv->matrices[0];
+ priv->geometry.reset ();
+ glAddGeometry (ml, priv->window->region (), reg);
+ if (priv->geometry.vCount)
+ glDrawTexture (priv->textures[0], fragment, mask);
+ }
+ else
+ {
+ if (priv->updateReg)
+ priv->updateWindowRegions ();
+ for (unsigned int i = 0; i < priv->textures.size (); i++)
+ {
+ ml[0] = priv->matrices[i];
+ priv->geometry.reset ();
+ glAddGeometry (ml, priv->regions[i], reg);
+ if (priv->geometry.vCount)
+ glDrawTexture (priv->textures[i], fragment, mask);
+ }
+ }
+
+ return true;
+}
+
+bool
+GLWindow::glPaint (const GLWindowPaintAttrib &attrib,
+ const GLMatrix &transform,
+ const CompRegion &region,
+ unsigned int mask)
+{
+ WRAPABLE_HND_FUNC_RETURN (0, bool, glPaint, attrib, transform, region, mask)
+
+ GLFragment::Attrib fragment (attrib);
+ bool status;
+
+ priv->lastPaint = attrib;
+
+ if (priv->window->alpha () || attrib.opacity != OPAQUE)
+ mask |= PAINT_WINDOW_TRANSLUCENT_MASK;
+
+ priv->lastMask = mask;
+
+ if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK)
+ {
+ if (mask & PAINT_WINDOW_TRANSFORMED_MASK)
+ return false;
+
+ if (mask & PAINT_WINDOW_NO_CORE_INSTANCE_MASK)
+ return false;
+
+ if (mask & PAINT_WINDOW_TRANSLUCENT_MASK)
+ return false;
+
+ if (priv->window->shaded ())
+ return false;
+
+ return true;
+ }
+
+ if (mask & PAINT_WINDOW_NO_CORE_INSTANCE_MASK)
+ return true;
+
+ if (mask & PAINT_WINDOW_TRANSFORMED_MASK ||
+ mask & PAINT_WINDOW_WITH_OFFSET_MASK)
+ {
+ glPushMatrix ();
+ glLoadMatrixf (transform.getMatrix ());
+ }
+
+ status = glDraw (transform, fragment, region, mask);
+
+ if (mask & PAINT_WINDOW_TRANSFORMED_MASK ||
+ mask & PAINT_WINDOW_WITH_OFFSET_MASK)
+ glPopMatrix ();
+
+ return status;
+}
diff --git a/plugins/opengl/src/privatefragment.h b/plugins/opengl/src/privatefragment.h
new file mode 100644
index 0000000..8a94d04
--- /dev/null
+++ b/plugins/opengl/src/privatefragment.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright © 2008 Dennis Kasprzyk
+ * Copyright © 2007 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
+ * Dennis Kasprzyk not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Dennis Kasprzyk makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * DENNIS KASPRZYK DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL DENNIS KASPRZYK 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.
+ *
+ * Authors: Dennis Kasprzyk <onestone@compiz-fusion.org>
+ * David Reveman <davidr@novell.com>
+ */
+
+#ifndef _PRIVATEFRAGMENT_H
+#define _PRIVATEFRAGMENT_H
+
+#include <vector>
+
+#include <opengl/fragment.h>
+
+namespace GLFragment {
+
+ class Function;
+ class Program;
+
+ class Storage {
+ public:
+ Storage ();
+ ~Storage ();
+
+ public:
+ int lastFunctionId;
+ std::vector<Function *> functions;
+ std::vector<Program *> programs;
+
+ FunctionId saturateFunction[2][64];
+ };
+};
+
+#endif
diff --git a/plugins/opengl/src/privates.h b/plugins/opengl/src/privates.h
new file mode 100644
index 0000000..3aebaf0
--- /dev/null
+++ b/plugins/opengl/src/privates.h
@@ -0,0 +1,172 @@
+/*
+ * Copyright © 2008 Dennis Kasprzyk
+ * Copyright © 2007 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
+ * Dennis Kasprzyk not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Dennis Kasprzyk makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * DENNIS KASPRZYK DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL DENNIS KASPRZYK 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.
+ *
+ * Authors: Dennis Kasprzyk <onestone@compiz-fusion.org>
+ * David Reveman <davidr@novell.com>
+ */
+
+#ifndef _OPENGL_PRIVATES_H
+#define _OPENGL_PRIVATES_H
+
+#include <composite/composite.h>
+#include <opengl/opengl.h>
+#include <core/atoms.h>
+
+#include "privatefragment.h"
+#include "privatetexture.h"
+#include "opengl_options.h"
+
+extern CompOutput *targetOutput;
+
+class GLIcon
+{
+ public:
+ GLIcon () : icon (NULL) {};
+
+ CompIcon *icon;
+ GLTexture::List textures;
+};
+
+class PrivateGLScreen :
+ public ScreenInterface,
+ public CompositeScreen::PaintHandler,
+ public OpenglOptions
+{
+ public:
+ PrivateGLScreen (GLScreen *gs);
+ ~PrivateGLScreen ();
+
+ bool setOption (const CompString &name, CompOption::Value &value);
+
+ void handleEvent (XEvent *event);
+
+ void outputChangeNotify ();
+
+ void paintOutputs (CompOutput::ptrList &outputs,
+ unsigned int mask,
+ const CompRegion &region);
+
+ bool hasVSync ();
+
+ void prepareDrawing ();
+
+ void waitForVideoSync ();
+
+ void paintBackground (const CompRegion &region,
+ bool transformed);
+
+ void paintOutputRegion (const GLMatrix &transform,
+ const CompRegion &region,
+ CompOutput *output,
+ unsigned int mask);
+
+ void updateScreenBackground ();
+
+ void updateView ();
+
+ public:
+
+ GLScreen *gScreen;
+ CompositeScreen *cScreen;
+
+ GLenum textureFilter;
+
+ GLFBConfig glxPixmapFBConfigs[MAX_DEPTH + 1];
+
+ GLTexture::List backgroundTextures;
+ bool backgroundLoaded;
+
+ GLTexture::Filter filter[3];
+
+ CompPoint rasterPos;
+
+ GLFragment::Storage fragmentStorage;
+
+ GLfloat projection[16];
+
+ bool clearBuffers;
+ bool lighting;
+
+ GL::GLXGetProcAddressProc getProcAddress;
+
+ GLXContext ctx;
+
+ CompRegion outputRegion;
+
+ bool pendingCommands;
+
+ XRectangle lastViewport;
+
+ std::vector<GLTexture::BindPixmapProc> bindPixmap;
+ bool hasCompositing;
+
+ GLIcon defaultIcon;
+};
+
+class PrivateGLWindow :
+ public WindowInterface,
+ public CompositeWindowInterface
+{
+ public:
+ PrivateGLWindow (CompWindow *w, GLWindow *gw);
+ ~PrivateGLWindow ();
+
+ void windowNotify (CompWindowNotify n);
+ void resizeNotify (int dx, int dy, int dwidth, int dheight);
+ void moveNotify (int dx, int dy, bool now);
+ void updateFrameRegion (CompRegion &region);
+
+ void setWindowMatrix ();
+ void updateWindowRegions ();
+
+ CompWindow *window;
+ GLWindow *gWindow;
+ CompositeWindow *cWindow;
+ GLScreen *gScreen;
+
+ GLTexture::List textures;
+ GLTexture::MatrixList matrices;
+ CompRegion::Vector regions;
+ bool updateReg;
+
+ CompRegion clip;
+
+ bool bindFailed;
+ bool overlayWindow;
+
+ GLushort opacity;
+ GLushort brightness;
+ GLushort saturation;
+
+ GLWindowPaintAttrib paint;
+ GLWindowPaintAttrib lastPaint;
+
+ unsigned int lastMask;
+
+ GLWindow::Geometry geometry;
+
+ std::list<GLIcon> icons;
+};
+
+
+#endif
diff --git a/plugins/opengl/src/privatetexture.h b/plugins/opengl/src/privatetexture.h
new file mode 100644
index 0000000..e647876
--- /dev/null
+++ b/plugins/opengl/src/privatetexture.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright © 2008 Dennis Kasprzyk
+ * Copyright © 2007 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
+ * Dennis Kasprzyk not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Dennis Kasprzyk makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * DENNIS KASPRZYK DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL DENNIS KASPRZYK 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.
+ *
+ * Authors: Dennis Kasprzyk <onestone@compiz-fusion.org>
+ * David Reveman <davidr@novell.com>
+ */
+
+#ifndef _PRIVATETEXTURE_H
+#define _PRIVATETEXTURE_H
+
+#include <map>
+
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <opengl/texture.h>
+
+class GLScreen;
+class GLDisplay;
+
+class PrivateTexture {
+ public:
+ PrivateTexture (GLTexture *);
+ ~PrivateTexture ();
+
+ static GLTexture::List loadImageData (const char *image,
+ unsigned int width,
+ unsigned int height,
+ GLenum format,
+ GLenum type);
+
+ public:
+ GLTexture *texture;
+ GLuint name;
+ GLenum target;
+ GLenum filter;
+ GLenum wrap;
+ GLTexture::Matrix matrix;
+ bool mipmap;
+ bool mipmapSupport;
+ bool initial;
+ int refCount;
+};
+
+class TfpTexture : public GLTexture {
+ public:
+ TfpTexture ();
+ ~TfpTexture ();
+
+ void enable (Filter filter);
+
+ static List bindPixmapToTexture (Pixmap pixmap,
+ int width,
+ int height,
+ int depth);
+
+ public:
+ GLXPixmap pixmap;
+ bool damaged;
+ Damage damage;
+ bool updateMipMap;
+};
+
+extern std::map<Damage, TfpTexture*> boundPixmapTex;
+
+#endif
diff --git a/plugins/opengl/src/screen.cpp b/plugins/opengl/src/screen.cpp
new file mode 100644
index 0000000..b7e77c3
--- /dev/null
+++ b/plugins/opengl/src/screen.cpp
@@ -0,0 +1,1193 @@
+/*
+ * Copyright © 2008 Dennis Kasprzyk
+ * Copyright © 2007 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
+ * Dennis Kasprzyk not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Dennis Kasprzyk makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * DENNIS KASPRZYK DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL DENNIS KASPRZYK 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.
+ *
+ * Authors: Dennis Kasprzyk <onestone@compiz-fusion.org>
+ * David Reveman <davidr@novell.com>
+ */
+
+#include "privates.h"
+
+#include <dlfcn.h>
+#include <math.h>
+
+namespace GL {
+ GLXBindTexImageProc bindTexImage = NULL;
+ GLXReleaseTexImageProc releaseTexImage = NULL;
+ GLXQueryDrawableProc queryDrawable = NULL;
+ GLXCopySubBufferProc copySubBuffer = NULL;
+ GLXGetVideoSyncProc getVideoSync = NULL;
+ GLXWaitVideoSyncProc waitVideoSync = NULL;
+ GLXGetFBConfigsProc getFBConfigs = NULL;
+ GLXGetFBConfigAttribProc getFBConfigAttrib = NULL;
+ GLXCreatePixmapProc createPixmap = NULL;
+ GLXDestroyPixmapProc destroyPixmap = NULL;
+
+ GLActiveTextureProc activeTexture = NULL;
+ GLClientActiveTextureProc clientActiveTexture = NULL;
+ GLMultiTexCoord2fProc multiTexCoord2f = NULL;
+
+ GLGenProgramsProc genPrograms = NULL;
+ GLDeleteProgramsProc deletePrograms = NULL;
+ GLBindProgramProc bindProgram = NULL;
+ GLProgramStringProc programString = NULL;
+ GLProgramParameter4fProc programEnvParameter4f = NULL;
+ GLProgramParameter4fProc programLocalParameter4f = NULL;
+ GLGetProgramivProc getProgramiv = NULL;
+
+ GLGenFramebuffersProc genFramebuffers = NULL;
+ GLDeleteFramebuffersProc deleteFramebuffers = NULL;
+ GLBindFramebufferProc bindFramebuffer = NULL;
+ GLCheckFramebufferStatusProc checkFramebufferStatus = NULL;
+ GLFramebufferTexture2DProc framebufferTexture2D = NULL;
+ GLGenerateMipmapProc generateMipmap = NULL;
+
+ bool textureFromPixmap = true;
+ bool textureRectangle = false;
+ bool textureNonPowerOfTwo = false;
+ bool textureEnvCombine = false;
+ bool textureEnvCrossbar = false;
+ bool textureBorderClamp = false;
+ bool textureCompression = false;
+ GLint maxTextureSize = 0;
+ bool fbo = false;
+ bool fragmentProgram = false;
+ GLint maxTextureUnits = 1;
+
+ bool canDoSaturated = false;
+ bool canDoSlightlySaturated = false;
+}
+
+CompOutput *targetOutput = NULL;
+
+GLScreen::GLScreen (CompScreen *s) :
+ PluginClassHandler<GLScreen, CompScreen, COMPIZ_OPENGL_ABI> (s),
+ priv (new PrivateGLScreen (this))
+{
+ Display *dpy = s->dpy ();
+ XVisualInfo templ;
+ XVisualInfo *visinfo;
+ GLXFBConfig *fbConfigs;
+ int defaultDepth, nvisinfo, nElements, value, i;
+ const char *glxExtensions, *glExtensions;
+ GLfloat globalAmbient[] = { 0.1f, 0.1f, 0.1f, 0.1f };
+ GLfloat ambientLight[] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ GLfloat diffuseLight[] = { 0.9f, 0.9f, 0.9f, 0.9f };
+ GLfloat light0Position[] = { -0.5f, 0.5f, -9.0f, 1.0f };
+ XWindowAttributes attr;
+
+ if (indirectRendering)
+ {
+ /* force Mesa libGL into indirect rendering mode, because
+ glXQueryExtensionsString is context-independant */
+ setenv ("LIBGL_ALWAYS_INDIRECT", "1", True);
+ }
+
+ if (!XGetWindowAttributes (dpy, s->root (), &attr))
+ {
+ setFailed ();
+ return;
+ }
+
+ templ.visualid = XVisualIDFromVisual (attr.visual);
+
+ visinfo = XGetVisualInfo (dpy, VisualIDMask, &templ, &nvisinfo);
+ if (!nvisinfo)
+ {
+ compLogMessage ("opengl", CompLogLevelFatal,
+ "Couldn't get visual info for default visual");
+ setFailed ();
+ return;
+ }
+
+ defaultDepth = visinfo->depth;
+
+ glXGetConfig (dpy, visinfo, GLX_USE_GL, &value);
+ if (!value)
+ {
+ compLogMessage ("opengl", CompLogLevelFatal,
+ "Root visual is not a GL visual");
+ XFree (visinfo);
+ setFailed ();
+ return;
+ }
+
+ glXGetConfig (dpy, visinfo, GLX_DOUBLEBUFFER, &value);
+ if (!value)
+ {
+ compLogMessage ("opengl", CompLogLevelFatal,
+ "Root visual is not a double buffered GL visual");
+ XFree (visinfo);
+ setFailed ();
+ return;
+ }
+
+ priv->ctx = glXCreateContext (dpy, visinfo, NULL, !indirectRendering);
+ if (!priv->ctx)
+ {
+ compLogMessage ("opengl", CompLogLevelFatal,
+ "glXCreateContext failed");
+ XFree (visinfo);
+
+ setFailed ();
+ return;
+ }
+
+ XFree (visinfo);
+ glxExtensions = glXQueryExtensionsString (dpy, s->screenNum ());
+
+ if (!strstr (glxExtensions, "GLX_SGIX_fbconfig"))
+ {
+ compLogMessage ("opengl", CompLogLevelFatal,
+ "GLX_SGIX_fbconfig is missing");
+ setFailed ();
+ return;
+ }
+
+ priv->getProcAddress = (GL::GLXGetProcAddressProc)
+ getProcAddress ("glXGetProcAddressARB");
+ GL::bindTexImage = (GL::GLXBindTexImageProc)
+ getProcAddress ("glXBindTexImageEXT");
+ GL::releaseTexImage = (GL::GLXReleaseTexImageProc)
+ getProcAddress ("glXReleaseTexImageEXT");
+ GL::queryDrawable = (GL::GLXQueryDrawableProc)
+ getProcAddress ("glXQueryDrawable");
+ GL::getFBConfigs = (GL::GLXGetFBConfigsProc)
+ getProcAddress ("glXGetFBConfigs");
+ GL::getFBConfigAttrib = (GL::GLXGetFBConfigAttribProc)
+ getProcAddress ("glXGetFBConfigAttrib");
+ GL::createPixmap = (GL::GLXCreatePixmapProc)
+ getProcAddress ("glXCreatePixmap");
+ GL::destroyPixmap = (GL::GLXDestroyPixmapProc)
+ getProcAddress ("glXDestroyPixmap");
+
+ if (!strstr (glxExtensions, "GLX_EXT_texture_from_pixmap") ||
+ !GL::bindTexImage || !GL::releaseTexImage)
+ {
+ compLogMessage ("opengl", CompLogLevelFatal,
+ "GLX_EXT_texture_from_pixmap is missing");
+ GL::textureFromPixmap = false;
+ }
+ else
+ GL::textureFromPixmap = true;
+
+ if (!GL::queryDrawable ||
+ !GL::getFBConfigs ||
+ !GL::getFBConfigAttrib ||
+ !GL::createPixmap ||
+ !GL::destroyPixmap)
+ {
+ compLogMessage ("opengl", CompLogLevelFatal,
+ "fbconfig functions missing");
+ setFailed ();
+ return;
+ }
+
+ if (strstr (glxExtensions, "GLX_MESA_copy_sub_buffer"))
+ GL::copySubBuffer = (GL::GLXCopySubBufferProc)
+ getProcAddress ("glXCopySubBufferMESA");
+
+ if (strstr (glxExtensions, "GLX_SGI_video_sync"))
+ {
+ GL::getVideoSync = (GL::GLXGetVideoSyncProc)
+ getProcAddress ("glXGetVideoSyncSGI");
+
+ GL::waitVideoSync = (GL::GLXWaitVideoSyncProc)
+ getProcAddress ("glXWaitVideoSyncSGI");
+ }
+
+ glXMakeCurrent (dpy, CompositeScreen::get (s)->output (), priv->ctx);
+
+ glExtensions = (const char *) glGetString (GL_EXTENSIONS);
+ if (!glExtensions)
+ {
+ compLogMessage ("opengl", CompLogLevelFatal,
+ "No valid GL extensions string found.");
+ setFailed ();
+ return;
+ }
+
+ if (strstr (glExtensions, "GL_ARB_texture_non_power_of_two"))
+ GL::textureNonPowerOfTwo = true;
+
+ glGetIntegerv (GL_MAX_TEXTURE_SIZE, &GL::maxTextureSize);
+
+ if (strstr (glExtensions, "GL_NV_texture_rectangle") ||
+ strstr (glExtensions, "GL_EXT_texture_rectangle") ||
+ strstr (glExtensions, "GL_ARB_texture_rectangle"))
+ {
+ GL::textureRectangle = true;
+
+ if (!GL::textureNonPowerOfTwo)
+ {
+ GLint maxTextureSize;
+
+ glGetIntegerv (GL_MAX_RECTANGLE_TEXTURE_SIZE_NV, &maxTextureSize);
+ if (maxTextureSize > GL::maxTextureSize)
+ GL::maxTextureSize = maxTextureSize;
+ }
+ }
+
+ if (!(GL::textureRectangle || GL::textureNonPowerOfTwo))
+ {
+ compLogMessage ("opengl", CompLogLevelFatal,
+ "Support for non power of two textures missing");
+ setFailed ();
+ return;
+ }
+
+ if (strstr (glExtensions, "GL_ARB_texture_env_combine"))
+ {
+ GL::textureEnvCombine = true;
+
+ /* XXX: GL_NV_texture_env_combine4 need special code but it seams to
+ be working anyway for now... */
+ if (strstr (glExtensions, "GL_ARB_texture_env_crossbar") ||
+ strstr (glExtensions, "GL_NV_texture_env_combine4"))
+ GL::textureEnvCrossbar = true;
+ }
+
+ if (strstr (glExtensions, "GL_ARB_texture_border_clamp") ||
+ strstr (glExtensions, "GL_SGIS_texture_border_clamp"))
+ GL::textureBorderClamp = true;
+
+ GL::maxTextureUnits = 1;
+ if (strstr (glExtensions, "GL_ARB_multitexture"))
+ {
+ GL::activeTexture = (GL::GLActiveTextureProc)
+ getProcAddress ("glActiveTexture");
+ GL::clientActiveTexture = (GL::GLClientActiveTextureProc)
+ getProcAddress ("glClientActiveTexture");
+ GL::multiTexCoord2f = (GL::GLMultiTexCoord2fProc)
+ getProcAddress ("glMultiTexCoord2f");
+
+ if (GL::activeTexture && GL::clientActiveTexture && GL::multiTexCoord2f)
+ glGetIntegerv (GL_MAX_TEXTURE_UNITS_ARB, &GL::maxTextureUnits);
+ }
+
+ if (strstr (glExtensions, "GL_ARB_fragment_program"))
+ {
+ GL::genPrograms = (GL::GLGenProgramsProc)
+ getProcAddress ("glGenProgramsARB");
+ GL::deletePrograms = (GL::GLDeleteProgramsProc)
+ getProcAddress ("glDeleteProgramsARB");
+ GL::bindProgram = (GL::GLBindProgramProc)
+ getProcAddress ("glBindProgramARB");
+ GL::programString = (GL::GLProgramStringProc)
+ getProcAddress ("glProgramStringARB");
+ GL::programEnvParameter4f = (GL::GLProgramParameter4fProc)
+ getProcAddress ("glProgramEnvParameter4fARB");
+ GL::programLocalParameter4f = (GL::GLProgramParameter4fProc)
+ getProcAddress ("glProgramLocalParameter4fARB");
+ GL::getProgramiv = (GL::GLGetProgramivProc)
+ getProcAddress ("glGetProgramivARB");
+
+ if (GL::genPrograms &&
+ GL::deletePrograms &&
+ GL::bindProgram &&
+ GL::programString &&
+ GL::programEnvParameter4f &&
+ GL::programLocalParameter4f &&
+ GL::getProgramiv)
+ GL::fragmentProgram = true;
+ }
+
+ if (strstr (glExtensions, "GL_EXT_framebuffer_object"))
+ {
+ GL::genFramebuffers = (GL::GLGenFramebuffersProc)
+ getProcAddress ("glGenFramebuffersEXT");
+ GL::deleteFramebuffers = (GL::GLDeleteFramebuffersProc)
+ getProcAddress ("glDeleteFramebuffersEXT");
+ GL::bindFramebuffer = (GL::GLBindFramebufferProc)
+ getProcAddress ("glBindFramebufferEXT");
+ GL::checkFramebufferStatus = (GL::GLCheckFramebufferStatusProc)
+ getProcAddress ("glCheckFramebufferStatusEXT");
+ GL::framebufferTexture2D = (GL::GLFramebufferTexture2DProc)
+ getProcAddress ("glFramebufferTexture2DEXT");
+ GL::generateMipmap = (GL::GLGenerateMipmapProc)
+ getProcAddress ("glGenerateMipmapEXT");
+
+ if (GL::genFramebuffers &&
+ GL::deleteFramebuffers &&
+ GL::bindFramebuffer &&
+ GL::checkFramebufferStatus &&
+ GL::framebufferTexture2D &&
+ GL::generateMipmap)
+ GL::fbo = true;
+ }
+
+ if (strstr (glExtensions, "GL_ARB_texture_compression"))
+ GL::textureCompression = true;
+
+ fbConfigs = (*GL::getFBConfigs) (dpy, s->screenNum (), &nElements);
+
+ for (i = 0; i <= MAX_DEPTH; i++)
+ {
+ int j, db, stencil, depth, alpha, mipmap, rgba;
+
+ priv->glxPixmapFBConfigs[i].fbConfig = NULL;
+ priv->glxPixmapFBConfigs[i].mipmap = 0;
+ priv->glxPixmapFBConfigs[i].yInverted = 0;
+ priv->glxPixmapFBConfigs[i].textureFormat = 0;
+ priv->glxPixmapFBConfigs[i].textureTargets = 0;
+
+ db = MAXSHORT;
+ stencil = MAXSHORT;
+ depth = MAXSHORT;
+ mipmap = 0;
+ rgba = 0;
+
+ for (j = 0; j < nElements; j++)
+ {
+ XVisualInfo *vi;
+ int visualDepth;
+
+ vi = glXGetVisualFromFBConfig (dpy, fbConfigs[j]);
+ if (vi == NULL)
+ continue;
+
+ visualDepth = vi->depth;
+
+ XFree (vi);
+
+ if (visualDepth != i)
+ continue;
+
+ (*GL::getFBConfigAttrib) (dpy, fbConfigs[j],
+ GLX_ALPHA_SIZE, &alpha);
+ (*GL::getFBConfigAttrib) (dpy, fbConfigs[j],
+ GLX_BUFFER_SIZE, &value);
+ if (value != i && (value - alpha) != i)
+ continue;
+
+ value = 0;
+ if (i == 32)
+ {
+ (*GL::getFBConfigAttrib) (dpy, fbConfigs[j],
+ GLX_BIND_TO_TEXTURE_RGBA_EXT, &value);
+
+ if (value)
+ {
+ rgba = 1;
+
+ priv->glxPixmapFBConfigs[i].textureFormat =
+ GLX_TEXTURE_FORMAT_RGBA_EXT;
+ }
+ }
+
+ if (!value)
+ {
+ if (rgba)
+ continue;
+
+ (*GL::getFBConfigAttrib) (dpy, fbConfigs[j],
+ GLX_BIND_TO_TEXTURE_RGB_EXT, &value);
+ if (!value)
+ continue;
+
+ priv->glxPixmapFBConfigs[i].textureFormat =
+ GLX_TEXTURE_FORMAT_RGB_EXT;
+ }
+
+ (*GL::getFBConfigAttrib) (dpy, fbConfigs[j],
+ GLX_DOUBLEBUFFER, &value);
+ if (value > db)
+ continue;
+
+ db = value;
+
+ (*GL::getFBConfigAttrib) (dpy, fbConfigs[j],
+ GLX_STENCIL_SIZE, &value);
+ if (value > stencil)
+ continue;
+
+ stencil = value;
+
+ (*GL::getFBConfigAttrib) (dpy, fbConfigs[j],
+ GLX_DEPTH_SIZE, &value);
+ if (value > depth)
+ continue;
+
+ depth = value;
+
+ if (GL::fbo)
+ {
+ (*GL::getFBConfigAttrib) (dpy, fbConfigs[j],
+ GLX_BIND_TO_MIPMAP_TEXTURE_EXT,
+ &value);
+ if (value < mipmap)
+ continue;
+
+ mipmap = value;
+ }
+
+ (*GL::getFBConfigAttrib) (dpy, fbConfigs[j],
+ GLX_Y_INVERTED_EXT, &value);
+
+ priv->glxPixmapFBConfigs[i].yInverted = value;
+
+ (*GL::getFBConfigAttrib) (dpy, fbConfigs[j],
+ GLX_BIND_TO_TEXTURE_TARGETS_EXT, &value);
+
+ priv->glxPixmapFBConfigs[i].textureTargets = value;
+
+ priv->glxPixmapFBConfigs[i].fbConfig = fbConfigs[j];
+ priv->glxPixmapFBConfigs[i].mipmap = mipmap;
+ }
+ }
+
+ if (nElements)
+ XFree (fbConfigs);
+
+ if (!priv->glxPixmapFBConfigs[defaultDepth].fbConfig)
+ {
+ compLogMessage ("opengl", CompLogLevelFatal,
+ "No GLXFBConfig for default depth, "
+ "this isn't going to work.");
+ setFailed ();
+ return;
+ }
+
+ glClearColor (0.0, 0.0, 0.0, 1.0);
+ glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable (GL_CULL_FACE);
+ glDisable (GL_BLEND);
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glColor4usv (defaultColor);
+ glEnableClientState (GL_VERTEX_ARRAY);
+ glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+
+ if (GL::textureEnvCombine && GL::maxTextureUnits >= 2)
+ {
+ GL::canDoSaturated = true;
+ if (GL::textureEnvCrossbar && GL::maxTextureUnits >= 4)
+ GL::canDoSlightlySaturated = true;
+ }
+
+ priv->updateView ();
+
+ glLightModelfv (GL_LIGHT_MODEL_AMBIENT, globalAmbient);
+
+ glEnable (GL_LIGHT0);
+ glLightfv (GL_LIGHT0, GL_AMBIENT, ambientLight);
+ glLightfv (GL_LIGHT0, GL_DIFFUSE, diffuseLight);
+ glLightfv (GL_LIGHT0, GL_POSITION, light0Position);
+
+ glColorMaterial (GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
+
+ glNormal3f (0.0f, 0.0f, -1.0f);
+
+ priv->lighting = false;
+
+
+ priv->filter[NOTHING_TRANS_FILTER] = GLTexture::Fast;
+ priv->filter[SCREEN_TRANS_FILTER] = GLTexture::Good;
+ priv->filter[WINDOW_TRANS_FILTER] = GLTexture::Good;
+
+ if (GL::textureFromPixmap)
+ registerBindPixmap (TfpTexture::bindPixmapToTexture);
+
+}
+
+GLScreen::~GLScreen ()
+{
+ if (priv->hasCompositing)
+ CompositeScreen::get (screen)->unregisterPaintHandler ();
+ glXDestroyContext (screen->dpy (), priv->ctx);
+ delete priv;
+}
+
+PrivateGLScreen::PrivateGLScreen (GLScreen *gs) :
+ gScreen (gs),
+ cScreen (CompositeScreen::get (screen)),
+ textureFilter (GL_LINEAR),
+ backgroundTextures (),
+ backgroundLoaded (false),
+ rasterPos (0, 0),
+ fragmentStorage (),
+ clearBuffers (true),
+ lighting (false),
+ getProcAddress (0),
+ outputRegion (),
+ pendingCommands (false),
+ bindPixmap (),
+ hasCompositing (false)
+{
+ ScreenInterface::setHandler (screen);
+}
+
+PrivateGLScreen::~PrivateGLScreen ()
+{
+}
+
+GLushort defaultColor[4] = { 0xffff, 0xffff, 0xffff, 0xffff };
+
+
+
+GLenum
+GLScreen::textureFilter ()
+{
+ return priv->textureFilter;
+}
+
+void
+GLScreen::setTextureFilter (GLenum filter)
+{
+ priv->textureFilter = filter;
+}
+
+void
+PrivateGLScreen::handleEvent (XEvent *event)
+{
+ CompWindow *w;
+
+ screen->handleEvent (event);
+
+ switch (event->type) {
+ case PropertyNotify:
+ if (event->xproperty.atom == Atoms::xBackground[0] ||
+ event->xproperty.atom == Atoms::xBackground[1])
+ {
+ if (event->xproperty.window == screen->root ())
+ gScreen->updateBackground ();
+ }
+ else if (event->xproperty.atom == Atoms::winOpacity ||
+ event->xproperty.atom == Atoms::winBrightness ||
+ event->xproperty.atom == Atoms::winSaturation)
+ {
+ w = screen->findWindow (event->xproperty.window);
+ if (w)
+ GLWindow::get (w)->updatePaintAttribs ();
+ }
+ else if (event->xproperty.atom == Atoms::wmIcon)
+ {
+ w = screen->findWindow (event->xproperty.window);
+ if (w)
+ GLWindow::get (w)->priv->icons.clear ();
+ }
+ break;
+ break;
+ default:
+ if (event->type == cScreen->damageEvent () + XDamageNotify)
+ {
+ XDamageNotifyEvent *de = (XDamageNotifyEvent *) event;
+
+ std::map<Damage, TfpTexture*>::iterator it =
+ boundPixmapTex.find (de->damage);
+ if (it != boundPixmapTex.end ())
+ {
+ it->second->damaged = true;
+ }
+ }
+ break;
+ }
+}
+
+void
+GLScreen::clearTargetOutput (unsigned int mask)
+{
+ clearOutput (targetOutput, mask);
+}
+
+
+static void
+frustum (GLfloat *m,
+ GLfloat left,
+ GLfloat right,
+ GLfloat bottom,
+ GLfloat top,
+ GLfloat nearval,
+ GLfloat farval)
+{
+ GLfloat x, y, a, b, c, d;
+
+ x = (2.0 * nearval) / (right - left);
+ y = (2.0 * nearval) / (top - bottom);
+ a = (right + left) / (right - left);
+ b = (top + bottom) / (top - bottom);
+ c = -(farval + nearval) / ( farval - nearval);
+ d = -(2.0 * farval * nearval) / (farval - nearval);
+
+#define M(row,col) m[col * 4 + row]
+ M(0,0) = x; M(0,1) = 0.0f; M(0,2) = a; M(0,3) = 0.0f;
+ M(1,0) = 0.0f; M(1,1) = y; M(1,2) = b; M(1,3) = 0.0f;
+ M(2,0) = 0.0f; M(2,1) = 0.0f; M(2,2) = c; M(2,3) = d;
+ M(3,0) = 0.0f; M(3,1) = 0.0f; M(3,2) = -1.0f; M(3,3) = 0.0f;
+#undef M
+
+}
+
+static void
+perspective (GLfloat *m,
+ GLfloat fovy,
+ GLfloat aspect,
+ GLfloat zNear,
+ GLfloat zFar)
+{
+ GLfloat xmin, xmax, ymin, ymax;
+
+ ymax = zNear * tan (fovy * M_PI / 360.0);
+ ymin = -ymax;
+ xmin = ymin * aspect;
+ xmax = ymax * aspect;
+
+ frustum (m, xmin, xmax, ymin, ymax, zNear, zFar);
+}
+
+void
+PrivateGLScreen::updateView ()
+{
+ glMatrixMode (GL_PROJECTION);
+ glLoadIdentity ();
+ glMatrixMode (GL_MODELVIEW);
+ glLoadIdentity ();
+ glDepthRange (0, 1);
+ glViewport (-1, -1, 2, 2);
+ glRasterPos2f (0, 0);
+
+ rasterPos = CompPoint (0, 0);
+
+ perspective (projection, 60.0f, 1.0f, 0.1f, 100.0f);
+
+ glMatrixMode (GL_PROJECTION);
+ glLoadIdentity ();
+ glMultMatrixf (projection);
+ glMatrixMode (GL_MODELVIEW);
+
+ CompRegion region (screen->region ());
+ /* remove all output regions from visible screen region */
+ foreach (CompOutput &o, screen->outputDevs ())
+ region -= o;
+
+ /* we should clear color buffers before swapping if we have visible
+ regions without output */
+ clearBuffers = !region.isEmpty ();
+
+ gScreen->setDefaultViewport ();
+}
+
+void
+PrivateGLScreen::outputChangeNotify ()
+{
+ screen->outputChangeNotify ();
+
+ updateView ();
+}
+
+GL::FuncPtr
+GLScreen::getProcAddress (const char *name)
+{
+ static void *dlhand = NULL;
+ GL::FuncPtr funcPtr = NULL;
+
+ if (priv->getProcAddress)
+ funcPtr = priv->getProcAddress ((GLubyte *) name);
+
+ if (!funcPtr)
+ {
+ if (!dlhand)
+ dlhand = dlopen ("libopengl.so", RTLD_LAZY);
+
+ if (dlhand)
+ {
+ dlerror ();
+ funcPtr = (GL::FuncPtr) dlsym (dlhand, name);
+ if (dlerror () != NULL)
+ funcPtr = NULL;
+ }
+ }
+
+ return funcPtr;
+}
+
+void
+PrivateGLScreen::updateScreenBackground ()
+{
+ Display *dpy = screen->dpy ();
+ Atom pixmapAtom, actualType;
+ int actualFormat, i, status;
+ unsigned int width = 1, height = 1, depth = 0;
+ unsigned long nItems;
+ unsigned long bytesAfter;
+ unsigned char *prop;
+ Pixmap pixmap = 0;
+
+ pixmapAtom = XInternAtom (dpy, "PIXMAP", false);
+
+ for (i = 0; pixmap == 0 && i < 2; i++)
+ {
+ status = XGetWindowProperty (dpy, screen->root (),
+ Atoms::xBackground[i],
+ 0, 4, false, AnyPropertyType,
+ &actualType, &actualFormat, &nItems,
+ &bytesAfter, &prop);
+
+ if (status == Success && nItems && prop)
+ {
+ if (actualType == pixmapAtom &&
+ actualFormat == 32 &&
+ nItems == 1)
+ {
+ Pixmap p;
+
+ memcpy (&p, prop, 4);
+
+ if (p)
+ {
+ unsigned int ui;
+ int i;
+ Window w;
+
+ if (XGetGeometry (dpy, p, &w, &i, &i,
+ &width, &height, &ui, &depth))
+ {
+ if ((int) depth == screen->attrib ().depth)
+ pixmap = p;
+ }
+ }
+ }
+
+ XFree (prop);
+ }
+ }
+
+ if (pixmap)
+ {
+ backgroundTextures =
+ GLTexture::bindPixmapToTexture (pixmap, width, height, depth);
+ if (backgroundTextures.empty ())
+ {
+ compLogMessage ("core", CompLogLevelWarn,
+ "Couldn't bind background pixmap 0x%x to "
+ "texture", (int) pixmap);
+ }
+ }
+ else
+ {
+ backgroundTextures.clear ();
+ }
+
+ if (backgroundTextures.empty () && backgroundImage)
+ {
+ CompSize size;
+ CompString fileName (backgroundImage);
+
+ backgroundTextures = GLTexture::readImageToTexture (fileName, size);
+ }
+
+ if (!backgroundTextures.empty ())
+ {
+ foreach (GLTexture *t, backgroundTextures)
+ if (t->target () == GL_TEXTURE_2D)
+ {
+ glBindTexture (t->target (), t->name ());
+ glTexParameteri (t->target (), GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri (t->target (), GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glBindTexture (t->target (), 0);
+ }
+ }
+}
+
+void
+GLScreen::setTexEnvMode (GLenum mode)
+{
+ if (priv->lighting)
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ else
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, mode);
+}
+
+void
+GLScreen::setLighting (bool lighting)
+{
+ if (priv->lighting != lighting)
+ {
+ if (!priv->optionGetLighting ())
+ lighting = false;
+
+ if (lighting)
+ {
+ glEnable (GL_COLOR_MATERIAL);
+ glEnable (GL_LIGHTING);
+ }
+ else
+ {
+ glDisable (GL_COLOR_MATERIAL);
+ glDisable (GL_LIGHTING);
+ }
+
+ priv->lighting = lighting;
+
+ setTexEnvMode (GL_REPLACE);
+ }
+}
+
+bool
+GLScreenInterface::glPaintOutput (const GLScreenPaintAttrib &sAttrib,
+ const GLMatrix &transform,
+ const CompRegion &region,
+ CompOutput *output,
+ unsigned int mask)
+ WRAPABLE_DEF (glPaintOutput, sAttrib, transform, region, output, mask)
+
+void
+GLScreenInterface::glPaintTransformedOutput (const GLScreenPaintAttrib &sAttrib,
+ const GLMatrix &transform,
+ const CompRegion &region,
+ CompOutput *output,
+ unsigned int mask)
+ WRAPABLE_DEF (glPaintTransformedOutput, sAttrib, transform, region,
+ output, mask)
+
+void
+GLScreenInterface::glApplyTransform (const GLScreenPaintAttrib &sAttrib,
+ CompOutput *output,
+ GLMatrix *transform)
+ WRAPABLE_DEF (glApplyTransform, sAttrib, output, transform)
+
+void
+GLScreenInterface::glEnableOutputClipping (const GLMatrix &transform,
+ const CompRegion &region,
+ CompOutput *output)
+ WRAPABLE_DEF (glEnableOutputClipping, transform, region, output)
+
+void
+GLScreenInterface::glDisableOutputClipping ()
+ WRAPABLE_DEF (glDisableOutputClipping)
+
+void
+GLScreen::updateBackground ()
+{
+ priv->backgroundTextures.clear ();
+
+ if (priv->backgroundLoaded)
+ {
+ priv->backgroundLoaded = false;
+ CompositeScreen::get (screen)->damageScreen ();
+ }
+}
+
+bool
+GLScreen::lighting ()
+{
+ return priv->lighting;
+}
+
+GLTexture::Filter
+GLScreen::filter (int filter)
+{
+ return priv->filter[filter];
+}
+
+void
+GLScreen::setFilter (int num, GLTexture::Filter filter)
+{
+ priv->filter[num] = filter;
+}
+
+GLFragment::Storage *
+GLScreen::fragmentStorage ()
+{
+ return &priv->fragmentStorage;
+}
+
+GLFBConfig*
+GLScreen::glxPixmapFBConfig (unsigned int depth)
+{
+ return &priv->glxPixmapFBConfigs[depth];
+}
+
+void
+GLScreen::clearOutput (CompOutput *output,
+ unsigned int mask)
+{
+ BoxPtr pBox = &output->region ()->extents;
+
+ if (pBox->x1 != 0 ||
+ pBox->y1 != 0 ||
+ pBox->x2 != (int) screen->width () ||
+ pBox->y2 != (int) screen->height ())
+ {
+ glPushAttrib (GL_SCISSOR_BIT);
+
+ glEnable (GL_SCISSOR_TEST);
+ glScissor (pBox->x1,
+ screen->height () - pBox->y2,
+ pBox->x2 - pBox->x1,
+ pBox->y2 - pBox->y1);
+ glClear (mask);
+
+ glPopAttrib ();
+ }
+ else
+ {
+ glClear (mask);
+ }
+}
+
+void
+GLScreen::setDefaultViewport ()
+{
+ priv->lastViewport.x = screen->outputDevs ()[0].x1 ();
+ priv->lastViewport.y = screen->height () -
+ screen->outputDevs ()[0].y2 ();
+ priv->lastViewport.width = screen->outputDevs ()[0].width ();
+ priv->lastViewport.height = screen->outputDevs ()[0].height ();
+
+ glViewport (priv->lastViewport.x,
+ priv->lastViewport.y,
+ priv->lastViewport.width,
+ priv->lastViewport.height);
+}
+
+void
+PrivateGLScreen::waitForVideoSync ()
+{
+ unsigned int sync;
+
+ if (!optionGetSyncToVblank ())
+ return;
+
+ if (GL::getVideoSync)
+ {
+ glFlush ();
+
+ (*GL::getVideoSync) (&sync);
+ (*GL::waitVideoSync) (2, (sync + 1) % 2, &sync);
+ }
+}
+
+void
+PrivateGLScreen::paintOutputs (CompOutput::ptrList &outputs,
+ unsigned int mask,
+ const CompRegion &region)
+{
+ XRectangle r;
+
+ if (clearBuffers)
+ {
+ if (mask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK)
+ glClear (GL_COLOR_BUFFER_BIT);
+ }
+
+ CompRegion tmpRegion (region);
+
+ foreach (CompOutput *output, outputs)
+ {
+ targetOutput = output;
+
+ r.x = output->x1 ();
+ r.y = screen->height () - output->y2 ();
+ r.width = output->width ();
+ r.height = output->height ();
+
+ if (lastViewport.x != r.x ||
+ lastViewport.y != r.y ||
+ lastViewport.width != r.width ||
+ lastViewport.height != r.height)
+ {
+ glViewport (r.x, r.y, r.width, r.height);
+ lastViewport = r;
+ }
+
+ if (mask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK)
+ {
+ GLMatrix identity;
+
+ gScreen->glPaintOutput (defaultScreenPaintAttrib,
+ identity,
+ CompRegion (*output), output,
+ PAINT_SCREEN_REGION_MASK |
+ PAINT_SCREEN_FULL_MASK);
+ }
+ else if (mask & COMPOSITE_SCREEN_DAMAGE_REGION_MASK)
+ {
+ GLMatrix identity;
+
+ outputRegion = tmpRegion & CompRegion (*output);
+
+ if (!gScreen->glPaintOutput (defaultScreenPaintAttrib,
+ identity,
+ outputRegion, output,
+ PAINT_SCREEN_REGION_MASK))
+ {
+ identity.reset ();
+
+ gScreen->glPaintOutput (defaultScreenPaintAttrib,
+ identity,
+ CompRegion (*output), output,
+ PAINT_SCREEN_FULL_MASK);
+
+ tmpRegion += *output;
+
+ }
+ }
+ }
+
+ targetOutput = &screen->outputDevs ()[0];
+
+ waitForVideoSync ();
+
+ if (mask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK)
+ {
+ glXSwapBuffers (screen->dpy (), cScreen->output ());
+ }
+ else
+ {
+ BoxPtr pBox;
+ int nBox, y;
+
+ pBox = const_cast <Region> (tmpRegion.handle ())->rects;
+ nBox = const_cast <Region> (tmpRegion.handle ())->numRects;
+
+ if (GL::copySubBuffer)
+ {
+ while (nBox--)
+ {
+ y = screen->height () - pBox->y2;
+
+ (*GL::copySubBuffer) (screen->dpy (), cScreen->output (),
+ pBox->x1, y,
+ pBox->x2 - pBox->x1,
+ pBox->y2 - pBox->y1);
+
+ pBox++;
+ }
+ }
+ else
+ {
+ glEnable (GL_SCISSOR_TEST);
+ glDrawBuffer (GL_FRONT);
+
+ while (nBox--)
+ {
+ y = screen->height () - pBox->y2;
+
+ glBitmap (0, 0, 0, 0,
+ pBox->x1 - rasterPos.x (),
+ y - rasterPos.y (),
+ NULL);
+
+ rasterPos = CompPoint (pBox->x1, y);
+
+ glScissor (pBox->x1, y,
+ pBox->x2 - pBox->x1,
+ pBox->y2 - pBox->y1);
+
+ glCopyPixels (pBox->x1, y,
+ pBox->x2 - pBox->x1,
+ pBox->y2 - pBox->y1,
+ GL_COLOR);
+
+ pBox++;
+ }
+
+ glDrawBuffer (GL_BACK);
+ glDisable (GL_SCISSOR_TEST);
+ glFlush ();
+ }
+ }
+}
+
+bool
+PrivateGLScreen::hasVSync ()
+{
+ return (GL::getVideoSync && optionGetSyncToVblank ());
+}
+
+void
+PrivateGLScreen::prepareDrawing ()
+{
+ if (pendingCommands)
+ {
+ glFinish ();
+ pendingCommands = false;
+ }
+}
+
+GLTexture::BindPixmapHandle
+GLScreen::registerBindPixmap (GLTexture::BindPixmapProc proc)
+{
+ priv->bindPixmap.push_back (proc);
+ if (!priv->hasCompositing &&
+ CompositeScreen::get (screen)->registerPaintHandler (priv))
+ priv->hasCompositing = true;
+ return priv->bindPixmap.size () - 1;
+}
+
+void
+GLScreen::unregisterBindPixmap (GLTexture::BindPixmapHandle hnd)
+{
+ bool hasBP = false;
+ priv->bindPixmap[hnd].clear ();
+ for (unsigned int i = 0; i < priv->bindPixmap.size (); i++)
+ if (!priv->bindPixmap[i].empty ())
+ hasBP = true;
+ if (!hasBP && priv->hasCompositing)
+ {
+ CompositeScreen::get (screen)->unregisterPaintHandler ();
+ priv->hasCompositing = false;
+ }
+}
+
+GLTexture *
+GLScreen::defaultIcon ()
+{
+ CompIcon *i = screen->defaultIcon ();
+ CompSize size;
+
+ if (!i)
+ return NULL;
+
+ if (!i->width () || !i->height ())
+ return NULL;
+
+ if (priv->defaultIcon.icon == i)
+ return priv->defaultIcon.textures[0];
+
+ priv->defaultIcon.textures =
+ GLTexture::imageBufferToTexture ((char *) i->data (), *i);
+
+ if (priv->defaultIcon.textures.size () == 1)
+ priv->defaultIcon.icon = i;
+ else
+ {
+ priv->defaultIcon.icon = NULL;
+ priv->defaultIcon.textures.clear ();
+ }
+
+ return priv->defaultIcon.textures[0];
+}
+
+void
+GLScreen::resetRasterPos ()
+{
+ glRasterPos2f (0, 0);
+ priv->rasterPos.setX (0);
+ priv->rasterPos.setY (0);
+}
+
+const float *
+GLScreen::projectionMatrix ()
+{
+ return priv->projection;
+}
diff --git a/plugins/opengl/src/texture.cpp b/plugins/opengl/src/texture.cpp
new file mode 100644
index 0000000..27ccddd
--- /dev/null
+++ b/plugins/opengl/src/texture.cpp
@@ -0,0 +1,615 @@
+/*
+ * Copyright © 2005 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 <compiz.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <core/core.h>
+#include <opengl/texture.h>
+#include <privatetexture.h>
+#include "privates.h"
+
+std::map<Damage, TfpTexture*> boundPixmapTex;
+
+static GLTexture::Matrix _identity_matrix = {
+ 1.0f, 0.0f,
+ 0.0f, 1.0f,
+ 0.0f, 0.0f
+};
+
+GLTexture::List::List () :
+ std::vector<GLTexture *> (0)
+{
+}
+
+GLTexture::List::List (unsigned int size) :
+ std::vector<GLTexture *> (size)
+{
+ for (unsigned int i = 0; i < size; i++)
+ at (i) = NULL;
+}
+
+GLTexture::List::List (const GLTexture::List &c) :
+ std::vector<GLTexture *> (c.size ())
+{
+ for (unsigned int i = 0; i < c.size (); i++)
+ {
+ at (i) = c[i];
+ GLTexture::incRef (c[i]);
+ }
+}
+
+GLTexture::List::~List ()
+{
+ foreach (GLTexture *t, *this)
+ if (t)
+ GLTexture::decRef (t);
+}
+
+GLTexture::List &
+GLTexture::List::operator= (const GLTexture::List &c)
+{
+ this->clear ();
+ resize (c.size ());
+ for (unsigned int i = 0; i < c.size (); i++)
+ {
+ at (i) = c[i];
+ GLTexture::incRef (c[i]);
+ }
+ return *this;
+}
+
+void
+GLTexture::List::clear ()
+{
+ foreach (GLTexture *t, *this)
+ if (t)
+ GLTexture::decRef (t);
+ std::vector <GLTexture *>::clear ();
+}
+
+GLTexture::GLTexture () :
+ CompRect (0, 0, 0, 0),
+ priv (new PrivateTexture (this))
+{
+}
+
+GLTexture::~GLTexture ()
+{
+ if (priv)
+ delete priv;
+}
+
+PrivateTexture::PrivateTexture (GLTexture *texture) :
+ texture (texture),
+ name (0),
+ target (GL_TEXTURE_2D),
+ filter (GL_NEAREST),
+ wrap (GL_CLAMP_TO_EDGE),
+ matrix (_identity_matrix),
+ mipmap (true),
+ mipmapSupport (false),
+ initial (true),
+ refCount (1)
+{
+ glGenTextures (1, &name);
+}
+
+PrivateTexture::~PrivateTexture ()
+{
+ if (name)
+ {
+ glDeleteTextures (1, &name);
+ }
+}
+
+GLuint
+GLTexture::name () const
+{
+ return priv->name;
+}
+
+GLenum
+GLTexture::target () const
+{
+ return priv->target;
+}
+
+const GLTexture::Matrix &
+GLTexture::matrix () const
+{
+ return priv->matrix;
+}
+
+bool
+GLTexture::mipmap () const
+{
+ return priv->mipmap & priv->mipmapSupport;
+}
+
+GLenum
+GLTexture::filter () const
+{
+ return priv->filter;
+}
+
+void
+GLTexture::enable (GLTexture::Filter filter)
+{
+ GLScreen *gs = GLScreen::get (screen);
+ glEnable (priv->target);
+ glBindTexture (priv->target, priv->name);
+
+ if (filter == Fast)
+ {
+ if (priv->filter != GL_NEAREST)
+ {
+ glTexParameteri (priv->target,
+ GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST);
+ glTexParameteri (priv->target,
+ GL_TEXTURE_MAG_FILTER,
+ GL_NEAREST);
+
+ priv->filter = GL_NEAREST;
+ }
+ }
+ else if (priv->filter != gs->textureFilter ())
+ {
+ if (gs->textureFilter () == GL_LINEAR_MIPMAP_LINEAR)
+ {
+ if (GL::textureNonPowerOfTwo && GL::fbo && priv->mipmap)
+ {
+ glTexParameteri (priv->target,
+ GL_TEXTURE_MIN_FILTER,
+ GL_LINEAR_MIPMAP_LINEAR);
+
+ if (priv->filter != GL_LINEAR)
+ glTexParameteri (priv->target,
+ GL_TEXTURE_MAG_FILTER,
+ GL_LINEAR);
+
+ priv->filter = GL_LINEAR_MIPMAP_LINEAR;
+ }
+ else if (priv->filter != GL_LINEAR)
+ {
+ glTexParameteri (priv->target,
+ GL_TEXTURE_MIN_FILTER,
+ GL_LINEAR);
+ glTexParameteri (priv->target,
+ GL_TEXTURE_MAG_FILTER,
+ GL_LINEAR);
+
+ priv->filter = GL_LINEAR;
+ }
+ }
+ else
+ {
+ glTexParameteri (priv->target,
+ GL_TEXTURE_MIN_FILTER,
+ gs->textureFilter ());
+ glTexParameteri (priv->target,
+ GL_TEXTURE_MAG_FILTER,
+ gs->textureFilter ());
+
+ priv->filter = gs->textureFilter ();
+ }
+ }
+
+ if (priv->filter == GL_LINEAR_MIPMAP_LINEAR)
+ {
+ if (priv->initial)
+ {
+ (*GL::generateMipmap) (priv->target);
+ priv->initial = false;
+ }
+ }
+}
+
+void
+GLTexture::disable ()
+{
+ glBindTexture (priv->target, 0);
+ glDisable (priv->target);
+}
+
+void
+GLTexture::setData (GLenum target, Matrix &m, bool mipmap)
+{
+ priv->target = target;
+ priv->matrix = m;
+ priv->mipmapSupport = mipmap;
+}
+
+void
+GLTexture::setMipmap (bool enable)
+{
+ priv->mipmap = enable;
+}
+
+void
+GLTexture::setFilter (GLenum filter)
+{
+ glBindTexture (priv->target, priv->name);
+
+ priv->filter = filter;
+
+ glTexParameteri (priv->target, GL_TEXTURE_MIN_FILTER, filter);
+ glTexParameteri (priv->target, GL_TEXTURE_MAG_FILTER, filter);
+
+ glBindTexture (priv->target, 0);
+}
+
+void
+GLTexture::setWrap (GLenum wrap)
+{
+ glBindTexture (priv->target, priv->name);
+
+ priv->wrap = GL_CLAMP_TO_EDGE;
+
+ glTexParameteri (priv->target, GL_TEXTURE_WRAP_S, wrap);
+ glTexParameteri (priv->target, GL_TEXTURE_WRAP_T, wrap);
+
+ glBindTexture (priv->target, 0);
+}
+
+GLTexture::List
+PrivateTexture::loadImageData (const char *image,
+ unsigned int width,
+ unsigned int height,
+ GLenum format,
+ GLenum type)
+{
+#warning Add support for multiple textures
+ if ((int) width > GL::maxTextureSize || (int) height > GL::maxTextureSize)
+ return GLTexture::List ();
+
+ GLTexture::List rv (1);
+ GLTexture *t = new GLTexture ();
+ rv[0] = t;
+
+ GLTexture::Matrix matrix = _identity_matrix;
+ CompOption *opt;
+ GLint internalFormat;
+ GLenum target;
+ bool mipmap;
+
+
+ if (GL::textureNonPowerOfTwo ||
+ (POWER_OF_TWO (width) && POWER_OF_TWO (height)))
+ {
+ target = GL_TEXTURE_2D;
+ matrix.xx = 1.0f / width;
+ matrix.yy = 1.0f / height;
+ matrix.y0 = 0.0f;
+ mipmap = true;
+ }
+ else
+ {
+ target = GL_TEXTURE_RECTANGLE_NV;
+ matrix.xx = 1.0f;
+ matrix.yy = 1.0f;
+ matrix.y0 = 0.0f;
+ mipmap = false;
+ }
+
+ t->setData (target, matrix, mipmap);
+ t->setGeometry (0, 0, width, height);
+
+ glBindTexture (target, t->name ());
+
+ opt = GLScreen::get (screen)->getOption ("texture_compression");
+ if (opt->value ().b () && GL::textureCompression)
+ internalFormat = GL_COMPRESSED_RGBA_ARB;
+ else
+ internalFormat = GL_RGBA;
+
+ glTexImage2D (target, 0, internalFormat, width, height, 0,
+ format, type, image);
+
+ t->setFilter (GL_NEAREST);
+ t->setWrap (GL_CLAMP_TO_EDGE);
+
+ return rv;
+}
+
+GLTexture::List
+GLTexture::imageBufferToTexture (const char *image,
+ CompSize size)
+{
+#if IMAGE_BYTE_ORDER == MSBFirst
+ return PrivateTexture::loadImageData (image, size.width (), size.height (),
+ GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV);
+#else
+ return PrivateTexture::loadImageData (image, size.width (), size.height (),
+ GL_BGRA, GL_UNSIGNED_BYTE);
+#endif
+}
+
+GLTexture::List
+GLTexture::imageDataToTexture (const char *image,
+ CompSize size,
+ GLenum format,
+ GLenum type)
+{
+ return PrivateTexture::loadImageData (image, size.width (), size.height (),
+ format, type);
+}
+
+
+GLTexture::List
+GLTexture::readImageToTexture (CompString &imageFileName,
+ CompSize &size)
+{
+ void *image = NULL;
+
+ if (!screen->readImageFromFile (imageFileName, size, image) || !image)
+ return GLTexture::List ();
+
+ GLTexture::List rv =
+ GLTexture::imageBufferToTexture ((char *)image, size);
+
+ free (image);
+
+ return rv;
+}
+
+void
+GLTexture::decRef (GLTexture *tex)
+{
+ tex->priv->refCount--;
+ if (tex->priv->refCount <= 0)
+ delete tex;
+}
+
+void
+GLTexture::incRef (GLTexture *tex)
+{
+ tex->priv->refCount++;
+}
+
+GLTexture::List
+GLTexture::bindPixmapToTexture (Pixmap pixmap,
+ int width,
+ int height,
+ int depth)
+{
+ GLTexture::List rv;
+
+ foreach (BindPixmapProc &proc, GLScreen::get (screen)->priv->bindPixmap)
+ {
+ if (!proc.empty ())
+ rv = proc (pixmap, width, height, depth);
+ if (rv.size ())
+ return rv;
+ }
+ return GLTexture::List ();
+}
+
+TfpTexture::TfpTexture () :
+ pixmap (0),
+ damaged (true),
+ damage (None),
+ updateMipMap (true)
+{
+}
+
+TfpTexture::~TfpTexture ()
+{
+ if (pixmap)
+ {
+ glEnable (target ());
+
+ glBindTexture (target (), name ());
+
+ (*GL::releaseTexImage) (screen->dpy (), pixmap, GLX_FRONT_LEFT_EXT);
+
+ glBindTexture (target (), 0);
+ glDisable (target ());
+
+ GL::destroyPixmap (screen->dpy (), pixmap);
+
+ boundPixmapTex.erase (damage);
+ XDamageDestroy (screen->dpy (), damage);
+ }
+}
+
+GLTexture::List
+TfpTexture::bindPixmapToTexture (Pixmap pixmap,
+ int width,
+ int height,
+ int depth)
+{
+ if ((int) width > GL::maxTextureSize || (int) height > GL::maxTextureSize ||
+ !GL::textureFromPixmap)
+ return GLTexture::List ();
+
+ GLTexture::List rv (1);
+ TfpTexture *tex = NULL;
+ unsigned int target = 0;
+ GLenum texTarget = GL_TEXTURE_2D;
+ GLXPixmap glxPixmap = None;
+ GLTexture::Matrix matrix = _identity_matrix;
+ bool mipmap = false;
+ GLFBConfig *config =
+ GLScreen::get (screen)->glxPixmapFBConfig (depth);
+ int attribs[7], i = 0;
+
+ if (!config->fbConfig)
+ {
+ compLogMessage ("core", CompLogLevelWarn,
+ "No GLXFBConfig for depth %d",
+ depth);
+
+ return GLTexture::List ();
+ }
+
+ attribs[i++] = GLX_TEXTURE_FORMAT_EXT;
+ attribs[i++] = config->textureFormat;
+ attribs[i++] = GLX_MIPMAP_TEXTURE_EXT;
+ attribs[i++] = config->mipmap;
+
+ /* If no texture target is specified in the fbconfig, or only the
+ TEXTURE_2D target is specified and GL_texture_non_power_of_two
+ is not supported, then allow the server to choose the texture target. */
+ if (config->textureTargets & GLX_TEXTURE_2D_BIT_EXT &&
+ (GL::textureNonPowerOfTwo ||
+ (POWER_OF_TWO (width) && POWER_OF_TWO (height))))
+ target = GLX_TEXTURE_2D_EXT;
+ else if (config->textureTargets & GLX_TEXTURE_RECTANGLE_BIT_EXT)
+ target = GLX_TEXTURE_RECTANGLE_EXT;
+
+ /* Workaround for broken texture from pixmap implementations,
+ that don't advertise any texture target in the fbconfig. */
+ if (!target)
+ {
+ if (!(config->textureTargets & GLX_TEXTURE_2D_BIT_EXT))
+ target = GLX_TEXTURE_RECTANGLE_EXT;
+ else if (!(config->textureTargets & GLX_TEXTURE_RECTANGLE_BIT_EXT))
+ target = GLX_TEXTURE_2D_EXT;
+ }
+
+ if (target)
+ {
+ attribs[i++] = GLX_TEXTURE_TARGET_EXT;
+ attribs[i++] = target;
+ }
+
+ attribs[i++] = None;
+
+ glxPixmap = (*GL::createPixmap) (screen->dpy (), config->fbConfig,
+ pixmap, attribs);
+
+ if (!glxPixmap)
+ {
+ compLogMessage ("core", CompLogLevelWarn,
+ "glXCreatePixmap failed");
+
+ return GLTexture::List ();
+ }
+
+ if (!target)
+ (*GL::queryDrawable) (screen->dpy (), glxPixmap,
+ GLX_TEXTURE_TARGET_EXT, &target);
+
+ switch (target) {
+ case GLX_TEXTURE_2D_EXT:
+ texTarget = GL_TEXTURE_2D;
+
+ matrix.xx = 1.0f / width;
+ if (config->yInverted)
+ {
+ matrix.yy = 1.0f / height;
+ matrix.y0 = 0.0f;
+ }
+ else
+ {
+ matrix.yy = -1.0f / height;
+ matrix.y0 = 1.0f;
+ }
+ mipmap = config->mipmap;
+ break;
+ case GLX_TEXTURE_RECTANGLE_EXT:
+ texTarget = GL_TEXTURE_RECTANGLE_ARB;
+
+ matrix.xx = 1.0f;
+ if (config->yInverted)
+ {
+ matrix.yy = 1.0f;
+ matrix.y0 = 0;
+ }
+ else
+ {
+ matrix.yy = -1.0f;
+ matrix.y0 = height;
+ }
+ mipmap = false;
+ break;
+ default:
+ compLogMessage ("core", CompLogLevelWarn,
+ "pixmap 0x%x can't be bound to texture",
+ (int) pixmap);
+
+ GL::destroyPixmap (screen->dpy (), glxPixmap);
+ glxPixmap = None;
+
+ return GLTexture::List ();
+ }
+
+ tex = new TfpTexture ();
+ tex->setData (texTarget, matrix, mipmap);
+ tex->setGeometry (0, 0, width, height);
+ tex->pixmap = glxPixmap;
+
+ rv[0] = tex;
+
+ glBindTexture (texTarget, tex->name ());
+
+
+ (*GL::bindTexImage) (screen->dpy (), glxPixmap, GLX_FRONT_LEFT_EXT, NULL);
+
+ tex->setFilter (GL_NEAREST);
+ tex->setWrap (GL_CLAMP_TO_EDGE);
+
+ glBindTexture (texTarget, 0);
+
+ tex->damage = XDamageCreate (screen->dpy (), pixmap,
+ XDamageReportRawRectangles);
+ boundPixmapTex[tex->damage] = tex;
+
+ return rv;
+}
+
+void
+TfpTexture::enable (GLTexture::Filter filter)
+{
+ glEnable (target ());
+ glBindTexture (target (), name ());
+
+ if (damaged && pixmap)
+ {
+ (*GL::releaseTexImage) (screen->dpy (), pixmap, GLX_FRONT_LEFT_EXT);
+ (*GL::bindTexImage) (screen->dpy (), pixmap, GLX_FRONT_LEFT_EXT, NULL);
+ }
+
+ GLTexture::enable (filter);
+
+ if (damaged)
+ updateMipMap = true;
+
+ if (this->filter () == GL_LINEAR_MIPMAP_LINEAR && updateMipMap)
+ {
+ (*GL::generateMipmap) (target ());
+ updateMipMap = false;
+ }
+ damaged = false;
+}
diff --git a/plugins/opengl/src/vector.cpp b/plugins/opengl/src/vector.cpp
new file mode 100644
index 0000000..28102aa
--- /dev/null
+++ b/plugins/opengl/src/vector.cpp
@@ -0,0 +1,276 @@
+/*
+ * Copyright © 2008 Danny Baumann
+ *
+ * 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
+ * Dennis Kasprzyk not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Dennis Kasprzyk makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * DENNIS KASPRZYK DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL DENNIS KASPRZYK 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.
+ *
+ * Authors: Danny Baumann <maniac@compiz-fusion.org>
+ */
+
+/*
+ * Copyright (C) 1999-2005 Brian Paul All Rights Reserved.
+ *
+ * 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 or substantial portions of the Software.
+ *
+ * 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
+ * BRIAN PAUL 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.
+ *
+ * From Mesa 3-D graphics library.
+ */
+
+#include <string.h>
+#include <math.h>
+#include <opengl/vector.h>
+
+GLVector::GLVector ()
+{
+ memset (v, 0, sizeof (v));
+}
+
+GLVector::GLVector (float x,
+ float y,
+ float z,
+ float w)
+{
+ v[0] = x;
+ v[1] = y;
+ v[2] = z;
+ v[3] = w;
+}
+
+float&
+GLVector::operator[] (int item)
+{
+ return v[item];
+}
+
+float&
+GLVector::operator[] (VectorCoordsEnum coord)
+{
+ int item = (int) coord;
+ return v[item];
+}
+
+const float
+GLVector::operator[] (int item) const
+{
+ return v[item];
+}
+
+const float
+GLVector::operator[] (VectorCoordsEnum coord) const
+{
+ int item = (int) coord;
+ return v[item];
+}
+
+GLVector&
+GLVector::operator+= (const GLVector& rhs)
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ v[i] += rhs[i];
+
+ return *this;
+}
+
+GLVector
+operator+ (const GLVector& lhs,
+ const GLVector& rhs)
+{
+ GLVector result;
+ int i;
+
+ for (i = 0; i < 4; i++)
+ result[i] = lhs[i] + rhs[i];
+
+ return result;
+}
+
+GLVector&
+GLVector::operator-= (const GLVector& rhs)
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ v[i] -= rhs[i];
+
+ return *this;
+}
+
+GLVector
+operator- (const GLVector& lhs,
+ const GLVector& rhs)
+{
+ GLVector result;
+ int i;
+
+ for (i = 0; i < 4; i++)
+ result[i] = lhs[i] - rhs[i];
+
+ return result;
+}
+
+GLVector
+operator- (const GLVector& vector)
+{
+ GLVector result;
+ int i;
+
+ for (i = 0; i < 4; i++)
+ result[i] = -vector[i];
+
+ return result;
+}
+
+GLVector&
+GLVector::operator*= (const float k)
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ v[i] *= k;
+
+ return *this;
+}
+
+float
+operator* (const GLVector& lhs,
+ const GLVector& rhs)
+{
+ float result = 0;
+ int i;
+
+ for (i = 0; i < 4; i++)
+ result += lhs[i] * rhs[i];
+
+ return result;
+}
+
+GLVector
+operator* (const float k,
+ const GLVector& vector)
+{
+ GLVector result;
+ int i;
+
+ for (i = 0; i < 4; i++)
+ result[i] = k * vector[i];
+
+ return result;
+}
+
+GLVector
+operator* (const GLVector& vector,
+ const float k)
+{
+ return k * vector;
+}
+
+GLVector&
+GLVector::operator/= (const float k)
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ v[i] /= k;
+
+ return *this;
+}
+
+GLVector
+operator/ (const GLVector& vector,
+ const float k)
+{
+ GLVector result;
+ int i;
+
+ for (i = 0; i < 4; i++)
+ result[i] = vector[i] / k;
+
+ return result;
+}
+
+GLVector&
+GLVector::operator^= (const GLVector& vector)
+{
+ *this = *this ^ vector;
+ return *this;
+}
+
+GLVector
+operator^ (const GLVector& lhs,
+ const GLVector& rhs)
+{
+ GLVector result;
+
+ result[0] = lhs[1] * rhs[2] - lhs[2] * rhs[1];
+ result[1] = lhs[2] * rhs[0] - lhs[0] * rhs[2];
+ result[2] = lhs[0] * rhs[1] - lhs[1] * rhs[0];
+ result[3] = 0.0f;
+
+ return result;
+}
+
+float
+GLVector::norm ()
+{
+ if (v[3] != 0.0)
+ return 1.0;
+ return sqrt ((v[0] * v[0]) + (v[1] * v[1]) + (v[2] * v[2]));
+}
+
+GLVector &
+GLVector::normalize ()
+{
+ float normal = norm ();
+
+ /* Vector is not homogenous */
+ if (normal == 1.0)
+ return *this;
+
+ for (unsigned int i = 0; i < 3; i++)
+ v[i] /= normal;
+ return *this;
+}
+
+GLVector &
+GLVector::homogenize ()
+{
+ if (v[3] ==0)
+ return *this;
+
+ for (unsigned int i = 0; i < 4; i++)
+ v[i] /= v[3];
+
+ return *this;
+}
diff --git a/plugins/opengl/src/window.cpp b/plugins/opengl/src/window.cpp
new file mode 100644
index 0000000..80d2bda
--- /dev/null
+++ b/plugins/opengl/src/window.cpp
@@ -0,0 +1,363 @@
+/*
+ * Copyright © 2008 Dennis Kasprzyk
+ * Copyright © 2007 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
+ * Dennis Kasprzyk not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Dennis Kasprzyk makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * DENNIS KASPRZYK DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL DENNIS KASPRZYK 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.
+ *
+ * Authors: Dennis Kasprzyk <onestone@compiz-fusion.org>
+ * David Reveman <davidr@novell.com>
+ */
+
+#include "privates.h"
+
+GLWindow::GLWindow (CompWindow *w) :
+ PluginClassHandler<GLWindow, CompWindow, COMPIZ_OPENGL_ABI> (w),
+ priv (new PrivateGLWindow (w, this))
+{
+ CompositeWindow *cw = CompositeWindow::get (w);
+
+ priv->paint.opacity = cw->opacity ();
+ priv->paint.brightness = cw->brightness ();
+ priv->paint.saturation = cw->saturation ();
+
+ priv->lastPaint = priv->paint;
+
+}
+
+GLWindow::~GLWindow ()
+{
+ delete priv;
+}
+
+PrivateGLWindow::PrivateGLWindow (CompWindow *w,
+ GLWindow *gw) :
+ window (w),
+ gWindow (gw),
+ cWindow (CompositeWindow::get (w)),
+ gScreen (GLScreen::get (screen)),
+ textures (),
+ regions (),
+ updateReg (true),
+ clip (),
+ bindFailed (false),
+ geometry (),
+ icons ()
+{
+ paint.xScale = 1.0f;
+ paint.yScale = 1.0f;
+ paint.xTranslate = 0.0f;
+ paint.yTranslate = 0.0f;
+
+ WindowInterface::setHandler (w);
+ CompositeWindowInterface::setHandler (cWindow);
+}
+
+PrivateGLWindow::~PrivateGLWindow ()
+{
+}
+
+void
+PrivateGLWindow::setWindowMatrix ()
+{
+ CompRect input (window->inputRect ());
+
+ if (textures.size () != matrices.size ())
+ matrices.resize (textures.size ());
+
+ for (unsigned int i = 0; i < textures.size (); i++)
+ {
+ matrices[i] = textures[i]->matrix ();
+ matrices[i].x0 -= (input.x () * matrices[i].xx);
+ matrices[i].y0 -= (input.y () * matrices[i].yy);
+ }
+}
+
+bool
+GLWindow::bind ()
+{
+ CompRect input (priv->window->inputRect ());
+
+ if (!priv->cWindow->pixmap () && !priv->cWindow->bind ())
+ return false;
+
+ priv->textures =
+ GLTexture::bindPixmapToTexture (priv->cWindow->pixmap (),
+ input.width (), input.height (),
+ priv->window->depth ());
+ if (priv->textures.empty ())
+ {
+ compLogMessage ("opengl", CompLogLevelInfo,
+ "Couldn't bind redirected window 0x%x to "
+ "texture\n", (int) priv->window->id ());
+ }
+
+ priv->setWindowMatrix ();
+ priv->updateReg = true;
+
+ return true;
+}
+
+void
+GLWindow::release ()
+{
+ priv->textures.clear ();
+
+ if (priv->cWindow->pixmap ())
+ {
+ priv->cWindow->release ();
+ }
+}
+
+bool
+GLWindowInterface::glPaint (const GLWindowPaintAttrib &attrib,
+ const GLMatrix &transform,
+ const CompRegion &region,
+ unsigned int mask)
+ WRAPABLE_DEF (glPaint, attrib, transform, region, mask)
+
+bool
+GLWindowInterface::glDraw (const GLMatrix &transform,
+ GLFragment::Attrib &fragment,
+ const CompRegion &region,
+ unsigned int mask)
+ WRAPABLE_DEF (glDraw, transform, fragment, region, mask)
+
+void
+GLWindowInterface::glAddGeometry (const GLTexture::MatrixList &matrix,
+ const CompRegion &region,
+ const CompRegion &clip,
+ unsigned int maxGridWidth,
+ unsigned int maxGridHeight)
+ WRAPABLE_DEF (glAddGeometry, matrix, region, clip,
+ maxGridWidth, maxGridHeight)
+
+void
+GLWindowInterface::glDrawTexture (GLTexture *texture,
+ GLFragment::Attrib &fragment,
+ unsigned int mask)
+ WRAPABLE_DEF (glDrawTexture, texture, fragment, mask)
+
+void
+GLWindowInterface::glDrawGeometry ()
+ WRAPABLE_DEF (glDrawGeometry)
+
+const CompRegion &
+GLWindow::clip () const
+{
+ return priv->clip;
+}
+
+GLWindowPaintAttrib &
+GLWindow::paintAttrib ()
+{
+ return priv->paint;
+}
+
+GLWindowPaintAttrib &
+GLWindow::lastPaintAttrib ()
+{
+ return priv->lastPaint;
+}
+
+
+void
+PrivateGLWindow::resizeNotify (int dx, int dy, int dwidth, int dheight)
+{
+ window->resizeNotify (dx, dy, dwidth, dheight);
+ setWindowMatrix ();
+ updateReg = true;
+ gWindow->release ();
+}
+
+void
+PrivateGLWindow::moveNotify (int dx, int dy, bool now)
+{
+ window->moveNotify (dx, dy, now);
+ updateReg = true;
+ setWindowMatrix ();
+}
+
+void
+PrivateGLWindow::windowNotify (CompWindowNotify n)
+{
+ switch (n)
+ {
+ case CompWindowNotifyUnmap:
+ case CompWindowNotifyReparent:
+ case CompWindowNotifyUnreparent:
+ case CompWindowNotifyFrameUpdate:
+ gWindow->release ();
+ break;
+ default:
+ break;
+ }
+
+ window->windowNotify (n);
+}
+
+void
+GLWindow::updatePaintAttribs ()
+{
+ CompositeWindow *cw = CompositeWindow::get (priv->window);
+
+ priv->paint.opacity = cw->opacity ();
+ priv->paint.brightness = cw->brightness ();
+ priv->paint.saturation = cw->saturation ();
+}
+
+GLWindow::Geometry &
+GLWindow::geometry ()
+{
+ return priv->geometry;
+}
+
+GLWindow::Geometry::Geometry () :
+ vertices (NULL),
+ vertexSize (0),
+ vertexStride (0),
+ indices (NULL),
+ indexSize (0),
+ vCount (0),
+ texUnits (0),
+ texCoordSize (0),
+ indexCount (0)
+{
+}
+
+GLWindow::Geometry::~Geometry ()
+{
+ if (vertices)
+ free (vertices);
+
+ if (indices)
+ free (indices);
+}
+
+void
+GLWindow::Geometry::reset ()
+{
+ vCount = indexCount = 0;
+}
+
+bool
+GLWindow::Geometry::moreVertices (int newSize)
+{
+ if (newSize > vertexSize)
+ {
+ GLfloat *nVertices;
+
+ nVertices = (GLfloat *)
+ realloc (vertices, sizeof (GLfloat) * newSize);
+ if (!nVertices)
+ return false;
+
+ vertices = nVertices;
+ vertexSize = newSize;
+ }
+
+ return true;
+}
+
+bool
+GLWindow::Geometry::moreIndices (int newSize)
+{
+ if (newSize > indexSize)
+ {
+ GLushort *nIndices;
+
+ nIndices = (GLushort *)
+ realloc (indices, sizeof (GLushort) * newSize);
+ if (!nIndices)
+ return false;
+
+ indices = nIndices;
+ indexSize = newSize;
+ }
+
+ return true;
+}
+
+const GLTexture::List &
+GLWindow::textures () const
+{
+ return priv->textures;
+}
+
+const GLTexture::MatrixList &
+GLWindow::matrices () const
+{
+ return priv->matrices;
+}
+
+GLTexture *
+GLWindow::getIcon (int width, int height)
+{
+ GLIcon icon;
+ CompIcon *i = priv->window->getIcon (width, height);
+
+ if (!i)
+ return NULL;
+
+ if (!i->width () || !i->height ())
+ return NULL;
+
+ foreach (GLIcon &icon, priv->icons)
+ if (icon.icon == i)
+ return icon.textures[0];
+
+ icon.icon = i;
+ icon.textures = GLTexture::imageBufferToTexture ((char *) i->data (), *i);
+
+ if (icon.textures.size () > 1 || icon.textures.size () == 0)
+ return NULL;
+
+ priv->icons.push_back (icon);
+
+ return icon.textures[0];
+}
+
+void
+PrivateGLWindow::updateFrameRegion (CompRegion &region)
+{
+ window->updateFrameRegion (region);
+ updateReg = true;
+}
+
+void
+PrivateGLWindow::updateWindowRegions ()
+{
+ CompRect input (window->inputRect ());
+
+ if (regions.size () != textures.size ())
+ regions.resize (textures.size ());
+ for (unsigned int i = 0; i < textures.size (); i++)
+ {
+ regions[i] = CompRegion (*textures[i]);
+ regions[i].translate (input.x (), input.y ());
+ regions[i] &= window->region ();
+ }
+ updateReg = false;
+}
+
+unsigned int
+GLWindow::lastMask () const
+{
+ return priv->lastMask;
+}