summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CompizFBO/CMakeLists.txt7
-rw-r--r--CompizFBO/fbo.xml.in71
-rw-r--r--CompizFBO/src/fbo.cpp940
-rw-r--r--CompizFBO/src/fbo.h205
4 files changed, 1223 insertions, 0 deletions
diff --git a/CompizFBO/CMakeLists.txt b/CompizFBO/CMakeLists.txt
new file mode 100644
index 0000000..451d186
--- /dev/null
+++ b/CompizFBO/CMakeLists.txt
@@ -0,0 +1,7 @@
+find_package (Compiz REQUIRED)
+include (FindOpenGL)
+include (CompizPlugin)
+
+if (OPENGL_GLU_FOUND)
+ compiz_plugin(fbo PLUGINDEPS composite opengl mousepoll LIBRARIES ${OPENGL_glu_LIBRARY} INCDIRS ${OPENGL_INCLUDE_DIR})
+endif (OPENGL_GLU_FOUND) \ No newline at end of file
diff --git a/CompizFBO/fbo.xml.in b/CompizFBO/fbo.xml.in
new file mode 100644
index 0000000..3222605
--- /dev/null
+++ b/CompizFBO/fbo.xml.in
@@ -0,0 +1,71 @@
+<compiz>
+ <plugin name="fbo" useBcop="true">
+ <_short>FBO</_short>
+ <_long>Renders screen content to OpenGL frame buffer object and uses that as texture for a screen size quad. GLSL vertex and fragment shader can be loaded to change its appearance</_long>
+ <category>Effects</category>
+ <deps>
+ <relation type="before">
+ <plugin>blur</plugin>
+ <plugin>video</plugin>
+ </relation>
+ <requirement>
+ <plugin>composite</plugin>
+ <plugin>opengl</plugin>
+ <plugin>mousepoll</plugin>
+ <feature>imageext:png</feature>
+ </requirement>
+ </deps>
+ <options>
+ <option name="toggle_fbo_key" type="key">
+ <_short>Toggle FBO</_short>
+ <_long>Toggle Offscreen-Rendering via FBO</_long>
+ <default>&lt;Shift&gt;F9</default>
+ </option>
+ <option name="reload_shader_key" type="key">
+ <_short>Reload Shader</_short>
+ <_long>Reloads Shader from HDD</_long>
+ <default>&lt;Shift&gt;F8</default>
+ </option>
+ <option name="toggle_shader_key" type="key">
+ <_short>Toggle Shader</_short>
+ <_long>Switches Shader on and off</_long>
+ <default>&lt;Shift&gt;F7</default>
+ </option>
+ <option name="file_dist_proj1" type="string">
+ <_short>Distortion map for projector 1</_short>
+ <_long>The distortion map for the fragment shader for projector 1 (vertical projection)</_long>
+ <hints>file;image;</hints>
+ </option>
+ <option name="file_dist_proj2" type="string">
+ <_short>Distortion map for projector 2</_short>
+ <_long>The distortion map for the fragment shader for projector 2 (horizontal projection)</_long>
+ <hints>file;image;</hints>
+ </option>
+ <option name="file_blend" type="string">
+ <_short>Blend map</_short>
+ <_long>The blend map for the fragment shader</_long>
+ <hints>file;image;</hints>
+ </option>
+ <option name="file_vert" type="string">
+ <_short>Vertex Shader</_short>
+ <_long>The GLSL Vertex Shader File</_long>
+ <hints>file;text;</hints>
+ </option>
+ <option name="file_frag" type="string">
+ <_short>Fragment Shader</_short>
+ <_long>The GLSL Fragment Shader File</_long>
+ <hints>file;text;</hints>
+ </option>
+ <option type="bool" name="transform_cursor">
+ <_short>Transform the mouse pointer</_short>
+ <_long>Enable this to get a transformed mouse pointer</_long>
+ <default>true</default>
+ </option>
+ <option type="bool" name="hide_original_mouse">
+ <_short>Hide original mouse pointer</_short>
+ <_long>Hides the original mouse pointer when transformed</_long>
+ <default>true</default>
+ </option>
+ </options>
+ </plugin>
+</compiz>
diff --git a/CompizFBO/src/fbo.cpp b/CompizFBO/src/fbo.cpp
new file mode 100644
index 0000000..203e13c
--- /dev/null
+++ b/CompizFBO/src/fbo.cpp
@@ -0,0 +1,940 @@
+#include "fbo.h"
+
+#include <GL/glext.h>
+#include <GL/glx.h>
+
+COMPIZ_PLUGIN_20090315 (fbo, FboPluginVTable);
+
+PFNGLCREATEPROGRAMPROC m_glCreateProgram = NULL;
+PFNGLUSEPROGRAMPROC m_glUseProgram = NULL;
+PFNGLCREATESHADERPROC m_glCreateShader = NULL;
+PFNGLSHADERSOURCEPROC m_glShaderSource = NULL;
+PFNGLCOMPILESHADERPROC m_glCompileShader = NULL;
+PFNGLATTACHSHADERPROC m_glAttachShader = NULL;
+PFNGLLINKPROGRAMPROC m_glLinkProgram = NULL;
+PFNGLGETUNIFORMLOCATIONPROC m_glGetUniformLocation = NULL;
+PFNGLUNIFORM1IPROC m_glUniform1i = NULL;
+PFNGLGETSHADERIVPROC m_glGetShaderiv = NULL;
+PFNGLGETSHADERINFOLOGPROC m_glGetShaderInfoLog = NULL;
+PFNGLGETPROGRAMINFOLOGPROC m_glGetProgramInfoLog = NULL;
+PFNGLGETPROGRAMIVPROC m_glGetProgramiv = NULL;
+PFNGLDELETESHADERPROC m_glDeleteShader = NULL;
+PFNGLDELETEPROGRAMPROC m_glDeleteProgram = NULL;
+
+bool
+FboScreen::queryForShader()
+{
+ m_glCreateProgram = (PFNGLCREATEPROGRAMPROC) gScreen->getProcAddress ("glCreateProgram");
+ m_glUseProgram = (PFNGLUSEPROGRAMPROC) gScreen->getProcAddress ("glUseProgram");
+ m_glCreateShader = (PFNGLCREATESHADERPROC) gScreen->getProcAddress ("glCreateShader");
+ m_glShaderSource = (PFNGLSHADERSOURCEPROC) gScreen->getProcAddress ("glShaderSource");
+ m_glCompileShader = (PFNGLCOMPILESHADERPROC) gScreen->getProcAddress ("glCompileShader");
+ m_glAttachShader = (PFNGLATTACHSHADERPROC) gScreen->getProcAddress ("glAttachShader");
+ m_glLinkProgram = (PFNGLLINKPROGRAMPROC) gScreen->getProcAddress ("glLinkProgram");
+ m_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) gScreen->getProcAddress ("glGetUniformLocation");
+ m_glUniform1i = (PFNGLUNIFORM1IPROC) gScreen->getProcAddress ("glUniform1i");
+ m_glGetShaderiv = (PFNGLGETSHADERIVPROC) gScreen->getProcAddress ("glGetShaderiv");
+ m_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) gScreen->getProcAddress ("glGetShaderInfoLog");
+ m_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) gScreen->getProcAddress ("glGetProgramInfoLog");
+ m_glGetProgramiv = (PFNGLGETPROGRAMIVPROC) gScreen->getProcAddress ("glGetProgramiv");
+ m_glDeleteShader = (PFNGLDELETESHADERPROC) gScreen->getProcAddress ("glDeleteShader");
+ m_glDeleteProgram = (PFNGLDELETEPROGRAMPROC) gScreen->getProcAddress ("glDeleteProgram");
+
+ if (m_glCreateShader == NULL)
+ std::cout << "glCreateShader not supported" << std::endl;
+ if (m_glUseProgram == NULL)
+ std::cout << "glUseProgram not supported" << std::endl;
+ if (m_glShaderSource == NULL)
+ std::cout << "glShaderSource not supported" << std::endl;
+ if (m_glCompileShader == NULL)
+ std::cout << "glCompileShader not supported" << std::endl;
+ if (m_glGetShaderiv == NULL)
+ std::cout << "glGetShaderiv not supported" << std::endl;
+ if (m_glGetShaderInfoLog == NULL)
+ std::cout << "glGetShaderInfoLog not supported" << std::endl;
+ if (m_glDeleteShader == NULL)
+ std::cout << "glDeleteShader not supported" << std::endl;
+ if (m_glDeleteProgram == NULL)
+ std::cout << "glDeleteProgram not supported" << std::endl;
+ if (m_glCreateProgram == NULL)
+ std::cout << "glCreateProgram not supported" << std::endl;
+ if (m_glAttachShader == NULL)
+ std::cout << "glAttachShader not supported" << std::endl;
+ if (m_glLinkProgram == NULL)
+ std::cout << "glLinkProgram not supported" << std::endl;
+ if (m_glGetProgramiv == NULL)
+ std::cout << "m_glGetProgramiv not supported" << std::endl;
+ if (m_glGetProgramInfoLog == NULL)
+ std::cout << "glGetProgramInfoLog not supported" << std::endl;
+ if (m_glGetUniformLocation == NULL)
+ std::cout << "glGetUniformLocation not supported" << std::endl;
+ if (m_glUniform1i == NULL)
+ std::cout << "glUniform1i not supported" << std::endl;
+
+ if (!(m_glUseProgram &&
+ m_glCreateShader &&
+ m_glShaderSource &&
+ m_glCompileShader &&
+ m_glGetShaderiv &&
+ m_glGetShaderInfoLog &&
+ m_glDeleteShader &&
+ m_glDeleteProgram &&
+ m_glCreateProgram &&
+ m_glAttachShader &&
+ m_glLinkProgram &&
+ m_glGetProgramiv &&
+ m_glGetProgramInfoLog &&
+ m_glGetUniformLocation &&
+ m_glUniform1i))
+ {
+ return false;
+ }
+ return true;
+}
+
+void
+FboScreen::allocTexture (int index, char* data)
+{
+ glGenTextures (1, &texture[index]);
+ glBindTexture (target, texture[index]);
+
+ glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri (target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexImage2D (target, 0, GL_RGBA, width, height, 0, GL_BGRA,
+#if IMAGE_BYTE_ORDER == MSBFirst
+ GL_UNSIGNED_INT_8_8_8_8_REV,
+#else
+ GL_UNSIGNED_BYTE,
+#endif
+ (data == NULL ? 0 : data));
+
+ glBindTexture (target, 0);
+}
+
+void
+FboScreen::loadMaps()
+{
+ void *image01 = NULL;
+ void *image02 = NULL;
+ CompSize size;
+ CompString map01Path(optionGetFileDistProj1());
+ CompString map02Path(optionGetFileDistProj2());
+
+ if (map01Path.empty() || map02Path.empty())
+ return;
+
+ if (!::screen->readImageFromFile (map01Path, size, image01) || !image01)
+ {
+ compLogMessage ("fbo", CompLogLevelWarn,
+ "Failed to load map: %s",
+ map01Path.c_str ());
+ return;
+ }
+ if (!::screen->readImageFromFile (map02Path, size, image02) || !image02)
+ {
+ compLogMessage ("fbo", CompLogLevelWarn,
+ "Failed to load map: %s",
+ map02Path.c_str ());
+ return;
+ }
+ allocTexture(1, (char*) image01);
+ allocTexture(2, (char*) image02);
+}
+
+GLuint
+FboScreen::loadShader(std::string& fileName, GLuint type)
+{
+ std::string strData;
+ std::ifstream fileStream;
+ fileStream.open(fileName.c_str());
+
+ if(!fileStream)
+ {
+ std::cerr << "File " << fileName.c_str() << " could not be opened\n";
+ return 0;
+ }
+ getline(fileStream, strData, fileStream.widen('\255'));
+ fileStream.close();
+ GLuint shader = 0;
+ shader = (*m_glCreateShader)(type);
+ if (shader == 0) //happens with FGLRX
+ {
+ std::cout << "Shader is invalid" << std::endl;
+ return 0;
+ }
+
+ const char* src = strData.c_str();
+ m_glShaderSource(shader, 1, &src, NULL);
+ m_glCompileShader(shader);
+
+ GLint compiled = 0;
+ m_glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+ if(!compiled)
+ {
+ GLsizei length;
+ m_glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
+ char* log = new char[length];
+ m_glGetShaderInfoLog(shader,length,&length,log);
+ std::cerr << "Shader Compile Error : " << log << std::endl;
+ delete log;
+ m_glDeleteShader(shader);
+ shader = 0;
+ }
+ return shader;
+}
+
+void
+FboScreen::clearShader()
+{
+ if (shaderProgram != 0)
+ m_glDeleteProgram(shaderProgram);
+ if (vertexShader != 0)
+ m_glDeleteShader(vertexShader);
+ if (fragmentShader != 0)
+ m_glDeleteShader(fragmentShader);
+
+ shaderProgram = 0;
+ vertexShader = 0;
+ fragmentShader = 0;
+}
+
+void
+FboScreen::loadProgram(std::string& vertexShaderPath, std::string& fragmentShaderPath)
+{
+ clearShader();
+
+ vertexShader = loadShader(vertexShaderPath, GL_VERTEX_SHADER);
+ if (vertexShader == 0)
+ {
+ std::cerr << "ERROR creating Vertex shader" << std::endl;
+ return;
+ }
+ fragmentShader = loadShader(fragmentShaderPath, GL_FRAGMENT_SHADER);
+ if (fragmentShader == 0)
+ {
+ std::cerr << "ERROR creating Fragment shader" << std::endl;
+ return;
+ }
+
+ GLuint program = 0;
+ program = m_glCreateProgram();
+ m_glAttachShader(program, vertexShader);
+ m_glAttachShader(program, fragmentShader);
+ m_glLinkProgram(program);
+
+ GLint linked;
+ m_glGetProgramiv(program, GL_LINK_STATUS, &linked);
+
+ if(!linked)
+ {
+ GLsizei length;
+ m_glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
+ char* log = new char[length];
+ m_glGetProgramInfoLog(program, length, &length, log);
+ std::cerr << "Program Link Error : " << log << "\n";
+ delete log;
+ m_glDeleteProgram(program);
+ program = 0;
+ }
+ std::cout << "Shader creation complete" << std::endl;
+ this->shaderProgram = program;
+}
+
+void
+FboScreen::bindShader()
+{
+ if (shaderProgram != 0)
+ {
+ m_glUseProgram(shaderProgram);
+
+ GLint colorMapSampler = m_glGetUniformLocation(shaderProgram,"colorMap");
+ m_glUniform1i(colorMapSampler,0);
+
+ GLint distortionMapSampler = m_glGetUniformLocation(shaderProgram,"distortionMap");
+ m_glUniform1i(distortionMapSampler,1);
+
+ GLint blendMapSampler = m_glGetUniformLocation(shaderProgram,"blendMap");
+ m_glUniform1i(blendMapSampler,2);
+ }
+
+}
+
+void
+FboScreen::unbindShader()
+{
+ m_glUseProgram(0);
+}
+
+bool
+FboScreen::fboPrologue ()
+{
+ int tIndex = 0;
+
+ if (fbo == 0)
+ return false;
+
+ if (!texture[tIndex])
+ allocTexture (tIndex);
+
+ GL::bindFramebuffer (GL_FRAMEBUFFER_EXT, fbo);
+
+ GL::framebufferTexture2D (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ target, texture[tIndex], 0);
+
+ glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT);
+ glReadBuffer (GL_COLOR_ATTACHMENT0_EXT);
+
+ if (!fboStatus)
+ {
+ fboStatus = GL::checkFramebufferStatus (GL_FRAMEBUFFER_EXT);
+ if (fboStatus != GL_FRAMEBUFFER_COMPLETE_EXT)
+ {
+ compLogMessage ("fbo", CompLogLevelError,
+ "framebuffer incomplete");
+
+ GL::bindFramebuffer (GL_FRAMEBUFFER_EXT, 0);
+ GL::deleteFramebuffers (1, &fbo);
+
+ glDrawBuffer (GL_BACK);
+ glReadBuffer (GL_BACK);
+
+ fbo = 0;
+
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void
+FboScreen::fboEpilogue ()
+{
+ GL::bindFramebuffer (GL_FRAMEBUFFER_EXT, 0);
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glMatrixMode (GL_MODELVIEW);
+ glLoadIdentity ();
+
+ glDrawBuffer (GL_BACK);
+ glReadBuffer (GL_BACK);
+
+}
+
+/**
+ * @see opengl/screen.cpp
+ */
+void
+FboScreen::paint(CompOutput::ptrList &outputs, unsigned int mask)
+{
+ fboEpilogue ();
+
+ if (!texture[0])
+ allocTexture (0);
+
+ glEnable (target);
+ GL::activeTexture (GL_TEXTURE0_ARB);
+ glBindTexture (target, texture[0]);
+ glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ XRectangle r;
+ XRectangle lastViewport;
+ int outputCount = 1;
+
+ foreach (CompOutput *output, outputs)
+ {
+ r.x = output->x1 ();
+ r.y = screen->height () - output->y2 ();
+ r.width = output->width ();
+ r.height = output->height ();
+
+ distWidth = r.width;
+ distHeight = r.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;
+ }
+
+ {
+ glPushMatrix();
+ GLMatrix transform;
+ transform.toScreenSpace (output, -DEFAULT_Z_CAMERA);
+ glLoadMatrixf (transform.getMatrix ());
+
+ //Since coordinate system is mirrored at the x axis (by toScreenSpace()),
+ //(0,0) is at the upper left of the screen (=screen coordinates)
+ //however the texture matrix was not changed and thereby (0,0) in texture space is at (0,screen->height()) in screen space
+ float texX = (1.0f / screen->width()) * output->x1();
+ float texY = (1.0f / screen->height()) * (screen->height () - output->y2 ());
+ float texX2 = (1.0f / screen->width()) * output->x2(); //x2() = x + width
+ float texY2 = (1.0f / screen->height()) * (screen->height () - output->y2 () + output->height());
+
+ if (!texture[1] || !texture[2])
+ loadMaps();
+
+ if (texture[1])
+ {
+ GL::activeTexture (GL_TEXTURE1_ARB);
+ glBindTexture (target, texture[1]);
+ glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ }
+ if (texture[2])
+ {
+ GL::activeTexture (GL_TEXTURE2_ARB);
+ glBindTexture (target, texture[2]);
+ glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ }
+
+ if(shaderInitialized)
+ {
+ if (mToggleShader)
+ bindShader();
+ else
+ unbindShader();
+ }
+ glBegin (GL_QUADS);
+ glTexCoord2f (texX, texY2);
+ glVertex2i (output->x1(), output->y1());
+ glTexCoord2f (texX, texY);
+ glVertex2i (output->x1(), output->y2());
+ glTexCoord2f (texX2, texY);
+ glVertex2i (output->x2(), output->y2());
+ glTexCoord2f (texX2, texY2);
+ glVertex2i (output->x2(), output->y1());
+ glEnd ();
+
+ if (shaderInitialized)
+ {
+ unbindShader();
+ }
+
+ if (texture[2])
+ {
+ glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glBindTexture (target, 0);
+ }
+ if (texture[1])
+ {
+ GL::activeTexture (GL_TEXTURE1_ARB);
+ glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glBindTexture (target, 0);
+ }
+ glPopMatrix();
+ }
+ outputCount++;
+ }
+
+ GL::activeTexture (GL_TEXTURE0_ARB);
+ glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glBindTexture (target, 0);
+
+ glDisable(target);
+
+ if (!fboPrologue ())
+ {
+ std::cout << "Error: Cannot use FBO" <<std::endl;
+ }
+ cScreen->paint (outputs, mask);
+}
+
+void
+FboScreen::donePaint ()
+{
+ cScreen->damageScreen();
+ cScreen->donePaint ();
+}
+
+bool
+FboScreen::glPaintOutput (const GLScreenPaintAttrib &attrib,
+ const GLMatrix &transform,
+ const CompRegion &region,
+ CompOutput *output,
+ unsigned int mask)
+{
+ bool status = gScreen->glPaintOutput(attrib, transform, region, output, mask);
+// if (toggle /*&& output == &screen->outputDevs().at(screen->outputDeviceForPoint(mouse.x(), mouse.y()))*/) //TODO: only draw cursor once
+// {
+ if (optionGetTransformCursor ())
+ {
+ glPushMatrix();
+ GLMatrix sTransform;
+ sTransform.toScreenSpace(output, -DEFAULT_Z_CAMERA);
+ glLoadMatrixf(sTransform.getMatrix());
+ cursor.draw(); //draw cursor on top of all windows and let it be distorted
+ glPopMatrix();
+ }
+
+ return status;
+}
+
+void
+FboScreen::glPaintTransformedOutput (const GLScreenPaintAttrib &attrib,
+ const GLMatrix &transform,
+ const CompRegion &region,
+ CompOutput *output,
+ unsigned int mask)
+{
+ //do nothing
+ gScreen->glPaintOutput (attrib, transform, region, output, mask);
+}
+
+
+static bool
+togglefbo (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &options)
+{
+ FboScreen* fs = FboScreen::get (screen);
+
+ fs->toggleFBO();
+ return false;
+}
+
+static bool
+reloadShaderOption (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &options)
+{
+ FboScreen* fs = FboScreen::get (screen);
+ fs->reloadShader();
+ return false;
+}
+
+bool
+FboScreen::toggleFBO ()
+{
+ if (!toggle)
+ {
+ screen->handleEventSetEnabled(this, true);
+ cScreen->paintSetEnabled (this, true);
+ cScreen->donePaintSetEnabled (this, true);
+ gScreen->glPaintOutputSetEnabled(this, true);
+
+ if (optionGetTransformCursor ())
+ cursorActivate();
+ }
+ else {
+ fboEpilogue();
+
+ screen->handleEventSetEnabled(this, false);
+ cScreen->paintSetEnabled (this, false);
+ cScreen->donePaintSetEnabled (this, false);
+ gScreen->glPaintOutputSetEnabled(this, false);
+
+ cursorDeactivate();
+
+ }
+ toggle = !toggle;
+ cScreen->damageScreen ();
+
+ return true;
+}
+
+void
+FboScreen::reloadShader()
+{
+ if (!shaderInitialized)
+ return;
+ CompString vertShaderFilePath(optionGetFileVert());
+ CompString fragShaderFilePath(optionGetFileFrag());
+ if (!vertShaderFilePath.empty() && !fragShaderFilePath.empty())
+ loadProgram(vertShaderFilePath, fragShaderFilePath);
+}
+
+bool
+FboScreen::toggleShader (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &options)
+{
+ if (!shaderInitialized)
+ {
+ if (!queryForShader())
+ {
+ std::cout << "ERROR: SHADER NOT SUPPORTED" << std::endl;
+ return false;
+ }
+ else
+ {
+ shaderInitialized = true;
+ }
+ }
+ if (!this->mToggleShader)
+ {
+ if (shaderProgram == 0)
+ reloadShader();
+ }
+ mToggleShader = !mToggleShader;
+ cScreen->damageScreen();
+ return false;
+}
+
+void
+FboScreen::handleEvent(XEvent* event)
+{
+ switch(event->type)
+ {
+ default:
+ if (event->type == fixesEventBase + XFixesCursorNotify)
+ {
+ //XFixesCursorNotifyEvent *cev = (XFixesCursorNotifyEvent *)
+ //event;
+// std::cout << "Cursor changed!" << std::endl;
+ updateCursor (&cursor);
+ }
+ }
+ screen->handleEvent(event);
+}
+
+
+FboScreen::Cursor::Cursor()
+: set(false),
+ texture(0),
+ screen(NULL)
+{
+}
+
+void
+FboScreen::Cursor::updateTextureData(unsigned char* data, int width, int height, int x, int y, int xHot, int yHot, CompScreen* screen)
+{
+ if (!set)
+ {
+ set = true;
+ screen = screen;
+ glEnable (GL_TEXTURE_RECTANGLE_ARB);
+ glGenTextures (1, &texture);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, texture);
+
+ glTexParameteri (GL_TEXTURE_RECTANGLE_ARB,
+ GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri (GL_TEXTURE_RECTANGLE_ARB,
+ GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri (GL_TEXTURE_RECTANGLE_ARB,
+ GL_TEXTURE_WRAP_S, GL_CLAMP);
+ glTexParameteri (GL_TEXTURE_RECTANGLE_ARB,
+ GL_TEXTURE_WRAP_T, GL_CLAMP);
+
+ glDisable(GL_TEXTURE_RECTANGLE_ARB);
+ }
+
+ mWidth = width;
+ mHeight = height;
+// this->x = x;
+// this->y = y;
+ mXHot = xHot;
+ mYHot = yHot;
+
+ glEnable(GL_TEXTURE_RECTANGLE_ARB);
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture);
+
+ glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, width,
+ height, 0, GL_BGRA, GL_UNSIGNED_BYTE, data);
+
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, 0);
+ glDisable (GL_TEXTURE_RECTANGLE_ARB);
+}
+
+void
+FboScreen::updateCursor(Cursor* cursor)
+{
+ XFixesCursorImage *cursorImage = XFixesGetCursorImage(screen->dpy ()); //TODO: Hack still necessary (@see ezoom)?
+
+ unsigned int numBytes = cursorImage->width * cursorImage->height * 4;
+ unsigned char *pixels = (unsigned char*)malloc(numBytes); //allocation with new() crashes compiz
+
+ if (!pixels)
+ {
+ XFree(cursorImage);
+ return;
+ }
+
+ for (int i = 0; i < cursorImage->width * cursorImage->height; i++)
+ {
+ unsigned long pixel = cursorImage->pixels[i];
+ pixels[i * 4] = pixel & 0xff;
+ pixels[(i * 4) + 1] = (pixel >> 8) & 0xff;
+ pixels[(i * 4) + 2] = (pixel >> 16) & 0xff;
+ pixels[(i * 4) + 3] = (pixel >> 24) & 0xff;
+ }
+
+ cursor->updateTextureData(pixels,
+ cursorImage->width,
+ cursorImage->height,
+ cursorImage->x,
+ cursorImage->y,
+ cursorImage->xhot,
+ cursorImage->yhot,
+ screen);
+
+ XFree (cursorImage);
+ free (pixels);
+
+}
+void
+FboScreen::Cursor::setPos(int x, int y)
+{
+ pos.setX (x);
+ pos.setY (y);
+}
+
+void
+FboScreen::Cursor::draw()
+{
+ glDisable(GL_LIGHTING);
+ glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+// std::cout << "drawCursor: x: " << -cursor.xHot() << ", y: " << -cursor.yHot() << std::endl;
+
+ int x = pos.x() - mXHot; //shouldn't that be cursor.x and .y?
+ int y = pos.y() - mYHot;
+ glEnable (GL_BLEND);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, texture);
+ glEnable (GL_TEXTURE_RECTANGLE_ARB);
+
+ GLfloat vertices[] = {
+ x, y,
+ x, y + mHeight,
+ x + mWidth, y + mHeight,
+ x + mWidth, y};
+
+ GLfloat texCoords[] = {
+ 0, 0,
+ 0, mHeight,
+ mWidth, mHeight,
+ mWidth, 0
+ };
+ glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ glVertexPointer(2, GL_FLOAT, 0, vertices);
+ glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
+
+ glDrawArrays(GL_QUADS, 0, 4);
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glPopClientAttrib();
+
+ glDisable (GL_BLEND);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, 0);
+ glDisable (GL_TEXTURE_RECTANGLE_ARB);
+ glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+ glEnable(GL_LIGHTING);
+}
+
+void
+FboScreen::Cursor::free()
+{
+ if (!set)
+ return;
+
+ set = false;
+ glDeleteTextures (1, &texture);
+ texture = 0;
+}
+
+/* Timeout handler to poll the mouse. Returns false (and thereby does not
+ * get re-added to the queue) when zoom is not active. */
+void
+FboScreen::updateMouseInterval (const CompPoint &p)
+{
+ cursor.setPos(p.x(), p.y());
+
+ cScreen->damageScreen ();
+}
+
+void
+FboScreen::cursorHide ()
+{
+ if (canHideCursor && optionGetHideOriginalMouse () && optionGetTransformCursor ()) //only allow hiding if cursor is drawn otherwise
+ {
+ XFixesHideCursor (screen->dpy (), screen->root ());
+ }
+}
+
+void
+FboScreen::cursorShow ()
+{
+ if (canHideCursor)
+ {
+ XFixesShowCursor (screen->dpy (), screen->root ());
+ }
+}
+
+void
+FboScreen::cursorActivate ()
+{
+ if (!fixesSupported)
+ return;
+
+ if (!cursorInfoSelected)
+ {
+ cursorInfoSelected = true;
+ XFixesSelectCursorInput (screen->dpy (), screen->root (),
+ XFixesDisplayCursorNotifyMask);
+ updateCursor (&cursor);
+ }
+
+ if (!pollHandle.active ())
+ pollHandle.start ();
+
+ cursorHide (); //in case transform was unchecked and hide was checked
+}
+
+void
+FboScreen::cursorDeactivate ()
+{
+ if (!fixesSupported)
+ return;
+
+ if (cursorInfoSelected)
+ {
+ cursorInfoSelected = false;
+ XFixesSelectCursorInput (screen->dpy (), screen->root (), 0);
+ }
+
+ if (pollHandle.active ())
+ pollHandle.stop ();
+
+ cursor.free();
+
+ cursorShow ();
+}
+
+void
+FboScreen::optionChanged (CompOption *option,
+ FboOptions::Options num)
+{
+ switch(num)
+ {
+ case FboOptions::HideOriginalMouse:
+ if (optionGetHideOriginalMouse () && toggle)//do not allow to hide cursor if fbo mode not active!
+ {
+ cursorHide();
+ }
+ else
+ {
+ cursorShow();
+ }
+ break;
+ case FboOptions::TransformCursor:
+ if (optionGetTransformCursor () && toggle) //do not allow to hide cursor if fbo mode not active!
+ {
+ cursorActivate ();
+ }
+ else
+ {
+ cursorDeactivate ();
+ }
+ break;
+ default:
+ break;
+ }
+ cScreen->damageScreen ();
+}
+
+FboScreen::FboScreen (CompScreen *screen) :
+ PluginClassHandler<FboScreen,CompScreen> (screen),
+ cScreen (CompositeScreen::get (screen)),
+ gScreen (GLScreen::get (screen)),
+ grabIndex (0),
+ width (0),
+ height (0),
+ tIndex (0),
+ target (0),
+ tx (0),
+ ty (0),
+ count (0),
+ fbo (0),
+ fboStatus (0),
+ shaderProgram(0),
+ vertexShader(0),
+ fragmentShader(0),
+ toggle(false),
+ mToggleShader(false),
+ shaderInitialized(false),
+ cursorInfoSelected (false)
+{
+
+ memset (texture, 0, sizeof (GLuint) * TEXTURE_NUM);
+
+ height = screen->height();
+ width = screen->width ();
+ target = GL_TEXTURE_2D;
+
+ if (GL::fbo)
+ {
+ GL::genFramebuffers (1, &fbo);
+ }
+
+ //Query X if current XFixes extension allows Hiding the cursor
+ int major, minor;
+ fixesSupported = XFixesQueryExtension(screen->dpy (),
+ &fixesEventBase,
+ &fixesErrorBase);
+
+ XFixesQueryVersion (screen->dpy (), &major, &minor);
+
+ if (major >= 4)
+ canHideCursor = true;
+ else
+ canHideCursor = false;
+
+ pollHandle.setCallback (boost::bind (
+ &FboScreen::updateMouseInterval, this, _1));
+
+ optionSetToggleFboKeyInitiate (togglefbo);
+ optionSetReloadShaderKeyInitiate (reloadShaderOption);
+ optionSetToggleShaderKeyInitiate (boost::bind (&FboScreen::toggleShader, this,
+ _1, _2, _3));
+
+ optionSetHideOriginalMouseNotify(boost::bind(&FboScreen::optionChanged, this, _1, _2));
+ optionSetTransformCursorNotify(boost::bind(&FboScreen::optionChanged, this, _1, _2));
+
+ ScreenInterface::setHandler (screen, false);
+ CompositeScreenInterface::setHandler (cScreen, false);
+ GLScreenInterface::setHandler(gScreen, false);
+}
+
+FboScreen::~FboScreen ()
+{
+ cursorDeactivate ();
+
+ if (fbo)
+ GL::deleteFramebuffers (1, &fbo);
+
+ for (unsigned int i = 0; i < TEXTURE_NUM; i++)
+ {
+ if (texture[i]) {
+ glDeleteTextures (1, &texture[i]);
+ texture[i] = 0;
+ }
+ }
+ clearShader();
+}
+
+bool
+FboPluginVTable::init ()
+{
+ if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION) |
+ !CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI) |
+ !CompPlugin::checkPluginABI ("opengl", COMPIZ_OPENGL_ABI) |
+ !CompPlugin::checkPluginABI ("mousepoll", COMPIZ_MOUSEPOLL_ABI))
+ return false;
+
+ return true;
+}
+
diff --git a/CompizFBO/src/fbo.h b/CompizFBO/src/fbo.h
new file mode 100644
index 0000000..870480c
--- /dev/null
+++ b/CompizFBO/src/fbo.h
@@ -0,0 +1,205 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <sys/time.h>
+#include <iostream>
+#include <string>
+#include <fstream>
+#include <X11/cursorfont.h>
+#include <compiz/core/core.h>
+#include <compiz/core/pluginclasshandler.h>
+
+#include <compiz/composite/composite.h>
+#include <compiz/opengl/opengl.h>
+#include <compiz/mousepoll/mousepoll.h>
+
+#include "fbo_options.h"
+
+#define STEP_SIZE_X 4 //Number of quads in x output->width() mod STEP_SIZE_X should be 0!!!
+#define STEP_SIZE_Y 512//540 //Number of quads in y, output->height() mod STEP_SIZE_Y should be 0!!!
+
+//typedef void ( *GLUseProgramProc) (GLuint program);
+//typedef GLuint ( *GLCreateShaderProc) (GLuint type);
+//typedef void ( *GLShaderSourceProc) (GLuint shader, GLsizei count, const GLchar** strings, const GLint* lengths);
+//typedef void ( *GLCompileShaderProc) (GLuint shader);
+//typedef void ( *GLGetShaderIvProc) (GLuint shader, GLenum pname, GLint* param);
+//typedef void ( *GLGetShaderInfoLogProc) (GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
+//typedef void ( *GLDeleteShaderProc) (GLuint shader);
+//typedef void ( *GLDeleteProgramProc) (GLuint program);
+//typedef GLuint ( *GLCreateProgramProc) (void);
+//typedef void (*GLAttachShaderProc) (GLuint program, GLuint shader);
+//typedef void (*GLLinkProgramProc) (GLuint program);
+//typedef void (*GLGetProgramIvProc) (GLuint program, GLenum pname, GLint* param);
+//typedef void (*GLGetProgramInfoLogProc) (GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
+//typedef GLint (*GLGetUniformLocationProc) (GLuint program, const GLchar* name);
+//typedef void (*GLUniform1iProc) (GLint location, GLint v0);
+//
+//extern GLUseProgramProc m_glUseProgram;
+//extern GLCreateShaderProc m_glCreateShader;
+//extern GLShaderSourceProc m_glShaderSource;
+//extern GLCompileShaderProc m_glCompileShader;
+//extern GLGetShaderIvProc m_glGetShaderiv;
+//extern GLGetShaderInfoLogProc m_glGetShaderInfoLog;
+//extern GLDeleteShaderProc m_glDeleteShader;
+//extern GLDeleteProgramProc m_glDeleteProgram;
+//extern GLCreateProgramProc m_m_glCreateProgram;
+//extern GLAttachShaderProc m_glAttachShader;
+//extern GLLinkProgramProc m_glLinkProgram;
+//extern GLGetProgramIvProc m_glGetProgramiv;
+//extern GLGetProgramInfoLogProc m_glGetProgramInfoLog;
+//extern GLGetUniformLocationProc m_glGetUniformLocation;
+//extern GLUniform1iProc m_glUniform1i;
+extern PFNGLCREATEPROGRAMPROC m_glCreateProgram;
+extern PFNGLUSEPROGRAMPROC m_glUseProgram;
+extern PFNGLCREATESHADERPROC m_glCreateShader;
+extern PFNGLSHADERSOURCEPROC m_glShaderSource;
+extern PFNGLCOMPILESHADERPROC m_glCompileShader;
+extern PFNGLATTACHSHADERPROC m_glAttachShader;
+extern PFNGLLINKPROGRAMPROC m_glLinkProgram;
+extern PFNGLGETUNIFORMLOCATIONPROC m_glGetUniformLocation;
+extern PFNGLUNIFORM1IPROC m_glUniform1i;
+extern PFNGLGETSHADERIVPROC m_glGetShaderiv;
+extern PFNGLGETSHADERINFOLOGPROC m_glGetShaderInfoLog;
+extern PFNGLGETPROGRAMINFOLOGPROC m_glGetProgramInfoLog;
+extern PFNGLGETPROGRAMIVPROC m_glGetProgramiv;
+extern PFNGLDELETESHADERPROC m_glDeleteShader;
+extern PFNGLDELETEPROGRAMPROC m_glDeleteProgram;
+
+#define TEXTURE_NUM 3 //color, distortion, blend
+
+class FboScreen :
+ public ScreenInterface,
+ public CompositeScreenInterface,
+ public GLScreenInterface,
+ public PluginClassHandler<FboScreen,CompScreen>,
+ public FboOptions
+{
+ public:
+
+ CompositeScreen *cScreen;
+ GLScreen *gScreen;
+
+ FboScreen (CompScreen *screen);
+ ~FboScreen ();
+
+ //Screen Interface
+ void handleEvent(XEvent* event);
+
+ void paint(CompOutput::ptrList &outputs, unsigned int mask);
+ void donePaint ();
+
+ bool glPaintOutput (const GLScreenPaintAttrib &,
+ const GLMatrix &, const CompRegion &,
+ CompOutput *, unsigned int);
+ void glPaintTransformedOutput (const GLScreenPaintAttrib &,
+ const GLMatrix &, const CompRegion &,
+ CompOutput *, unsigned int);
+
+ void allocTexture (int index, char* data=NULL);
+ void loadMaps();
+ bool fboPrologue ();
+ void fboEpilogue ();
+
+ bool toggleFBO();
+ bool toggleShader();
+ bool queryForShader();
+
+ void clearShader();
+ GLuint loadShader(std::string& fileName, GLuint type);
+ void reloadShader();
+ void loadProgram(std::string& vertexShaderPath, std::string& fragmentShaderPath);
+ void bindShader();
+ void unbindShader();
+
+ bool
+ toggleShader (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &options);
+
+ //Cursor related code, partly taken from ezoom plugin
+ public:
+ class Cursor
+ {
+ private:
+ bool set;
+ GLuint texture;
+ CompScreen *screen;
+ int mXHot;
+ int mYHot;
+ int mWidth;
+ int mHeight;
+ CompPoint pos;
+
+
+ public:
+ Cursor ();
+ void
+ setPos(int x, int y);
+ void
+ updateTextureData(unsigned char* data, int width, int height, int x, int y, int xHot, int yHot, CompScreen* screen);
+ void
+ draw();
+ void
+ free();
+ };
+ void
+ cursorActivate();
+ void
+ cursorDeactivate();
+ void
+ cursorHide();
+ void
+ cursorShow();
+ void
+ updateCursor (Cursor * cursor);
+ void
+ updateMouseInterval (const CompPoint &p);
+ void
+ optionChanged (CompOption *option,
+ FboOptions::Options num);
+
+private:
+ CompScreen::GrabHandle grabIndex;
+
+ int width, height;
+
+ GLuint program;
+ GLuint texture[TEXTURE_NUM];
+
+ int tIndex;
+ unsigned int mCurrentTextureIndex;
+ GLenum target;
+ GLfloat tx, ty;
+
+ int count;
+
+ GLuint fbo;
+ GLint fboStatus;
+ GLuint shaderProgram;
+ GLuint vertexShader;
+ GLuint fragmentShader;
+
+ bool toggle, mToggleShader;
+ bool shaderInitialized;
+ float rotate;
+ int counter;
+ int distWidth, distHeight;
+
+ MousePoller pollHandle;
+
+ bool fixesSupported;
+ int fixesEventBase;
+ int fixesErrorBase;
+ bool canHideCursor;
+ bool cursorInfoSelected;
+ Cursor cursor;
+};
+
+class FboPluginVTable :
+ public CompPlugin::VTableForScreen<FboScreen>
+{
+ public:
+
+ bool init ();
+};