// // graph.c - graphing utility functions using OpenGL // // Copyright (C) 2006 Nathan (Acorn) Pooley // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // version 2 as published by the Free Software Foundation. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License (gpl.txt) for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // You can contact the author, Nathan (Acorn) Pooley, by writing // to Nathan (Acorn) Pooley, 949 Buckeye Drive, Sunnyvale, CA 94086, USA // or through the form at http://www.rawbw.com/~acorn/wand/feedback.html // //#@DOC@ generic graphing utility functions //########################################################################### //############################### INCLUDES ################################## //########################################################################### #include <math.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <X11/Xlib.h> #include <GL/glx.h> #include <GL/gl.h> #include <unistd.h> #include "graph.h" //########################################################################### //############################### DEFINES ################################### //########################################################################### #define ARG_FILENAME "/tmp/graph_args.txt" #define MAX_LINEARGS 2 #define MAX_FLOATARGS 2 #define MAX_FLOATS 20 #ifndef MAXFLOAT #define MAXFLOAT 3.40282347e+38F #endif //########################################################################### //############################### TYPEDEFS ################################## //########################################################################### typedef struct GWinLineNodeRec { struct GWinLineNodeRec *next; struct GWinLineNodeRec *prev; } GWinLineNode; typedef struct GWinLineRec { GWinLineNode node; int id; char *name; int hidden; int selected; float r,g,b; float xscale; float yscale; float xoffset; float yoffset; int vertCnt; int vertAlloc; float *verts; int step; GWinLineFuncInfo funcInfo; float curs_d; // used by cursor functions int curs_vert; // used by cursor functions } GWinLine; typedef struct GWinCursorRec { int is_vertical; float pos; float color[3]; struct GWinCursorRec *next; } GWinCursor; typedef struct GWinArgInfoRec { GWinArg arg; GWinArgDesc desc; struct GWinArgInfoRec *next; struct GWinArgInfoRec *prev; } GWinArgInfo; struct GWindowRec { Display *dpy; Window win; GLXContext gc; int loop; // 0=exit event loop int redraw; int resize; int recalc; int doubleBuffer; int argc; char **argv; char *name; float win_width; float win_height; float xmin, xmax, ymin, ymax; float border_x, border_y; float border_xmin, border_xmax, border_ymin, border_ymax; float disp_width, disp_height; float xscale, yscale; float xoffset, yoffset; float xoffset_max, yoffset_max; float x_drag_scale; float y_drag_scale; float bgcolor[3]; int iswidth; int isheight; GWinCBFunc cb_func; void *cb_data; GWinArgInfo argHead; GWinArgInfo *argCurrent; FILE *argFile; int x_drag, y_drag; int is_drag; GWinCursor *cursors; GWinCursor *curs_prev_v; GWinCursor *curs_current_v; GWinCursor *curs_prev_h; GWinCursor *curs_current_h; int selectLine; GWinLineNode line_head; GWinLine **lines; int lineCnt; int lineAlloc; int lineNameLen; }; typedef enum GWinPickFlagsEnum { GW_PICKFLG_NORMAL = 0, GW_PICKFLG_IGNORE_X = 0x00000001, GW_PICKFLG_IGNORE_Y = 0x00000002, GW_PICKFLG_INC_X = 0x00000004, GW_PICKFLG_DEC_X = 0x00000008, GW_PICKFLG_INC_Y = 0x00000010, GW_PICKFLG_DEC_Y = 0x00000020, GW_PICKFLG_NAMED = 0x00000040, // only named lines GW_PICKFLG_UNHIDDEN = 0x00000080, // only unhidden lines GW_PICKFLG_SELECTED = 0x00000100, // only selected line GW_PICKFLG_UNSELECTED = 0x00000200, // only unselected lines GW_PICKFLG_END } GWinPickFlags; //########################################################################### //############################### CODE ###################################### //########################################################################### //=========================================================================== // gwinLineGet() //=========================================================================== static GWinLine *gwinGetLine(GWindow *gw, int line) { if (line<0 || line>=gw->lineCnt) return 0; return gw->lines[line]; } //=========================================================================== // gwinMakeCurrent() //=========================================================================== static void gwinMakeCurrent(GWindow *gw) { glXMakeCurrent(gw->dpy,gw->win,gw->gc); } //=========================================================================== // gwinXYToWin() //=========================================================================== static float gwinXToWin(GWindow *gw, float x) { return (x - gw->border_xmin - gw->xoffset) / gw->x_drag_scale; } static float gwinYToWin(GWindow *gw, float y) { return (y - gw->border_ymin - gw->yoffset) / gw->y_drag_scale; } //=========================================================================== // gwinXYFromWin() //=========================================================================== static float gwinXFromWin(GWindow *gw, float x) { return x * gw->x_drag_scale + gw->border_xmin + gw->xoffset; } static float gwinYFromWin(GWindow *gw, float y) { return y * gw->y_drag_scale + gw->border_ymin + gw->yoffset; } //=========================================================================== // gwinCalcScales() //=========================================================================== void gwinCalcScales(GWindow *gw) { float ooxs = 1.0f/gw->xscale; float ooys = 1.0f/gw->yscale; float border_x = 0.05 * (gw->xmax - gw->xmin) * ooxs; float border_y = 0.05 * (gw->ymax - gw->ymin) * ooys; gw->border_xmin = gw->xmin - border_x; gw->border_xmax = gw->xmax + border_x; gw->border_ymin = gw->ymin - border_y; gw->border_ymax = gw->ymax + border_y; gw->disp_width = (gw->border_xmax - gw->border_xmin) * ooxs; gw->disp_height = (gw->border_ymax - gw->border_ymin) * ooys; gw->xoffset_max = (gw->border_xmax - gw->border_xmin) - gw->disp_width; gw->yoffset_max = (gw->border_ymax - gw->border_ymin) - gw->disp_height; gw->x_drag_scale = gw->disp_width / gw->win_width; gw->y_drag_scale = gw->disp_height / gw->win_height; gw->resize = 0; gw->redraw = 1; } //=========================================================================== // gwinFuncCalc() //=========================================================================== static void gwinFuncCalc(GWindow *gw, GWinLine *l) { int i; int min = 0; int max = 0; for (i=0; i<l->funcInfo.argCnt; i++) { if (l->funcInfo.args[i]->type == GW_ARGTYPE_LINE) { GWinArgLine *al = &l->funcInfo.args[i]->l; GWinLine *l2 = gwinGetLine(gw,al->line); if (l2) { al->vertCnt = l2->vertCnt; al->verts = l2->verts; } else { al->vertCnt = 0; al->verts = 0; } if (max == 0) { min = max = al->vertCnt; } else { min = min < al->vertCnt ? min : al->vertCnt; max = max > al->vertCnt ? max : al->vertCnt; } } } l->funcInfo.vertCntMin = min; l->funcInfo.vertCntMax = max; l->funcInfo.func(&l->funcInfo); for (i=0; i<l->vertCnt; i++) { float x = l->verts[i*2+0]; float y = l->verts[i*2+1]; gw->xmax = x > gw->xmax ? x : gw->xmax; gw->ymax = y > gw->ymax ? y : gw->ymax; gw->xmin = x < gw->xmin ? x : gw->xmin; gw->ymin = y < gw->ymin ? y : gw->ymin; } gw->resize = 1; } //=========================================================================== // gwinGlInit() //=========================================================================== static void gwinGlInit(GWindow *gw) { //glEnable(GL_DEPTH_TEST); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho( 0.0, 1.0, 0.0, 1.0, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glClearColor(gw->bgcolor[0], gw->bgcolor[1], gw->bgcolor[2], 1.0); } //=========================================================================== // gwinDraw() //=========================================================================== void gwinDraw(GWindow *gw) { int i; GWinLineNode *lnp; GWinCursor *curs; float disp_xmin, disp_ymin; gwinMakeCurrent(gw); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // // recalc functions // if (gw->recalc) { for (i=0; i<gw->lineCnt; i++) { GWinLine *l = gw->lines[i]; if (!l) continue; if (l->funcInfo.func) { gwinFuncCalc(gw, l); } } gw->recalc = 0; } // // resize so all lines fit on screen at scale=1 // if (gw->resize) { gwinCalcScales(gw); } glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (gw->xoffset < 0) gw->xoffset = 0; if (gw->yoffset < 0) gw->yoffset = 0; if (gw->xoffset > gw->xoffset_max) { gw->xoffset = gw->xoffset_max; } if (gw->yoffset > gw->yoffset_max) { gw->yoffset = gw->yoffset_max; } disp_xmin = gw->border_xmin + gw->xoffset; disp_ymin = gw->border_ymin + gw->yoffset; glOrtho( disp_xmin, disp_xmin + gw->disp_width, disp_ymin, disp_ymin + gw->disp_height, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glLineWidth(1.0); // // draw cursors // for (curs=gw->cursors; curs; curs = curs->next) { glBegin(GL_LINE_STRIP); { if (curs == gw->curs_current_v || curs == gw->curs_current_h) { glColor3f(1.0, 1.0, 1.0); } else if (curs == gw->curs_prev_v || curs == gw->curs_prev_h) { glColor3f(0.7, 0.7, 0.7); } else { glColor3f(curs->color[0],curs->color[1],curs->color[2]); } if (curs->is_vertical) { glVertex2f(curs->pos, gw->border_ymin); glVertex2f(curs->pos, gw->border_ymax); } else { glVertex2f(gw->border_xmin, curs->pos); glVertex2f(gw->border_xmax, curs->pos); } } glEnd(); } // // draw lines // for (lnp=gw->line_head.next; lnp != &gw->line_head; lnp=lnp->next) { GWinLine *l = (GWinLine*)lnp; float *vp = l->verts; float *vpe = vp + (l->vertCnt * 2); float svert[2]; int step = l->step; if (!l) continue; if (l->vertCnt < 2) continue; if (l->hidden) continue; glPushMatrix(); glTranslatef(l->xoffset, l->yoffset, 0.0f); glScalef(l->xscale, l->yscale, 1.0f); glLineWidth( l->selected ? 2.0 : 1.0); svert[0] = vp[0]; svert[1] = vp[1]; glBegin(GL_LINE_STRIP); { glColor3f(l->r, l->g, l->b); for (; vp != vpe; vp+=2) { if (step) { svert[0] = vp[0]; glVertex2fv(svert); svert[1] = vp[1]; } glVertex2fv(vp); } } glEnd(); glPopMatrix(); } glLineWidth(1.0); #if 0 // // ticks along bottom // for (i=0; ; i++) { float x = 0.1 * i; float y = (i % 10) ? 0.05 : 0.1; if (x > gw->xmax) break; glBegin(GL_LINE_STRIP); { glColor3f(0.0, 0.0, 0.0); glVertex2f(x, gw->ymin); glVertex2f(x, gw->ymin-y); } glEnd(); } // // ticks along left // for (i=0; ; i++) { float y = 0.1 * i; float x = (i % 10) ? 0.05 : 0.1; if (y > gw->ymax) break; glBegin(GL_LINE_STRIP); { glColor3f(0.0, 0.0, 0.0); glVertex2f(gw->xmin, y); glVertex2f(gw->xmin-x, y); } glEnd(); } #endif if (gw->doubleBuffer) { glXSwapBuffers(gw->dpy,gw->win); } else { glFlush(); } gw->redraw = 0; } //=========================================================================== // gwinLineToFront() //=========================================================================== void gwinLineToFront(GWindow *gw, int line) { GWinLine *l = gwinGetLine(gw,line); if (!l) return; l->node.next->prev = l->node.prev; l->node.prev->next = l->node.next; l->node.next = &gw->line_head; l->node.prev = gw->line_head.prev; l->node.next->prev = &l->node; l->node.prev->next = &l->node; } //=========================================================================== // gwinLineToBack() //=========================================================================== void gwinLineToBack(GWindow *gw, int line) { GWinLine *l = gwinGetLine(gw,line); if (!l) return; l->node.next->prev = l->node.prev; l->node.prev->next = l->node.next; l->node.next = gw->line_head.next; l->node.prev = &gw->line_head; l->node.next->prev = &l->node; l->node.prev->next = &l->node; } //=========================================================================== // gwinLineCreate() //=========================================================================== int gwinLineCreate(GWindow *gw) { int line; char name[100]; GWinLine *l = calloc(1,sizeof(GWinLine)); if (gw->lineCnt >= gw->lineAlloc) { gw->lineAlloc = gw->lineCnt + 10; gw->lines = realloc(gw->lines, gw->lineAlloc * sizeof(GWinLine*)); } line = gw->lineCnt++; gw->lines[line] = l; l->id = line; l->r = l->g = l->b = 1.0; l->vertAlloc = 10; l->verts = malloc(l->vertAlloc * 2 * sizeof(float)); l->xscale = 1.0; l->yscale = 1.0; l->step = 1; sprintf(name,"%d",gw->lineCnt); l->name = strdup(name); l->node.next = l->node.prev = &l->node; gwinLineToFront(gw,line); return line; } //=========================================================================== // gwinLineDelete() //=========================================================================== void gwinLineDelete(GWindow *gw, int line) { GWinLine *l = gwinGetLine(gw,line); if (!l) return; l->node.next->prev = l->node.prev; l->node.prev->next = l->node.next; if (l->verts) free(l->verts); if (l->name) free(l->name); gw->lines[line] = 0; free(l); } //=========================================================================== // gwinLineName() //=========================================================================== void gwinLineName(GWindow *gw, int line, const char *name) { int len = 0; GWinLine *l = gwinGetLine(gw,line); if (!l) return; if (l->name) free(l->name); l->name = 0; if (name) { #if 0 int l2 = gwinFindLine(gw, name); if (l2 >= 0) { fprintf(stderr,"WARNING: 2 lines named '%s'\n",name); } #endif l->name = strdup(name); len = strlen(name); } if (len > gw->lineNameLen) { gw->lineNameLen = len; } } //=========================================================================== // gwinLineStep() //=========================================================================== void gwinLineStep(GWindow *gw, int line, int step) { GWinLine *l = gwinGetLine(gw,line); if (!l) return; l->step = step; } //=========================================================================== // gwinLineScaleOffset() //=========================================================================== void gwinLineScaleOffset( GWindow *gw, int line, float xscale, float yscale, float xoffset, float yoffset) { GWinLine *l = gwinGetLine(gw,line); if (!l) return; l->xscale = xscale; l->yscale = yscale; l->xoffset = xoffset; l->yoffset = yoffset; } //=========================================================================== // gwinLineColor() //=========================================================================== void gwinLineColor(GWindow *gw, int line, int color) { GWinLine *l = gwinGetLine(gw,line); if (!l) return; l->r = ((color >> 16) & 0xff) * 1.0/255.0; l->g = ((color >> 8) & 0xff) * 1.0/255.0; l->b = ((color ) & 0xff) * 1.0/255.0; } //=========================================================================== // gwinLinePointFlags() //=========================================================================== void gwinLinePointFlags(GWindow *gw, int line, float x, float y, GWLineFlags flags) { GWinLine *l = gwinGetLine(gw,line); if (!l) return; if (l->vertCnt+1 >= l->vertAlloc) { l->vertAlloc = l->vertCnt*2 + 1000; l->verts = realloc(l->verts, l->vertAlloc * 2 * sizeof(float)); } // // GW_LFLG_STEPY: repeat last y value at new x value // if ((flags & GW_LFLG_STEPY) && l->vertCnt) { l->verts[l->vertCnt*2 + 0] = x; l->verts[l->vertCnt*2 + 1] = l->verts[(l->vertCnt-1)*2 + 1]; l->vertCnt++; } l->verts[l->vertCnt*2 + 0] = x; l->verts[l->vertCnt*2 + 1] = y; l->vertCnt++; x = x * l->xscale + l->xoffset; y = y * l->yscale + l->yoffset; if (x > gw->xmax) { gw->xmax = x; gw->resize = 1; } if (x < gw->xmin) { gw->xmin = x; gw->resize = 1; } if (y > gw->ymax) { gw->ymax = y; gw->resize = 1; } if (y < gw->ymin) { gw->ymin = y; gw->resize = 1; } gw->redraw = 1; if ((l->vertCnt %100)==0) { gwinDraw(gw); } } //=========================================================================== // gwinLinePoint() //=========================================================================== void gwinLinePoint(GWindow *gw, int line, float x, float y) { gwinLinePointFlags(gw,line,x,y,0); } //=========================================================================== // gwinLinePointStep() //=========================================================================== void gwinLinePointStep(GWindow *gw, int line, float x, float y) { gwinLinePointFlags(gw,line,x,y,1); } //=========================================================================== // gwinLineHide() //=========================================================================== void gwinLineHide(GWindow *gw, int line, int hidden) { GWinLine *l = gwinGetLine(gw,line); if (l) l->hidden = hidden; gw->redraw = 1; } //=========================================================================== // gwinLineFuncVerts() - set cnt and get pointer //=========================================================================== float *gwinLineFuncVerts(GWinLineFuncInfo *info, int cnt) { GWinLine *l = gwinGetLine(info->gw,info->line); if (!l) { // // return dummy array // static float *dummy = 0; static int dummy_cnt = -1; if (dummy_cnt < cnt || !dummy) { if (dummy) free(dummy); cnt += 100; if (cnt<100) cnt = 100; dummy_cnt = dummy_cnt > cnt ? dummy_cnt : cnt; dummy = malloc(dummy_cnt * 2 * sizeof(float)); } return dummy; } if (cnt > l->vertAlloc) { float *ptr = realloc(l->verts, cnt * 2 * sizeof(float)); if (!ptr) return 0; l->verts = ptr; l->vertAlloc = cnt; } l->vertCnt = cnt; return l->verts; } //=========================================================================== // gwinFindLine() //=========================================================================== int gwinFindLine(GWindow *gw, const char *name) { int i; for (i=0; i<gw->lineCnt; i++) { GWinLine *l = gw->lines[i]; if (!l) continue; if (!l->name) continue; if (!strcmp(name,l->name)) return i; } return -1; } //=========================================================================== // gwinArgCreate() //=========================================================================== GWinArg *gwinArgCreate(GWindow *gw, int line, GWinArgDesc *args) { GWinArgInfo *ai; for (ai=gw->argHead.next; ai!=&gw->argHead; ai=ai->next) { if (!strcmp(ai->desc.name, args->name) && args->type == GW_ARGTYPE_VAR && ai->desc.type == GW_ARGTYPE_VAR) { return &ai->arg; } } ai = calloc(1, sizeof(GWinArgInfo)); ai->arg.type = args->type; switch(ai->arg.type) { case GW_ARGTYPE_VAR: ai->arg.v.val = args->init; gw->argCurrent = ai; break; case GW_ARGTYPE_LINE: ai->arg.l.line = gwinFindLine(gw,args->name); break; default: free(ai); return 0; } ai->desc = *args; ai->desc.name = strdup(args->name); ai->prev = gw->argHead.prev; ai->next = &gw->argHead; ai->prev->next = ai; ai->next->prev = ai; gw->recalc = 1; gw->redraw = 1; return &ai->arg; } //=========================================================================== // gwinLineFunc() //=========================================================================== void gwinLineFunc(GWindow *gw, int line, GWinLineFunc func, GWinArgDesc *args) { GWinArgDesc args1[1] = {{0,}}; int cnt; GWinLine *l = gwinGetLine(gw,line); if (!l) return; if (!args) args = args1; for (cnt=0; args[cnt].type; cnt++); l->funcInfo.gw = gw; l->funcInfo.line = line; l->funcInfo.func = func; l->funcInfo.argCnt = cnt; l->funcInfo.args = calloc(cnt+1,sizeof(GWinArg*)); for (cnt=0; args[cnt].type; cnt++) { l->funcInfo.args[cnt] = gwinArgCreate(gw, line, &args[cnt]); } gw->recalc = 1; gw->redraw = 1; } //=========================================================================== // gwinCreate() //=========================================================================== GWindow *gwinCreate(void) { static char *fakeArgs[] = { "program", 0 }; GWindow *gw = calloc(1,sizeof(GWindow)); gw->redraw = 1; gw->resize = 1; gw->doubleBuffer = 1; gw->argc = 1; gw->argv = fakeArgs; gw->name = strdup(fakeArgs[0]); gw->lineAlloc = 10; gw->lines = malloc(gw->lineAlloc * sizeof(GWinLine*)); gw->xmin = 1.0; gw->xmax = -1.0; gw->ymin = 0.0; gw->ymax = 0.0; gw->xscale = 1.0; gw->yscale = 1.0; gw->win_width = 1; gw->win_height = 1; gw->resize = 1; gw->lineNameLen = 4; gw->selectLine = -1; gw->iswidth = 300; gw->isheight = 300; gw->bgcolor[0] = .2; gw->bgcolor[1] = .3; gw->bgcolor[2] = .1; gw->line_head.next = gw->line_head.prev = &gw->line_head; gw->argHead.next = gw->argHead.prev = &gw->argHead; gw->argFile = fopen(ARG_FILENAME,"r"); if (!gw->argFile) { gw->argFile = fopen(ARG_FILENAME,"w"); if (gw->argFile) { fclose(gw->argFile); gw->argFile = fopen(ARG_FILENAME,"r"); } } return gw; } //=========================================================================== // gwinDelete() //=========================================================================== void gwinDelete(GWindow *gw) { int i; for (i=0; i<gw->lineCnt; i++) { gwinLineDelete(gw,i); } if (gw->lines) free(gw->lines); if (gw->name) free(gw->name); // // todo: destroy window // free(gw); } //=========================================================================== // gwinSetArgs() //=========================================================================== void gwinSetArgs(GWindow *gw, int argc,char *argv[]) { gw->argc = argc; gw->argv = argv ? argv : gw->argv; } //=========================================================================== // gwinSetName() //=========================================================================== void gwinSetName(GWindow *gw, const char *name) { if (gw->name) free(gw->name); gw->name = strdup(name); } //=========================================================================== // gwinSetISize() - initial size //=========================================================================== void gwinSetISize(GWindow *gw, int w, int h) { gw->iswidth = w; gw->isheight = h; } //=========================================================================== // gwinSetRange() //=========================================================================== void gwinSetRange(GWindow *gw, float min, float max) { gw->xmin = min; gw->xmax = max; } //=========================================================================== // gwinSetDomain() //=========================================================================== void gwinSetDomain(GWindow *gw, float min, float max) { gw->ymin = min; gw->ymax = max; } //=========================================================================== // gwinDestroy() //=========================================================================== void gwinDestroy(GWindow *gw) { } //=========================================================================== // gwinOpen() //=========================================================================== void gwinOpen(GWindow *gw) { XVisualInfo *vi; Colormap cmap; XSetWindowAttributes swa; int dummy; char *name; static int sbuf[] = { GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, GLX_DEPTH_SIZE, 12, None}; static int dbuf[] = { GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, GLX_DEPTH_SIZE, 12, GLX_DOUBLEBUFFER, None}; // open X server connection gw->dpy = XOpenDisplay(NULL); if (gw->dpy == NULL) { fprintf(stderr,"Could not open display"); gwinDestroy(gw); return; } // check for GLX extension if (!glXQueryExtension(gw->dpy,&dummy,&dummy)) { fprintf(stderr,"X server has no OpenGL GLX extension"); gwinDestroy(gw); return; } // get visual vi = glXChooseVisual(gw->dpy,DefaultScreen(gw->dpy),dbuf); if (vi == NULL) { vi = glXChooseVisual(gw->dpy,DefaultScreen(gw->dpy),sbuf); if (vi == NULL) { fprintf(stderr,"No RGB visual with depth buffer"); gwinDestroy(gw); return; } gw->doubleBuffer = 0; } if (vi->class != TrueColor) { fprintf(stderr,"TrueColor visual required and not found"); gwinDestroy(gw); return; } // create openGL rendering context gw->gc = glXCreateContext(gw->dpy,vi, None, // do not share display lists True); // direct rendering if possible if (gw->gc == NULL) { fprintf(stderr,"could not create rendering context"); gwinDestroy(gw); return; } name = gw->name ? gw->name : (gw->argv && gw->argv[0]) ? gw->argv[0] : "graph"; // create X window and color map cmap = XCreateColormap(gw->dpy,RootWindow(gw->dpy,vi->screen), vi->visual,AllocNone); swa.colormap = cmap; swa.border_pixel = 0; swa.event_mask = ExposureMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | Button1MotionMask | EnterWindowMask | StructureNotifyMask; gw->win = XCreateWindow(gw->dpy, RootWindow(gw->dpy,vi->screen), 0,0,gw->iswidth,gw->isheight, 0,vi->depth, InputOutput, vi->visual, CWBorderPixel | CWColormap | CWEventMask, &swa); XSetStandardProperties(gw->dpy,gw->win, name,name, None,gw->argv,gw->argc,NULL); // bind context to window glXMakeCurrent(gw->dpy,gw->win,gw->gc); // display window XMapWindow(gw->dpy,gw->win); // config openGL gwinGlInit(gw); } //=========================================================================== // gwinLinePickPointSub() //=========================================================================== static void gwinLinePickPointSub( GWinPickInfo *info, int line, float win_x, float win_y, unsigned int flags) // from enum GWinPickFlagsEnum { int j; GWindow *gw = info->gw; GWinLine *l = gwinGetLine(gw,line); float sx,ox,sy,oy; if (!l) return; if (l->vertCnt < 1) return; if (!l->name && (flags & GW_PICKFLG_NAMED)) return; if (l->hidden && (flags & GW_PICKFLG_UNHIDDEN)) return; if (l->selected) { if (flags & GW_PICKFLG_UNSELECTED) return; } else { if (flags & GW_PICKFLG_SELECTED) return; } if (info->win_dist_squared < 0) { info->win_dist_squared = MAXFLOAT; } sx = l->xscale / gw->x_drag_scale; ox = (l->xoffset - gw->border_xmin - gw->xoffset) / gw->x_drag_scale; sy = l->yscale / gw->y_drag_scale; oy = (l->yoffset - gw->border_ymin - gw->yoffset) / gw->y_drag_scale; ox -= win_x; oy -= win_y; if (flags & GW_PICKFLG_IGNORE_X) { ox = sx = 0.0; } if (flags & GW_PICKFLG_IGNORE_Y) { oy = sy = 0.0; } flags &= GW_PICKFLG_INC_X | GW_PICKFLG_DEC_X | GW_PICKFLG_INC_Y | GW_PICKFLG_DEC_Y; for (j=0; j<l->vertCnt; j++) { float dx = ox + sx * l->verts[j*2+0]; float dy = oy + sy * l->verts[j*2+1]; float d = dx * dx + dy * dy; if (d >= info->win_dist_squared) continue; if (flags) { if (flags & (GW_PICKFLG_INC_X|GW_PICKFLG_DEC_X)) { float pos = l->verts[j*2+0] * l->xscale + l->xoffset; if ((flags & GW_PICKFLG_INC_X) && pos <= info->old_pos) { continue; } if ((flags & GW_PICKFLG_DEC_X) && pos >= info->old_pos) { continue; } } if (flags & (GW_PICKFLG_INC_Y|GW_PICKFLG_DEC_Y)) { float pos = l->verts[j*2+1] * l->yscale + l->yoffset; if ((flags & GW_PICKFLG_INC_Y) && pos <= info->old_pos) { continue; } if ((flags & GW_PICKFLG_DEC_Y) && pos >= info->old_pos) { continue; } } } info->line = line; info->vert = j; info->win_dist_squared = d; info->win_x = dx + win_x; info->win_y = dy + win_y; } } //=========================================================================== // gwinLinePickPoint() //=========================================================================== int gwinLinePickPoint( GWindow *gw, int line, GWinPickInfo *info, float win_x, float win_y, unsigned int flags) // from GWinPickFlagsEnum { info->gw = gw; info->line = -1; info->vert = -1; info->win_x = win_x; info->win_y = win_y; info->win_dist_squared = MAXFLOAT; gwinLinePickPointSub(info, line, win_x, win_y, flags); return (info->win_dist_squared < MAXFLOAT); } //=========================================================================== // gwinPickPoint() //=========================================================================== int gwinPickPoint( GWindow *gw, GWinPickInfo *info, float win_x, float win_y, unsigned int flags) // from GWinPickFlagsEnum { GWinLineNode *lnp; info->gw = gw; info->line = -1; info->vert = -1; info->win_x = win_x; info->win_y = win_y; info->win_dist_squared = MAXFLOAT; for (lnp=gw->line_head.prev; lnp != &gw->line_head; lnp=lnp->prev) { GWinLine *l = (GWinLine*)lnp; gwinLinePickPointSub(info, l->id, win_x, win_y, flags); } return (info->win_dist_squared < MAXFLOAT); } //=========================================================================== // gwinCursorPrintLine() //=========================================================================== static void gwinCursorPrintLine( GWindow *gw, GWinCursor *curs, int line, float x, float y) { int r,g,b; GWinLine *l = gw->lines[line]; if (!l->name) return; r = l->r * 255; g = l->g * 255; b = l->b * 255; r = r<0?0:r>255?255:r; g = g<0?0:g>255?255:g; b = b<0?0:b>255?255:b; r = (r<<16)|(g<<8)|b; printf("Cursor: [%2d] %-*s x=%10.6f y=%10.6f %06x\n", line, gw->lineNameLen,l->name, x, y, r); } //=========================================================================== // gwinCursorPrint() //=========================================================================== static void gwinCursorPrint(GWindow *gw, GWinCursor *curs) { GWinCursor *curs2; GWinPickInfo info[1]; int i; unsigned int flags = 0; float win_x = 0; float win_y = 0; float dmin = MAXFLOAT; int n=0; memset(info,0,sizeof(info[0])); info->gw = gw; if (curs->is_vertical) { if (curs->pos > gw->xmax) { curs->pos = gw->xmax; gw->redraw = 1; } if (curs->pos < gw->xmin) { curs->pos = gw->xmin; gw->redraw = 1; } win_x = gwinXToWin(gw,curs->pos); flags |= GW_PICKFLG_IGNORE_Y; } else { if (curs->pos > gw->ymax) { curs->pos = gw->ymax; gw->redraw = 1; } if (curs->pos < gw->ymin) { curs->pos = gw->ymin; gw->redraw = 1; } win_y = gwinYToWin(gw,curs->pos); flags |= GW_PICKFLG_IGNORE_X; } // // find closest point on each line // for (i=0; i<gw->lineCnt; i++) { GWinLine *l = gw->lines[i]; if (!l) continue; if (gw->selectLine >= 0 && !l->selected) continue; info->win_dist_squared = MAXFLOAT; info->line = -1; gwinLinePickPointSub(info, i, win_x, win_y, flags); l->curs_d = info->win_dist_squared; l->curs_vert = info->vert; dmin = dmin < l->curs_d ? dmin : l->curs_d; } // // print line points near cursor // if (dmin <= 4) { for (i=0; i<gw->lineCnt; i++) { int line; GWinLine *l = gw->lines[i]; int j; if (!l) continue; if (!l->name) continue; if (l->curs_d < 0) continue; if (l->curs_d > dmin) continue; line = i; for (j=i+1; j<gw->lineCnt; j++) { GWinLine *l2 = gw->lines[j]; if (!l2) continue; if (l2->curs_d < 0) continue; if (!l2->name) continue; if (strcmp(l->name, l2->name)) continue; if (l2->curs_d < l->curs_d) { l->curs_d = -1.0; l = l2; line = j; } else { l2->curs_d = -1.0; } } gwinCursorPrintLine( gw, curs, line, l->verts[l->curs_vert*2+0], l->verts[l->curs_vert*2+1]); n++; l->curs_d = -1.0; } } for (curs2=gw->cursors; curs2; curs2 = curs2->next) { if (curs2 == curs) continue; if (curs2->is_vertical != curs->is_vertical) continue; printf("Delta %s: %10.6f\n", curs->is_vertical ? "x" : "y", curs->pos - curs2->pos); } if (!n) { printf("Cursor: %s=%10.6f\n", curs->is_vertical ? "x" : "y", curs->pos); } printf("\n"); } //=========================================================================== // gwinCursorSnap() //=========================================================================== // // showinfo: // 0 = never // 1 = if x changes // 2 = always // void gwinCursorSnap(GWindow *gw, GWinCursor *curs, int inc, int showinfo, float win_x, float win_y) { float pos; GWinPickInfo info[1]; GWinLine *l; unsigned int flags = GW_PICKFLG_NAMED; if (inc) { info->old_pos = curs->pos; if (curs->is_vertical) { win_x = gwinXToWin(gw, curs->pos); win_y = 0; flags |= (inc < 0) ? GW_PICKFLG_DEC_X : GW_PICKFLG_INC_X; flags |= GW_PICKFLG_IGNORE_Y; } else { win_x = 0; win_y = gwinYToWin(gw, curs->pos); flags |= (inc < 0) ? GW_PICKFLG_DEC_Y : GW_PICKFLG_INC_Y; flags |= GW_PICKFLG_IGNORE_X; } } else { if (curs->is_vertical) { flags |= GW_PICKFLG_IGNORE_Y; } } gwinPickPoint(gw, info, win_x, win_y, flags); l = gwinGetLine(gw,info->line); if (!l) { if (showinfo == 2) { printf("No vertex found\n"); } return; } if (curs->is_vertical) { pos = l->verts[info->vert*2+0] * l->xscale + l->xoffset; pos = pos > gw->xmin ? pos : gw->xmin; pos = pos < gw->xmax ? pos : gw->xmax; } else { pos = l->verts[info->vert*2+1] * l->yscale + l->yoffset; pos = pos > gw->ymin ? pos : gw->ymin; pos = pos < gw->ymax ? pos : gw->ymax; } if (curs->pos != pos) { curs->pos = pos; gw->redraw = 1; } else if (showinfo == 1) { return; } if (!showinfo) return; gwinCursorPrint(gw, curs); } //=========================================================================== // gwinCursorMove() //=========================================================================== void gwinCursorMove(GWindow *gw, GWinCursor *curs, float pos) { curs->pos = pos; gw->redraw = 1; } //=========================================================================== // gwinCursorCreate() //=========================================================================== GWinCursor *gwinCursorCreate(GWindow *gw, int vertical, float x, float y, float r, float g, float b) { GWinCursor *curs = calloc(1,sizeof(GWinCursor)); curs->is_vertical = vertical; curs->color[0] = r; curs->color[1] = g; curs->color[2] = b; curs->next = gw->cursors; gw->cursors= curs; gw->redraw = 1; if (vertical) { if (gw->curs_current_v) { gw->curs_prev_v = gw->curs_current_v; } gw->curs_current_v = curs; curs->pos = x; } else { if (gw->curs_current_h) { gw->curs_prev_h = gw->curs_current_h; } gw->curs_current_h = curs; curs->pos = y; } return curs; } //=========================================================================== // gwinCursorGetCurrent() //=========================================================================== GWinCursor *gwinCursorGetCurrent(GWindow *gw, int vertical) { GWinCursor *curs = vertical ? gw->curs_current_v : gw->curs_current_h; if (!curs) { curs = gwinCursorCreate(gw,vertical, (gw->xmax + gw->xmin) * 0.5, (gw->ymax + gw->ymin) * 0.5, 0,0,0); } return curs; } //=========================================================================== // gwinCursorDelete() //=========================================================================== void gwinCursorDelete(GWindow *gw,GWinCursor *curs) { GWinCursor **p = &gw->cursors; while(*p) { if (*p == curs) { *p = curs->next; break; } p = &(*p)->next; } if (gw->curs_current_h == curs) { gw->curs_current_h = 0; } if (gw->curs_current_v == curs) { gw->curs_current_v = 0; } free(curs); gw->redraw = 1; } //=========================================================================== // gwinLineSelect() //=========================================================================== void gwinLineSelect(GWindow *gw, int line, int quiet) { GWinLine *l = gwinGetLine(gw,line); float xmin, xmax; float ymin, ymax; double xsum, ysum; float *vp; GWinPickInfo info[1]; int i; gw->redraw = 1; if (!l) { if (!quiet) { printf("No line selected\n"); } gw->selectLine = -1; for (i=0; i<gw->lineCnt; i++) { GWinLine *l2 = gw->lines[i]; if (l2) { l2->selected = 0; } } return; } printf("Select line [%d] %s\n", line, l->name); gw->selectLine = line; for (i=0; i<gw->lineCnt; i++) { GWinLine *l2 = gw->lines[i]; if (!l2 || l2 == l) { } if (!l->name || !l2->name || strcmp(l2->name, l->name)) { l2->selected = 0; } else { l2->selected = 1; gwinLineToFront(gw, l2->id); } } l->selected = 1; gwinLineToFront(gw, line); if (quiet) return; if (gw->curs_prev_v && gwinLinePickPoint( gw, line, info, gw->curs_prev_v->pos, 0, GW_PICKFLG_IGNORE_Y)) { gwinCursorPrintLine( gw, gw->curs_prev_v, line, l->verts[info->vert*2+0], l->verts[info->vert*2+1]); } if (gw->curs_current_v && gwinLinePickPoint( gw, line, info, gw->curs_current_v->pos, 0, GW_PICKFLG_IGNORE_Y)) { gwinCursorPrintLine( gw, gw->curs_current_v, line, l->verts[info->vert*2+0], l->verts[info->vert*2+1]); } if (!gw->curs_current_v) return; if (!gw->curs_prev_v) return; xmax = gw->curs_current_v->pos; xmin = gw->curs_prev_v->pos; printf(" dx = %10.6f\n",xmax-xmin); if (xmin > xmax) { float t = xmax; xmax = xmin; xmin = t; } ymin = 1.0; ymax = -1.0; vp = l->verts; for (i=0; i<l->vertCnt; i++, vp+=2) { float x = vp[0]; float y = vp[1]; float xn = vp[0]; float yn = vp[1]; float dx = 0; if (i<l->vertCnt-1) { xn = vp[2]; yn = vp[3]; if (x < xn) { dx = xn-x; } } if (xn >= xmin && x <= xmax) { if (ymin > ymax) { ymin = ymax = y; ysum = y * dx; xsum = dx; } else { ymin = (ymin<y)?ymin:y; ymax = (ymax>y)?ymax:y; ysum += y * dx; xsum += dx; } } } if (ymin <= ymax) { printf(" ymax = %10.6f\n",ymax); printf(" ymed = %10.6f\n",(ymax+ymin)*0.5); printf(" ymin = %10.6f\n",ymin); if (xsum <= 0) { ysum = 0; xsum = 1; } printf(" yavg = %10.6f\n",ysum/xsum); } } //=========================================================================== // gwinSetCallback() //=========================================================================== void gwinSetCallback(GWindow *gw, GWinCBFunc func, void *data) { gw->cb_func = func; gw->cb_data = data; } //=========================================================================== // gwinHandleEvent() - handle one event //=========================================================================== // Note: call gwinMakeCurrent before calling this static void gwinHandleEvent(GWindow *gw, XEvent *event) { GWinCursor *curs; static int event_debug = 0; float wx, wy, pos; switch(event->type) { case ConfigureNotify: glViewport(0,0, event->xconfigure.width, event->xconfigure.height); gw->win_width = event->xconfigure.width; gw->win_height = event->xconfigure.height; gw->resize = 1; gw->redraw = 1; break; case KeyPress: if (event_debug) { printf("Event: key pressed state=0x%08x code=0x%0x\n", event->xkey.state, event->xkey.keycode); } break; case KeyRelease: if (event_debug) { printf("Event: key released state=0x%08x code=0x%0x\n", event->xkey.state, event->xkey.keycode); } if (gw->resize) { gwinCalcScales(gw); } switch(event->xkey.keycode) { case 0x3d: // ? or / printf("\n\n" " Key commands\n" " ------------\n" " q quit\n" " l run callback func (look)\n" " x/X zoom in/out x\n" " y/Y zoom in/out y\n" " z reset zoom\n" " c center graph\n" " v vertical cursor (V=save)\n" " h horizontal cursor (H=save)\n" " s/S select/unselect line\n" " o/O obscure selected (O=unobscure all)\n" " -> cursor right\n" " <- cursor left\n" " e erase black cursors\n" " E erase all cursors\n" " f/F put selected line in front/back\n" " 1-9 choose float variable to modify\n" " </> modify float variable\n" " ? help (/ works too)\n" " ; toggle event debug mode\n" ); break; case 0x2f: // ; event_debug = !event_debug; break; case 0x2e: // l if (gw->cb_func) { gw->cb_func(gw,gw->cb_data); } break; case 0x62: // up arrow curs = gwinCursorGetCurrent(gw, 0); if (event->xkey.state & 4) { if (event->xkey.state & 1) { curs->pos += gw->y_drag_scale * 10; } else { curs->pos += gw->y_drag_scale; } gwinCursorPrint(gw,curs); gw->redraw = 1; } else { gwinCursorSnap(gw, curs, 1, 2, 0,0); } break; case 0x68: // down curs = gwinCursorGetCurrent(gw, 0); if (event->xkey.state & 4) { if (event->xkey.state & 1) { curs->pos -= gw->y_drag_scale * 10; } else { curs->pos -= gw->y_drag_scale; } gwinCursorPrint(gw,curs); gw->redraw = 1; } else { gwinCursorSnap(gw, curs, -1, 2, 0,0); } break; case 0x66: // -> curs = gwinCursorGetCurrent(gw, 1); if (event->xkey.state & 4) { if (event->xkey.state & 1) { curs->pos += gw->x_drag_scale * 10; } else { curs->pos += gw->x_drag_scale; } gwinCursorPrint(gw,curs); gw->redraw = 1; } else { gwinCursorSnap(gw, curs, 1, 2, 0,0); } break; case 0x64: // <- curs = gwinCursorGetCurrent(gw, 1); if (event->xkey.state & 4) { if (event->xkey.state & 1) { curs->pos -= gw->x_drag_scale * 10; } else { curs->pos -= gw->x_drag_scale; } gwinCursorPrint(gw,curs); gw->redraw = 1; } else { gwinCursorSnap(gw, curs, -1, 2, 0,0); } break; case 0x18: // q gw->loop = 0; break; case 0x34: // z gw->xscale = 1.0; gw->yscale = 1.0; gw->xoffset = 0; gw->yoffset = 0; gw->redraw = 1; gw->resize = 1; break; case 0x35: // x wx = event->xkey.x; pos = gwinXFromWin(gw, wx); if (event->xkey.state & 1) { gw->xscale *= 0.8f; if (gw->xscale < 1.0) gw->xscale = 1.0; } else { gw->xscale *= 1.25; } gwinCalcScales(gw); gw->xoffset -= gwinXFromWin(gw, wx) - pos; gw->redraw = 1; break; case 0x1d: // y wy = gw->win_height - event->xkey.y; pos = gwinYFromWin(gw, wy); if (event->xkey.state & 1) { gw->yscale *= 0.8f; if (gw->yscale < 1.0) gw->yscale = 1.0; } else { gw->yscale *= 1.25; } gwinCalcScales(gw); gw->yoffset -= gwinYFromWin(gw, wy) - pos; gw->redraw = 1; break; case 0x36: // c gw->xoffset = gw->xoffset_max * 0.5;; gw->yoffset = gw->yoffset_max * 0.5;; gw->redraw = 1; break; case 0x1a: // e if (event->xkey.state & 1) { while(gw->cursors) { gwinCursorDelete(gw,gw->cursors); } } else { GWinCursor *curs = gw->cursors; while(curs) { if (curs == gw->curs_current_h || curs == gw->curs_current_v || curs == gw->curs_prev_h || curs == gw->curs_prev_v) { curs = curs->next; } else { gwinCursorDelete(gw,curs); curs = gw->cursors; } } } break; case 0x38: // b if (gw->curs_current_v) { gw->curs_prev_v = gw->curs_current_v; } gw->curs_current_v = 0; gw->redraw = 1; break; case 0x37: // v wx = event->xkey.x; wy = gw->win_height - event->xkey.y; curs = gwinCursorGetCurrent(gw, 1); gwinCursorSnap(gw, curs, 0, 1, wx, wy); break; case 0x2c: // j if (gw->curs_current_h) { gw->curs_prev_h = gw->curs_current_h; } gw->curs_current_h = 0; gw->redraw = 1; break; case 0x2b: // h wx = event->xkey.x; wy = gw->win_height - event->xkey.y; curs = gwinCursorGetCurrent(gw, 0); gwinCursorSnap(gw, curs, 0, 1, wx, wy); break; case 0x29: // f wx = event->xkey.x; wy = gw->win_height - event->xkey.y; { int line = gw->selectLine; if (line < 0) { GWinPickInfo info[1]; gwinPickPoint(gw,info,wx,wy,0); line = info->line; } if (line < 0) { printf("No line found\n"); } else { GWinLine *l = gwinGetLine(gw,line); int toback = event->xkey.state & 1; if (l == (GWinLine*)gw->line_head.prev) { toback = 1; } printf("Move line [%d] %s to ", line, gw->lines[line]->name); if (l && l->name) { int i; for (i=0; i<gw->lineCnt; i++) { GWinLine *l2 = gw->lines[i]; if (!l || l2 == l) { } if (!l->name || strcmp(l2->name, l->name)) { } else { if (toback) { gwinLineToBack(gw, l2->id); } else { gwinLineToFront(gw, l2->id); } } } } if (toback) { printf("Back\n"); gwinLineToBack(gw, line); } else { printf("Front\n"); gwinLineToFront(gw, line); } gw->redraw = 1; } } break; case 0x27: // s select wx = event->xkey.x; wy = gw->win_height - event->xkey.y; gw->redraw = 1; if ((event->xkey.state & 1) == 0) { GWinPickInfo info[1]; int flags = GW_PICKFLG_UNHIDDEN | GW_PICKFLG_UNSELECTED; if ((event->xkey.state & 4)==0) { flags |= GW_PICKFLG_NAMED; } gwinPickPoint(gw,info,wx,wy,flags); gwinLineSelect(gw,info->line,0); } else { gwinLineSelect(gw,-1,0); } break; case 0x20: // o obscure if (event->xkey.state & 1) { int i; for (i=0; i<gw->lineCnt; i++) { gwinLineHide(gw, i, 0); } } else if (gw->selectLine != -1) { int i; for (i=0; i<gw->lineCnt; i++) { GWinLine *l2 = gw->lines[i]; if (l2 && l2->selected) { l2->selected = 0; gwinLineHide(gw, l2->id, 1); } } gw->selectLine = -1; } break; case 0x14: if (gw->argCurrent) { GWinArgInfo *ai = gw->argCurrent->prev; while(ai->arg.type != GW_ARGTYPE_VAR && ai != gw->argCurrent) ai = ai->prev; printf("Modify arg: %s\n",ai->desc.name); } break; case 0x15: if (gw->argCurrent) { GWinArgInfo *ai = gw->argCurrent->next; while(ai->arg.type != GW_ARGTYPE_VAR && ai != gw->argCurrent) ai = ai->next; printf("Modify arg: %s\n",ai->desc.name); } break; case 0x3b: if (gw->argCurrent && gw->argCurrent->arg.type == GW_ARGTYPE_VAR) { GWinArgInfo *ai = gw->argCurrent; ai->arg.v.val *= 0.8; printf("current var: %s = %10.5f\n", ai->desc.name, ai->arg.v.val); gw->recalc = 1; gw->redraw = 1; } break; case 0x3c: if (gw->argCurrent && gw->argCurrent->arg.type == GW_ARGTYPE_VAR) { GWinArgInfo *ai = gw->argCurrent; ai->arg.v.val *= 1.25; printf("current var: %s = %10.5f\n", ai->desc.name, ai->arg.v.val); gw->recalc = 1; gw->redraw = 1; } break; case 0x22: gw->xoffset -= gw->x_drag_scale * (gw->win_width * 0.1); gw->redraw = 1; break; case 0x23: gw->xoffset += gw->x_drag_scale * (gw->win_width * 0.1); gw->redraw = 1; break; } break; case ButtonPress: wx = event->xbutton.x; wy = gw->win_height - event->xbutton.y; if (event_debug) { printf("Event: button pressed state=0x%08x butn=0x%0x " "x=%-4d y=%d\n", event->xbutton.state, event->xbutton.button, (int)wx,(int)wy); } if (event->xbutton.button == 1) { gw->x_drag = wx; gw->y_drag = wy; gw->is_drag = 1; } break; case ButtonRelease: wx = event->xbutton.x; wy = gw->win_height - event->xbutton.y; if (event_debug) { printf("Event: button released state=0x%08x butn=0x%0x " "x=%-4d y=%d\n", event->xbutton.state, event->xbutton.button, (int)wx,(int)wy); } if (!gw->is_drag) { break; } gw->is_drag = 0; if (0) { case MotionNotify: wx = event->xmotion.x; wy = gw->win_height - event->xmotion.y; if (event_debug) { printf("Event: pointer moved x=%d y=%d hint=%d\n", (int)wx, (int)wy, event->xmotion.is_hint); } if (gw->resize) { gwinCalcScales(gw); } } gw->xoffset += gw->x_drag_scale * (gw->x_drag - wx); gw->yoffset += gw->y_drag_scale * (gw->y_drag - wy); gw->x_drag = wx; gw->y_drag = wy; gw->redraw = 1; break; case Expose: gw->redraw = 1; break; } } //=========================================================================== // gwinHandleArgFile() - read arg file //=========================================================================== void gwinHandleArgFile(GWindow *gw) { if (gw->argFile) { while(1) { int c = getc(gw->argFile); if (c == EOF) break; printf("file:%c\n",c); gw->redraw = 1; } } } //=========================================================================== // gwinHandleEvents() - handle pending events and then return //=========================================================================== void gwinHandleEvents(GWindow *gw) { XEvent event; gwinMakeCurrent(gw); while(XPending(gw->dpy)) { XNextEvent(gw->dpy, &event); gwinHandleEvent(gw,&event); } #if 0 gwinHandleArgFile(gw); #endif if (gw->redraw) { gwinDraw(gw); } } //=========================================================================== // gwinEventLoop() - wait for events and handle them //=========================================================================== void gwinEventLoop(GWindow *gw) { XEvent event; gwinMakeCurrent(gw); gw->loop = 1; while(gw->loop) { while(XPending(gw->dpy)) { XNextEvent(gw->dpy, &event); gwinHandleEvent(gw,&event); } if (!gw->loop) break; if (gw->redraw) { gwinDraw(gw); } #if 0 gwinHandleArgFile(gw); #endif XNextEvent(gw->dpy, &event); gwinHandleEvent(gw,&event); } } #ifdef GRAPHTEST //=========================================================================== // main() //=========================================================================== int main(int argc, char *argv[]) { int la; int lb; int lc; GWindow *gw = gwinCreate(); gwinSetArgs(gw, argc,argv); gwinOpen(gw); la = gwinLineCreate(gw); gwinLineColor(gw,la,0xff00ff); gwinLinePoint(gw,la,0.0,0.0); gwinLinePoint(gw,la,0.3,0.4); gwinLinePoint(gw,la,0.4,0.2); gwinLinePoint(gw,la,0.5,0.2); gwinLinePoint(gw,la,0.7,0.5); lb = gwinLineCreate(gw); gwinLineColor(gw,lb,0x0000ff); gwinLinePoint(gw,lb,0.0,0.2); gwinLinePoint(gw,lb,0.9,0.4); gwinLinePoint(gw,lb,2.4,0.2); lc = gwinLineCreate(gw); gwinLineColor(gw,lc,0xffff00); gwinLinePoint(gw,lc,0.0,0.9); gwinLinePoint(gw,lc,0.8,0.4); gwinLinePoint(gw,lc,1.4,0.2); while(1) { gwinHandleEvents(gw); usleep(1000000); } return 0; } #endif |
This file Copyright (C) 2006 by Nathan (Acorn) Pooley
Go to TOP Wand page
Go to Acorn's personal webpage
Go to Hogwarts website: www.gotohogwarts.com
Snout: www.snout.org/game
Gadgets of Justice Unlimited
Snout GC (Wiki)
Snout Wiki
File created by do_doc at Wed May 30 03:28:13 PDT 2007