diff options
author | Thorvald Natvig <slicer@users.sourceforge.net> | 2007-07-05 20:26:06 +0400 |
---|---|---|
committer | Thorvald Natvig <slicer@users.sourceforge.net> | 2007-07-05 20:26:06 +0400 |
commit | 12fe384d406c97c9c79178581dfff75dd4e929ba (patch) | |
tree | 01f6548a4b7459d9f66784584b901355c53567d2 /overlay_gl | |
parent | bfe22705cc52867ec009abb52c6ce80485c5e4da (diff) |
Working Linux OpenGL overlay
git-svn-id: https://mumble.svn.sourceforge.net/svnroot/mumble/trunk@540 05730e5d-ab1b-0410-a4ac-84af385074fa
Diffstat (limited to 'overlay_gl')
-rw-r--r-- | overlay_gl/overlay.cpp | 365 | ||||
-rw-r--r-- | overlay_gl/overlay_gl.pro | 3 |
2 files changed, 359 insertions, 9 deletions
diff --git a/overlay_gl/overlay.cpp b/overlay_gl/overlay.cpp index 3a5ea51b5..e8c826d63 100644 --- a/overlay_gl/overlay.cpp +++ b/overlay_gl/overlay.cpp @@ -29,19 +29,66 @@ */ #include <GL/glx.h> +#include <GL/glu.h> #include <GL/gl.h> #include <dlfcn.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> +#include <sys/types.h> +#include <sys/mman.h> +#include <sys/ipc.h> +#include <sys/time.h> +#include <time.h> +#include <semaphore.h> +#include <fcntl.h> +#include <stdarg.h> +#include <map> +#include "../overlay/overlay.h" + +using namespace std; + +// Prototypes +static void resolveOpenGL(void *); +static void resolveSM(); +static void ods(const char *format, ...); + +static SharedMem *sm; + +#define FDEF(return,name,args) typedef return(*f##name)args; static f##name o##name + +FDEF(void,glXSwapBuffers,(Display *,GLXDrawable)); +FDEF(GLXContext, glXGetCurrentContext,(void)); +FDEF(void, glGenTextures,(GLsizei,GLuint *)); +FDEF(void, glXQueryDrawable, (Display *,GLXDrawable, int, unsigned int *)); +FDEF(void, glBindTexture, (GLenum, GLuint)); +FDEF(void, glBegin, (GLenum)); +FDEF(void, glVertex2f, (GLfloat, GLfloat)); +FDEF(void, glEnd, (void)); +FDEF(void, glPushAttrib, (GLbitfield)); +FDEF(void, glPopAttrib, (void)); +FDEF(void, glViewport, (GLint, GLint, GLsizei, GLsizei)); +FDEF(void, glMatrixMode, (GLenum)); +FDEF(void, glPushMatrix, (void)); +FDEF(void, glPopMatrix, (void)); +FDEF(void, glLoadIdentity, (void)); +FDEF(void, glOrtho, (GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble)); +FDEF(void, glActiveTextureARB, (GLenum)); +FDEF(void, glEnable, (GLenum)); +FDEF(void, glDisable, (GLenum)); +FDEF(void, glBlendFunc, (GLenum, GLenum)); +FDEF(void, glColorMaterial, (GLenum, GLenum)); +FDEF(void, glTexParameteri, (GLenum, GLenum, GLint)); +FDEF(void, glTexImage2D, (GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *)); +FDEF(void, glColor4ub, (GLubyte, GLubyte, GLubyte, GLubyte)); +FDEF(void, glTranslatef, (GLfloat, GLfloat, GLfloat)); +FDEF(void, glTexCoord2f, (GLfloat, GLfloat)); // Typdefs for functions we're overriding typedef void *(*fdlsym)(void *, const char *); -typedef void(*fglXSwapBuffers)(Display *,GLXDrawable); // Original and replacement swapbuffers -static fglXSwapBuffers oglXSwapBuffers; void glXSwapBuffers(Display *, GLXDrawable); // Define for the dlsym we're chaining to. Ugly hack. @@ -71,7 +118,7 @@ void *dlsym(void *ctx, const char *fname) { } if (! bTrueSymbol) { if (strcmp(fname, "glXSwapBuffers")==0) { - oglXSwapBuffers = (fglXSwapBuffers) gdlsym(ctx, fname); + resolveOpenGL(ctx); if (oglXSwapBuffers) return (void *) glXSwapBuffers; else @@ -81,16 +128,318 @@ void *dlsym(void *ctx, const char *fname) { return gdlsym(ctx, fname); } -static void *glsym(const char *fname) { +#define RESOLVE(x) o##x = (f##x) dlsym(ctx, #x) + +static void resolveOpenGL(void *ctx) { bTrueSymbol = true; - void *r=dlsym(RTLD_NEXT, fname); + if (ctx == RTLD_DEFAULT) + ctx = RTLD_NEXT; + +RESOLVE(glXSwapBuffers); +RESOLVE(glXGetCurrentContext); +RESOLVE(glGenTextures); +RESOLVE(glXQueryDrawable); +RESOLVE(glBindTexture); +RESOLVE(glBegin); +RESOLVE(glVertex2f); +RESOLVE(glEnd); +RESOLVE(glPushAttrib); +RESOLVE(glPopAttrib); +RESOLVE(glViewport); +RESOLVE(glMatrixMode); +RESOLVE(glPushMatrix); +RESOLVE(glPopMatrix); +RESOLVE(glLoadIdentity); +RESOLVE(glOrtho); +RESOLVE(glActiveTextureARB); +RESOLVE(glEnable); +RESOLVE(glDisable); +RESOLVE(glBlendFunc); +RESOLVE(glColorMaterial); +RESOLVE(glTexParameteri); +RESOLVE(glTexImage2D); +RESOLVE(glColor4ub); +RESOLVE(glTranslatef); +RESOLVE(glTexCoord2f); + + RESOLVE(glXGetCurrentContext); + RESOLVE(glXSwapBuffers); + RESOLVE(glGenTextures); + RESOLVE(glXQueryDrawable); + RESOLVE(glBindTexture); + RESOLVE(glBegin); + RESOLVE(glVertex2f); + RESOLVE(glEnd); + bTrueSymbol = false; - return r; } +static sem_t *sem; + +static void resolveSM() { + int fd = shm_open("/MumbleOverlayMem", O_RDWR, 0600); + if (fd >= 0) { + sm=static_cast<SharedMem *>(mmap(NULL, sizeof(SharedMem), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)); + if (sm == reinterpret_cast<SharedMem *>(-1)) { + sm = NULL; + close(fd); + } else { + sem = sem_open("/MumbleOverlaySem", 0); + if (sem == SEM_FAILED) { + munmap(sm, sizeof(SharedMem)); + sm = NULL; + close(fd); + } + } + } +} + +void ods(const char *format, ...) { + if (!sm || ! sm->bDebug) + return; + + va_list args; + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, "\n"); + fflush(stderr); +} + +class GLContext { + public: + GLXContext ctx; + GLuint textures[NUM_TEXTS]; + GLContext(GLXContext context); + void draw(Display *, GLXDrawable); + ~GLContext(); +}; + +GLContext::GLContext(GLXContext context) { + ctx = context; + oglGenTextures(NUM_TEXTS, textures); +} + +GLContext::~GLContext() { +} + +void GLContext::draw(Display *dpy, GLXDrawable draw) { + sm->bHooked = true; + + // DEBUG + // sm->bDebug = true; + + unsigned int width, height; + oglXQueryDrawable(dpy, draw, GLX_WIDTH, &width); + oglXQueryDrawable(dpy, draw, GLX_HEIGHT, &height); + + ods("DrawStart: Screen is %d x %d", width, height); + + if (sm->fFontSize < 0.01) + sm->fFontSize = 0.01; + else if (sm->fFontSize > 1.0) + sm->fFontSize = 1.0; + + int iHeight = (height *1.0) * sm->fFontSize; + if (iHeight > TEXT_HEIGHT) + iHeight = TEXT_HEIGHT; + + float s = iHeight / 60.0; + int y = 0; + int idx = 0; + + int texs[NUM_TEXTS]; + int widths[NUM_TEXTS]; + int yofs[NUM_TEXTS]; + unsigned int color[NUM_TEXTS]; + + if (sem_trywait(sem) != 0) + return; + + // Save all state. Please? + oglPushAttrib(-1); + + oglViewport(0,0,width,height); + + oglMatrixMode(GL_PROJECTION); + oglPushMatrix(); + oglLoadIdentity(); + oglOrtho(0, width, height, 0, -100.0, 100.0); + oglMatrixMode(GL_TEXTURE); + oglPushMatrix(); + oglLoadIdentity(); + oglMatrixMode(GL_COLOR); + oglPushMatrix(); + oglLoadIdentity(); + + oglMatrixMode(GL_MODELVIEW); + oglPushMatrix(); + oglLoadIdentity(); + + oglActiveTextureARB(GL_TEXTURE0_ARB); + + // Here we go. From the top. Where is glResetState? + oglDisable(GL_ALPHA_TEST); + oglDisable(GL_AUTO_NORMAL); + oglEnable(GL_BLEND); + // Skip clip planes, there are thousands of them. + oglDisable(GL_COLOR_LOGIC_OP); + oglEnable(GL_COLOR_MATERIAL); + oglDisable(GL_COLOR_TABLE); + oglDisable(GL_CONVOLUTION_1D); + oglDisable(GL_CONVOLUTION_2D); + oglDisable(GL_CULL_FACE); + oglDisable(GL_DEPTH_TEST); + oglDisable(GL_DITHER); + oglDisable(GL_FOG); + oglDisable(GL_HISTOGRAM); + oglDisable(GL_INDEX_LOGIC_OP); + oglDisable(GL_LIGHTING); + // Skip line smmooth + // Skip map + oglDisable(GL_MINMAX); + // Skip polygon offset + oglDisable(GL_SEPARABLE_2D); + oglDisable(GL_SCISSOR_TEST); + oglDisable(GL_STENCIL_TEST); + oglEnable(GL_TEXTURE_2D); + oglDisable(GL_TEXTURE_GEN_Q); + oglDisable(GL_TEXTURE_GEN_R); + oglDisable(GL_TEXTURE_GEN_S); + oglDisable(GL_TEXTURE_GEN_T); + + oglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + oglColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); + + for(int i=0;i<NUM_TEXTS;i++) { + if (sm->texts[i].width == 0) { + y+= iHeight / 4; + } else if (sm->texts[i].width > 0) { + if (sm->texts[i].bUpdated) { + ods("Updating %d %d texture", sm->texts[i].width, TEXT_HEIGHT); + oglBindTexture(GL_TEXTURE_2D, textures[i]); + oglTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + oglTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); +// oglTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); +// oglTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); + oglTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE); + oglTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE); + oglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEXT_WIDTH, TEXT_HEIGHT, 0, GL_BGRA, GL_UNSIGNED_BYTE, sm->texts[i].texture); + sm->texts[i].bUpdated = false; + } + texs[idx] = textures[i]; + widths[idx] = sm->texts[i].width; + color[idx] = sm->texts[i].color; + yofs[idx] = y; + y += iHeight; + idx++; + } + } + sem_post(sem); + + int h = y; + y = height * sm->fY; + + if (sm->bTop) { + y -= h; + } else if (sm->bBottom) { + } else { + y -= h / 2; + } + + if (y < 1) + y = 1; + if ((y+h+1) > height) + y = height - h - 1; + + + for(int i=0;i<idx;i++) { + int w = widths[i] * s; + int x = width * sm->fX; + if (sm->bLeft) { + x -= w; + } else if (sm->bRight) { + } else { + x -= w / 2; + } + + if (x < 1) + x = 1; + if ((x + w + 1) > width) + x = width - w - 1; + + ods("Drawing text at %d %d %d %d", x, y+yofs[i], w, iHeight); + oglBindTexture(GL_TEXTURE_2D, texs[i]); + oglPushMatrix(); + oglLoadIdentity(); + + double xm = 0.0; + double ym = 0.0; + double xmx = (1.0 * widths[i]) / TEXT_WIDTH; + double ymx = 1.0; + + unsigned int c = color[i]; + + oglColor4ub((c >> 16) & 0xFF, (c >> 8) & 0xFF, c & 0xFF, (c >> 24) & 0xFF); + + + oglTranslatef(x, y + yofs[i], 0.0); + oglBegin(GL_QUADS); + oglTexCoord2f(xm, ymx); + oglVertex2f(0, iHeight); + oglTexCoord2f(xm, ym); + oglVertex2f(0, 0); + oglTexCoord2f(xmx, ym); + oglVertex2f(w, 0); + oglTexCoord2f(xmx, ymx); + oglVertex2f(w, iHeight); + oglEnd(); + oglPopMatrix(); + } + + oglBindTexture(GL_TEXTURE_2D, textures[NUM_TEXTS-1]); + + oglPopMatrix(); + oglMatrixMode(GL_COLOR); + oglPopMatrix(); + oglMatrixMode(GL_TEXTURE); + oglPopMatrix(); + oglMatrixMode(GL_PROJECTION); + oglPopMatrix(); + + oglPopAttrib(); +} + +static map<GLXContext, GLContext *> contexts; + void glXSwapBuffers(Display *dpy, GLXDrawable draw) { if (! oglXSwapBuffers) - oglXSwapBuffers = (fglXSwapBuffers) glsym("glXSwapBuffers"); - fprintf(stderr, "Swapping\n"); + resolveOpenGL(RTLD_NEXT); + + if (! sm) { + resolveSM(); + if (sm) { + sm->bHooked = true; + for(int i=0;i<NUM_TEXTS;i++) + sm->texts[i].bUpdated = true; + } + } + + if (sm) { + GLXContext ctx = oglXGetCurrentContext(); + + GLContext *c = contexts[ctx]; + if (!c) { + c = new GLContext(ctx); + contexts[ctx] = c; + } + c->draw(dpy,draw); + } else { + static bool warned = false; + if (! warned) { + fprintf(stderr, "MUMBLE OVERLAY:: NO CONTACT WITH MUMBLE\n"); + warned = true; + } + } oglXSwapBuffers(dpy, draw); } diff --git a/overlay_gl/overlay_gl.pro b/overlay_gl/overlay_gl.pro index e6e7d9f97..60666c927 100644 --- a/overlay_gl/overlay_gl.pro +++ b/overlay_gl/overlay_gl.pro @@ -3,9 +3,10 @@ TEMPLATE = lib CONFIG -= qt -CONFIG += release +CONFIG += debug_and_release TARGET = mumble_ol SOURCES = overlay.cpp +LIBS += -lrt CONFIG(debug, debug|release) { DESTDIR = ../debug |