diff options
author | Pixel <pixel@nobis-crew.org> | 2009-11-04 11:56:41 -0800 |
---|---|---|
committer | Pixel <pixel@nobis-crew.org> | 2009-11-04 11:59:33 -0800 |
commit | d577d991b97ae2b5ee1af23641bcffc3f83af5b2 (patch) | |
tree | 590639d50205d1bcfaff2a7d2dc6ebf3f373c7ed /iup/srcgl/iup_glcanvas_x.c |
Initial import. Contains the im, cd and iup librairies, and a "working" Makefile for them under linux.
Diffstat (limited to 'iup/srcgl/iup_glcanvas_x.c')
-rwxr-xr-x | iup/srcgl/iup_glcanvas_x.c | 448 |
1 files changed, 448 insertions, 0 deletions
diff --git a/iup/srcgl/iup_glcanvas_x.c b/iup/srcgl/iup_glcanvas_x.c new file mode 100755 index 0000000..adddeb1 --- /dev/null +++ b/iup/srcgl/iup_glcanvas_x.c @@ -0,0 +1,448 @@ +/** \file + * \brief iupgl control for X11 + * + * See Copyright Notice in "iup.h" + */ + +#include <X11/Xlib.h> +#include <GL/glx.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <memory.h> + +#include "iup.h" +#include "iupcbs.h" +#include "iupgl.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_stdcontrols.h" +#include "iup_assert.h" +#include "iup_register.h" + + +struct _IcontrolData +{ + iupCanvas canvas; /* from IupCanvas (must reserve it) */ + + Display* display; + Drawable window; + + Colormap colormap; + XVisualInfo *vinfo; + GLXContext context; +}; + +static int xGLCanvasDefaultResize(Ihandle *ih, int width, int height) +{ + IupGLMakeCurrent(ih); + glViewport(0,0,width,height); + return IUP_DEFAULT; +} + +static int xGLCanvasCreateMethod(Ihandle* ih, void** params) +{ + (void)params; + free(ih->data); /* allocated by the iCanvasCreateMethod of IupCanvas */ + ih->data = iupALLOCCTRLDATA(); + IupSetCallback(ih, "RESIZE_CB", (Icallback)xGLCanvasDefaultResize); + return IUP_NOERROR; +} + +static void xGLCanvasGetVisual(Ihandle* ih) +{ + int erb, evb, number; + int n = 0; + int alist[40]; + + if (!ih->data->display) + ih->data->display = (Display*)IupGetGlobal("XDISPLAY"); /* works for Motif and GTK, can be called before mapped */ + if (!ih->data->display) + return; + + /* double or single buffer */ + if (iupStrEqualNoCase(iupAttribGetStr(ih,"BUFFER"), "DOUBLE")) + { + alist[n++] = GLX_DOUBLEBUFFER; + } + + /* stereo */ + if (iupAttribGetBoolean(ih,"STEREO")) + { + alist[n++] = GLX_STEREO; + } + + /* rgba or index */ + if (iupStrEqualNoCase(iupAttribGetStr(ih,"COLOR"), "INDEX")) + { + /* buffer size (for index mode) */ + number = iupAttribGetInt(ih,"BUFFER_SIZE"); + if (number > 0) + { + alist[n++] = GLX_BUFFER_SIZE; + alist[n++] = number; + } + } + else + { + alist[n++] = GLX_RGBA; /* assume rgba as default */ + } + + /* red, green, blue bits */ + number = iupAttribGetInt(ih,"RED_SIZE"); + if (number > 0) + { + alist[n++] = GLX_RED_SIZE; + alist[n++] = number; + } + + number = iupAttribGetInt(ih,"GREEN_SIZE"); + if (number > 0) + { + alist[n++] = GLX_GREEN_SIZE; + alist[n++] = number; + } + + number = iupAttribGetInt(ih,"BLUE_SIZE"); + if (number > 0) + { + alist[n++] = GLX_BLUE_SIZE; + alist[n++] = number; + } + + number = iupAttribGetInt(ih,"ALPHA_SIZE"); + if (number > 0) + { + alist[n++] = GLX_ALPHA_SIZE; + alist[n++] = number; + } + + /* depth and stencil size */ + number = iupAttribGetInt(ih,"DEPTH_SIZE"); + if (number > 0) + { + alist[n++] = GLX_DEPTH_SIZE; + alist[n++] = number; + } + + number = iupAttribGetInt(ih,"STENCIL_SIZE"); + if (number > 0) + { + alist[n++] = GLX_STENCIL_SIZE; + alist[n++] = number; + } + + /* red, green, blue accumulation bits */ + number = iupAttribGetInt(ih,"ACCUM_RED_SIZE"); + if (number > 0) + { + alist[n++] = GLX_ACCUM_RED_SIZE; + alist[n++] = number; + } + + number = iupAttribGetInt(ih,"ACCUM_GREEN_SIZE"); + if (number > 0) + { + alist[n++] = GLX_ACCUM_GREEN_SIZE; + alist[n++] = number; + } + + number = iupAttribGetInt(ih,"ACCUM_BLUE_SIZE"); + if (number > 0) + { + alist[n++] = GLX_ACCUM_BLUE_SIZE; + alist[n++] = number; + } + + number = iupAttribGetInt(ih,"ACCUM_ALPHA_SIZE"); + if (number > 0) + { + alist[n++] = GLX_ACCUM_ALPHA_SIZE; + alist[n++] = number; + } + alist[n++] = None; + + /* check out X extension */ + if (!glXQueryExtension(ih->data->display, &erb, &evb)) + { + iupAttribSetStr(ih, "ERROR", "X server has no OpenGL GLX extension"); + return; + } + + /* choose visual */ + ih->data->vinfo = glXChooseVisual(ih->data->display, DefaultScreen(ih->data->display), alist); + if (!ih->data->vinfo) + iupAttribSetStr(ih, "ERROR", "No appropriate visual"); +} + +static char* xGLCanvasGetVisualAttrib(Ihandle *ih) +{ + /* This must be available before mapping, because IupCanvas uses it during map in GTK and Motif. */ + if (ih->data->vinfo) + return (char*)ih->data->vinfo->visual; + + xGLCanvasGetVisual(ih); + + if (ih->data->vinfo) + return (char*)ih->data->vinfo->visual; + + return NULL; +} + +static int xGLCanvasMapMethod(Ihandle* ih) +{ + GLXContext shared_context = NULL; + Ihandle* ih_shared; + + /* the IupCanvas is already mapped, just initialize the OpenGL context */ + + if (!xGLCanvasGetVisualAttrib(ih)) + return IUP_NOERROR; /* do not abort mapping */ + + ih->data->window = (XID)iupAttribGet(ih, "XWINDOW"); /* check first in the hash table, can be defined by the IupFileDlg */ + if (!ih->data->window) + ih->data->window = (XID)IupGetAttribute(ih, "XWINDOW"); /* works for Motif and GTK, only after mapping the IupCanvas */ + if (!ih->data->window) + return IUP_NOERROR; + + ih_shared = IupGetAttributeHandle(ih, "SHAREDCONTEXT"); + if (ih_shared && iupStrEqual(ih_shared->iclass->name, "glcanvas")) /* must be an IupGLCanvas */ + shared_context = ih_shared->data->context; + + /* create rendering context */ + ih->data->context = glXCreateContext(ih->data->display, ih->data->vinfo, shared_context, GL_TRUE); + if (!ih->data->context) + { + iupAttribSetStr(ih, "ERROR", "Could not create a rendering context"); + return IUP_NOERROR; + } + iupAttribSetStr(ih, "CONTEXT", (char*)ih->data->context); + + /* create colormap for index mode */ + if (iupStrEqualNoCase(iupAttribGetStr(ih,"COLOR"), "INDEX") && + ih->data->vinfo->class != StaticColor && ih->data->vinfo->class != StaticGray) + { + ih->data->colormap = XCreateColormap(ih->data->display, RootWindow(ih->data->display, DefaultScreen(ih->data->display)), ih->data->vinfo->visual, AllocAll); + iupAttribSetStr(ih, "COLORMAP", (char*)ih->data->colormap); + } + + if (ih->data->colormap != None) + IupGLPalette(ih,0,1,1,1); /* set first color as white */ + + return IUP_NOERROR; +} + +static void xGLCanvasUnMapMethod(Ihandle* ih) +{ + if (ih->data->context) + { + if (ih->data->context == glXGetCurrentContext()) + glXMakeCurrent(ih->data->display, None, NULL); + + glXDestroyContext(ih->data->display, ih->data->context); + } + + if (ih->data->colormap != None) + XFreeColormap(ih->data->display, ih->data->colormap); + + if (ih->data->vinfo) + XFree(ih->data->vinfo); +} + +static Iclass* xGlCanvasGetClass(void) +{ + Iclass* ic = iupClassNew(iupCanvasGetClass()); + + ic->name = "glcanvas"; + ic->format = "A"; /* one optional callback name */ + ic->nativetype = IUP_TYPECANVAS; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 1; + + ic->Create = xGLCanvasCreateMethod; + ic->Map = xGLCanvasMapMethod; + ic->UnMap = xGLCanvasUnMapMethod; + + iupClassRegisterAttribute(ic, "BUFFER", NULL, NULL, IUPAF_SAMEASSYSTEM, "SINGLE", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "COLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "RGBA", IUPAF_DEFAULT); + + iupClassRegisterAttribute(ic, "CONTEXT", NULL, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_STRING); + iupClassRegisterAttribute(ic, "VISUAL", xGLCanvasGetVisualAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_STRING|IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "COLORMAP", NULL, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_STRING); + + return ic; +} + + +/******************************************* Exported functions */ + +void IupGLCanvasOpen(void) +{ + if (!IupGetGlobal("_IUP_GLCANVAS_OPEN")) + { + iupRegisterClass(xGlCanvasGetClass()); + IupSetGlobal("_IUP_GLCANVAS_OPEN", "1"); + } +} + +Ihandle* IupGLCanvas(const char *action) +{ + void *params[2]; + params[0] = (void*)action; + params[1] = NULL; + return IupCreatev("glcanvas", params); +} + +int IupGLIsCurrent(Ihandle* ih) +{ + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return 0; + + /* must be an IupGLCanvas */ + if (!iupStrEqual(ih->iclass->name, "glcanvas")) + return 0; + + /* must be mapped */ + if (!ih->data->window) + return 0; + + if (ih->data->context == glXGetCurrentContext()) + return 1; + + return 0; +} + +void IupGLMakeCurrent(Ihandle* ih) +{ + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return; + + /* must be an IupGLCanvas */ + if (!iupStrEqual(ih->iclass->name, "glcanvas")) + return; + + /* must be mapped */ + if (!ih->data->window) + return; + + glXMakeCurrent(ih->data->display, ih->data->window, ih->data->context); + glXWaitX(); +} + +void IupGLSwapBuffers(Ihandle* ih) +{ + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return; + + /* must be an IupGLCanvas */ + if (!iupStrEqual(ih->iclass->name, "glcanvas")) + return; + + /* must be mapped */ + if (!ih->data->window) + return; + + glXSwapBuffers(ih->data->display, ih->data->window); +} + +static int xGLCanvasIgnoreError(Display *param1, XErrorEvent *param2) +{ + (void)param1; + (void)param2; + return 0; +} + +void IupGLPalette(Ihandle* ih, int index, float r, float g, float b) +{ + XColor color; + int rShift, gShift, bShift; + XVisualInfo *vinfo; + XErrorHandler old_handler; + + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return; + + /* must be an IupGLCanvas */ + if (!iupStrEqual(ih->iclass->name, "glcanvas")) + return; + + /* must be mapped */ + if (!ih->data->window) + return; + + /* must have a colormap */ + if (ih->data->colormap == None) + return; + + /* code fragment based on the toolkit library provided with OpenGL */ + old_handler = XSetErrorHandler(xGLCanvasIgnoreError); + + vinfo = ih->data->vinfo; + switch (vinfo->class) + { + case DirectColor: + rShift = ffs((unsigned int)vinfo->red_mask) - 1; + gShift = ffs((unsigned int)vinfo->green_mask) - 1; + bShift = ffs((unsigned int)vinfo->blue_mask) - 1; + color.pixel = ((index << rShift) & vinfo->red_mask) | + ((index << gShift) & vinfo->green_mask) | + ((index << bShift) & vinfo->blue_mask); + color.red = (unsigned short)(r * 65535.0 + 0.5); + color.green = (unsigned short)(g * 65535.0 + 0.5); + color.blue = (unsigned short)(b * 65535.0 + 0.5); + color.flags = DoRed | DoGreen | DoBlue; + XStoreColor(ih->data->display, ih->data->colormap, &color); + break; + case GrayScale: + case PseudoColor: + if (index < vinfo->colormap_size) + { + color.pixel = index; + color.red = (unsigned short)(r * 65535.0 + 0.5); + color.green = (unsigned short)(g * 65535.0 + 0.5); + color.blue = (unsigned short)(b * 65535.0 + 0.5); + color.flags = DoRed | DoGreen | DoBlue; + XStoreColor(ih->data->display, ih->data->colormap, &color); + } + break; + } + + XSync(ih->data->display, 0); + XSetErrorHandler(old_handler); +} + +void IupGLUseFont(Ihandle* ih, int first, int count, int list_base) +{ + Font font; + + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return; + + /* must be an IupGLCanvas */ + if (!iupStrEqual(ih->iclass->name, "glcanvas")) + return; + + /* must be mapped */ + if (!ih->data->window) + return; + + font = (Font)IupGetAttribute(ih, "XFONTID"); + if (font) + glXUseXFont(font, first, count, list_base); +} + +void IupGLWait(int gl) +{ + if (gl) + glXWaitGL(); + else + glXWaitX(); +} |