Summary of changes made to FORMS 2.0, through October 1993, at the Geometry Center. FORMS/colorwheel.c: New color-picker module. FORMS/fouraxis.c: New module, derived from positioner.c. Allows specifying a direction in 4-space. FORMS/objects.c: Be more intelligent about frozen forms: only redraw if some object changed while the form was frozen. Use the sign bit of the form->frozen field to tell. FORMS/browser.c: Add '@I' prefix to embed FL_ICON_STYLE (symbol font) items in a browser. FORMS/draw.c: Tie mouse (x,y) position to all mouse clicks. Use this to ensure that we always register a mouse click in its correct position, not the place where the mouse lies when we get a chance to read it! Click position is fed to the next caller to ask for the mouse position after a click; later calls read the live mouse position. Seems to work. Cache stuff as much as possible. Don't load fonts or read color map unless (until) we actually need them. Might allow programs to start up at a reasonable speed, since the SGI font manager is slower in 4.0.x than 3.3. Handle Icon font usefully -- use the Symbol font, and allow it to be scaled. Accommodate new font-sizing rule in IRIX 4.0.5: fonts are now scaled to constant real size rather than constant size in pixels. On IRIX 4.0.5 or greater, we discover the error this will cause and scale all font sizes by its reciprocal (!). FORMS/forms.c: More of record-mouse-position-on-click mod mentioned under draw.c. Cut out so-called Correction for Irix 4.0 INPUTCHANGE Bug. With the bugfix installed, FORMS seems to lose inputchange's for new windows appearing under the cursor; without it, it sees them correctly. FORMS/bitmap.c: Optimize drawing bitmaps. Cache fl_getmcolor() values; use pointers to scan input & output pixel arrays. ~sixfold speedup. Save 64K of static data. DESIGN/Makefile: Add rule for fdesign2c, batch-mode translator from *.fd to *.{c,h}. DESIGN/fd_forms.c: DESIGN/fd_main.c: DESIGN/fd_main.h: Adapt to allow batch mode. DESIGN/fd_objects.c: Added colorwheel and fouraxis objects. DESIGN/formsstubs.c: Stubs for FORMS routines -- used for batch-mode fdesign2c program. diff -r -c orig/DEMOS/Makefile new/DEMOS/Makefile *** orig/DEMOS/Makefile Thu Nov 28 02:22:04 1991 --- new/DEMOS/Makefile Mon Aug 10 12:57:18 1992 *************** *** 15,21 **** demo21.o demo22.o demo23.o demo24.o demo25.o \ demo26.o demo27.o demo28.o demo29.o demo30.o \ demo31.o demo32.o demo33.o demo34.o demo35.o \ ! demo36.o demo37.o demo38.o # DEMOS= ${DEMOSO:.o=} --- 15,22 ---- demo21.o demo22.o demo23.o demo24.o demo25.o \ demo26.o demo27.o demo28.o demo29.o demo30.o \ demo31.o demo32.o demo33.o demo34.o demo35.o \ ! demo36.o demo37.o demo38.o \ ! demof01.o demof02.o # DEMOS= ${DEMOSO:.o=} diff -r -c orig/DEMOS/Readme new/DEMOS/Readme *** orig/DEMOS/Readme Mon Nov 18 13:26:09 1991 --- new/DEMOS/Readme Mon Aug 10 19:01:55 1992 *************** *** 50,52 **** --- 50,56 ---- demo36 A demo of counters. demo37 A strip chart. demo38 All charts. + + demof01 Fouraxis demo: fouraxis and numerical display + demof02 Fouraxis demo: fouraxis and basis-matrix display + diff -r -c orig/DEMOS/demo.menu new/DEMOS/demo.menu *** orig/DEMOS/demo.menu Tue Nov 5 06:39:04 1991 --- new/DEMOS/demo.menu Mon Aug 10 12:36:21 1992 *************** *** 44,49 **** --- 44,51 ---- @other:Choice\nObjects:demo32 @other:Bitmaps:demo33 @other:Timer\nObjects:demo34 + @other:4-D Axis:demof01 + @other:4-D Axis\n+ Basis:demof02 @main:Attributes:@attribs @attribs:All\nBoxtypes:demo17 Only in new/DEMOS: demof01.c Only in new/DEMOS: demof02.c diff -r -c orig/DESIGN/Makefile new/DESIGN/Makefile *** orig/DESIGN/Makefile Wed Nov 27 09:51:42 1991 --- new/DESIGN/Makefile Mon Aug 31 11:01:18 1992 *************** *** 9,24 **** # # Change the following for correct installation # ! DIR= /usr/sbin # FILEo = fd_rubber.o fd_select.o fd_names.o fd_objects.o fd_attribs.o \ fd_forms.o fd_groups.o fd_file.o fd_print.o fd_theforms.o \ ! fd_help.o fd_main.o all: fdesign conv15to20 fdesign: $(FILEo) ! ${CC} ${CFLAGS} ${LDFLAGS} $(FILEo) -o fdesign ${LIBS} conv15to20: conv15to20.o ${CC} conv15to20.o -o conv15to20 -s --- 9,30 ---- # # Change the following for correct installation # ! DIR= /usr/local/bin # + # Note fd_main.c in the following list. + # This forces recompilation with the appropriate -DBATCH setting. + FILEo = fd_rubber.o fd_select.o fd_names.o fd_objects.o fd_attribs.o \ fd_forms.o fd_groups.o fd_file.o fd_print.o fd_theforms.o \ ! fd_help.o fd_main.c all: fdesign conv15to20 fdesign: $(FILEo) ! ${CC} ${CFLAGS} ${LDFLAGS} $(FILEo) -o $@ ${LIBS} ! ! fdesign2c: $(FILEo) formsstubs.o ! ${CC} -DBATCH ${CFLAGS} ${LDFLAGS} ${FILEo} formsstubs.o -o $@ -lforms -lm -lc_s conv15to20: conv15to20.o ${CC} conv15to20.o -o conv15to20 -s diff -r -c orig/DESIGN/fd_forms.c new/DESIGN/fd_forms.c *** orig/DESIGN/fd_forms.c Wed Dec 11 10:35:17 1991 --- new/DESIGN/fd_forms.c Thu May 28 13:56:47 1992 *************** *** 155,161 **** LOADING AND SAVING ****/ ! void load_forms(int merge, char *str) /* loads or merges a file with form definitions */ { int i,magic; --- 155,161 ---- LOADING AND SAVING ****/ ! int load_forms(int merge, char *str) /* loads or merges a file with form definitions */ { int i,magic; *************** *** 168,174 **** ff = fl_show_file_selector("Filename to merge forms from","","*.fd",""); else ff = fl_show_file_selector("Filename to load forms from","","*.fd",""); ! if (ff == NULL || ff[0] == '\0') return; /* Append .fd if required. */ strcpy(fname,ff); i = strlen(fname) -1; --- 168,174 ---- ff = fl_show_file_selector("Filename to merge forms from","","*.fd",""); else ff = fl_show_file_selector("Filename to load forms from","","*.fd",""); ! if (ff == NULL || ff[0] == '\0') return 0; /* Append .fd if required. */ strcpy(fname,ff); i = strlen(fname) -1; *************** *** 176,187 **** strcat(fname,".fd"); /* Open the file for reading */ fn = fopen(fname,"r"); ! if (fn == (FILE *) NULL) { fl_show_message("No such file!!","",""); return; } /* Read in the definitions */ if (!merge) { fnumb = 0; fl_clear_browser(formbrowser);} magic = 0; fscanf(fn,"Magic: %d\n\n",&magic); ! if (magic != 12321) { fl_show_message("Wrong type of file!!","",""); return; } fscanf(fn,"Internal Form Definition File\n"); fscanf(fn," (do not change)\n\n"); fscanf(fn,"Number of forms: %d\n",&i); --- 176,187 ---- strcat(fname,".fd"); /* Open the file for reading */ fn = fopen(fname,"r"); ! if (fn == (FILE *) NULL) { fl_show_message("No such file!!",fname,""); return 0; } /* Read in the definitions */ if (!merge) { fnumb = 0; fl_clear_browser(formbrowser);} magic = 0; fscanf(fn,"Magic: %d\n\n",&magic); ! if (magic != 12321) { fl_show_message("Wrong type of file!!",fname,""); return 0; } fscanf(fn,"Internal Form Definition File\n"); fscanf(fn," (do not change)\n\n"); fscanf(fn,"Number of forms: %d\n",&i); *************** *** 194,200 **** fl_add_browser_line(formbrowser,forms[fnumb].fname); fnumb++; } ! if (i>0) fl_show_message("Not all forms could be loaded!!","",""); if (i == 0 && !merge) { fscanf(fn,"\n==============================\n"); --- 194,200 ---- fl_add_browser_line(formbrowser,forms[fnumb].fname); fnumb++; } ! if (i>0) fl_show_message("Not all forms could be loaded!!",fname,""); if (i == 0 && !merge) { fscanf(fn,"\n==============================\n"); *************** *** 204,212 **** if (fnumb>0) set_form(0); else set_form(-1); if (merge) changed = 1; fclose(fn); } ! int save_forms() /* saves the form definitions, retunrs whether saved */ { int i,j; --- 204,213 ---- if (fnumb>0) set_form(0); else set_form(-1); if (merge) changed = 1; fclose(fn); + return 1; } ! int save_forms(int do_fd, char *dfname) /* saves the form definitions, retunrs whether saved */ { int i,j; *************** *** 213,229 **** FILE *fn; char fname[256], filename[256], *ff; ! /* Get the file name */ ! ff = fl_show_file_selector("Filename to save forms to","","*.fd",""); ! if (ff == NULL || ff[0] == '\0') ! { fl_show_message("No forms were saved.","",""); return 0; } /* Remove .fd is required */ - strcpy(filename,ff); i = strlen(filename) -1; if (filename[i] == 'd' && filename[i-1] == 'f' && filename[i-2] == '.') filename[i-2] = '\0'; /* Make the .h file. */ strcpy(fname,filename); strcat(fname,".h"); --- 214,251 ---- FILE *fn; char fname[256], filename[256], *ff; ! if(dfname == NULL) { ! /* Get the file name */ ! ff = fl_show_file_selector("Filename to save forms to","","*.fd",""); ! if (ff == NULL || ff[0] == '\0') ! { fl_show_message("No forms were saved.","",""); return 0; } ! strcpy(filename, ff); ! } else { ! strcpy(filename, dfname); ! } /* Remove .fd is required */ i = strlen(filename) -1; if (filename[i] == 'd' && filename[i-1] == 'f' && filename[i-2] == '.') filename[i-2] = '\0'; + /* Make the .fd file. */ + if(do_fd) { + strcpy(fname,filename); + strcat(fname,".fd"); + fn = fopen(fname,"w"); + if (fn == (FILE *) NULL) + { fl_show_message("Cannot create definition file!!","",""); return 0; } + fprintf(fn,"Magic: 12321\n\n"); + fprintf(fn,"Internal Form Definition File\n"); + fprintf(fn," (do not change)\n\n"); + fprintf(fn,"Number of forms: %d\n",fnumb); + for (i=0; ispec)); ! int i,j,c,k = 0; ! short r,g,b; ! int xx,yy; /* position of bitmap */ /* Draw the box */ fl_drw_box(ob->boxtype,ob->x,ob->y,ob->w,ob->h,ob->col2,FL_BITMAP_BW); --- 17,31 ---- char *bits; /* pointer to the bitmap */ } SPEC; static void draw_bitmap(FL_OBJECT *ob) /* draws the bitmap */ { SPEC *sp = ((SPEC *)(ob->spec)); ! ! unsigned int j,k = 0; ! long color[2]; ! int i, xx,yy; /* position of bitmap */ ! unsigned long thebits[FL_BITMAP_MAXSIZE]; /* Draw the box */ fl_drw_box(ob->boxtype,ob->x,ob->y,ob->w,ob->h,ob->col2,FL_BITMAP_BW); *************** *** 33,52 **** ob->lcol,ob->lsize,ob->lstyle,ob->label); if (sp->bits_w == 0) return; /* Create the bitmap */ for (j=0; jbits_h; j++) { ! for (i=0; ibits_w; i++) ! { ! if (sp->bits[k + i/8] & (1 << (i % 8))) c = ob->col1; else c = ob->col2; ! if (fl_rgbmode) ! { ! fl_getmcolor(c,&r,&g,&b); ! thebits[(sp->bits_h-j-1)*sp->bits_w+i] = 0x10000 * b + 0x100 * g + r; ! } ! else ! thebits[(sp->bits_h-j-1)*sp->bits_w+i] = (short)c; ! } k += (sp->bits_w+7)/8; } --- 33,67 ---- ob->lcol,ob->lsize,ob->lstyle,ob->label); if (sp->bits_w == 0) return; + + if(fl_rgbmode) { + short r,g,b; + fl_getmcolor(ob->col1, &r,&g,&b); color[1] = (b<<16) | (g<<8) | r; + fl_getmcolor(ob->col2, &r,&g,&b); color[0] = (b<<16) | (g<<8) | r; + } else { + color[1] = ob->col1; + color[0] = ob->col2; + } + /* Create the bitmap */ for (j=0; jbits_h; j++) { ! register unsigned long *op = &thebits[(sp->bits_h - j - 1) * sp->bits_w]; ! unsigned char *ip = (unsigned char *)&sp->bits[k]; ! i = sp->bits_w; ! do { ! register int byte = *ip++; ! switch(i <= 8 ? (i & 7) : 0) { ! case 0: *op++ = color[byte&1]; byte >>= 1; ! case 7: *op++ = color[byte&1]; byte >>= 1; ! case 6: *op++ = color[byte&1]; byte >>= 1; ! case 5: *op++ = color[byte&1]; byte >>= 1; ! case 4: *op++ = color[byte&1]; byte >>= 1; ! case 3: *op++ = color[byte&1]; byte >>= 1; ! case 2: *op++ = color[byte&1]; byte >>= 1; ! case 1: *op++ = color[byte&1]; byte >>= 1; ! } ! } while((i -= 8) > 0); k += (sp->bits_w+7)/8; } diff -r -c orig/FORMS/browser.c new/FORMS/browser.c *** orig/FORMS/browser.c Thu Dec 12 05:09:14 1991 --- new/FORMS/browser.c Tue Jun 22 21:10:34 1993 *************** *** 153,158 **** --- 153,159 ---- case 's': size = FL_SMALL_FONT; break; case 'b': style = FL_BOLD_STYLE; break; case 'i': style = FL_ITALIC_STYLE; break; + case 'I': style = FL_ICON_STYLE; break; case 'f': style = FL_FIXED_STYLE; break; case 'c': align = FL_ALIGN_CENTER; break; case 'r': align = FL_ALIGN_RIGHT; break; Only in new/FORMS: colorwheel.c diff -r -c orig/FORMS/draw.c new/FORMS/draw.c *** orig/FORMS/draw.c Wed Nov 27 09:04:20 1991 --- new/FORMS/draw.c Wed Oct 20 19:05:49 1993 *************** *** 17,22 **** --- 17,23 ---- #include #include #include + #include /* 4.0.5 hack */ #include "forms.h" /********* *************** *** 23,37 **** Mouse stuff. *********/ void fl_get_mouse(float *xx,float *yy) /* returns the position of the mouse in world coordinates*/ { ! long x,y; getorigin(&x,&y); ! *xx = (float) (getvaluator(MOUSEX)-x); ! *yy = (float) (getvaluator(MOUSEY)-y); } /********* Clipping. *********/ --- 24,67 ---- Mouse stuff. *********/ + static struct { + long x, y; + int valid; + } mouse; + + /* + * Remember, briefly, where the mouse was when a button is clicked; + * lets us keep things straight when we're behind real time. + */ + void fl_mouse_click_at(long xpix, long ypix) + { + mouse.x = xpix; + mouse.y = ypix; + mouse.valid = 1; + } + + void fl_get_raw_mouse(long *xx, long *yy) + { + if(!mouse.valid) { + mouse.x = getvaluator(MOUSEX); + mouse.y = getvaluator(MOUSEY); + } + *xx = mouse.x; + *yy = mouse.y; + mouse.valid = 0; + } + void fl_get_mouse(float *xx,float *yy) /* returns the position of the mouse in world coordinates*/ { ! long x,y, mx,my; ! fl_get_raw_mouse(&mx, &my); getorigin(&x,&y); ! *xx = mx - x; ! *yy = my - y; } + /********* Clipping. *********/ *************** *** 59,93 **** Font related stuff *********/ ! static fmfonthandle thefont[5],smallfont[5],normalfont[5],largefont[5], ! iconfont; ! ! void fl_set_font(char normalname[], char boldname[], ! char italicname[], char fixedname[]) { int i; ! fminit(); ! thefont[0] = fmfindfont(normalname); ! thefont[1] = fmfindfont(boldname); ! thefont[2] = fmfindfont(italicname); ! thefont[3] = fmfindfont(fixedname); ! for (i=0; i<4; i++) ! { ! smallfont[i] = fmscalefont(thefont[i],FL_SMALL_FONT); ! normalfont[i] = fmscalefont(thefont[i],FL_NORMAL_FONT); ! largefont[i] = fmscalefont(thefont[i],FL_LARGE_FONT); ! } ! thefont[4] = thefont[0]; ! smallfont[4] = smallfont[0]; ! normalfont[4] = normalfont[0]; ! largefont[4] = largefont[0]; } void fl_init_fonts() { ! fl_set_font(FL_FONT_NAME,FL_FONT_BOLDNAME, ! FL_FONT_ITALICNAME,FL_FONT_FIXEDNAME); ! iconfont = fmfindfont(FL_FONT_ICONNAME); } float fl_get_char_height(float size, int style) --- 89,166 ---- Font related stuff *********/ ! static fmfonthandle thefont[6],smallfont[6],normalfont[6],largefont[6]; ! static char *fontname[6] = { ! FL_FONT_NAME, FL_FONT_BOLDNAME, FL_FONT_ITALICNAME, ! FL_FONT_FIXEDNAME, NULL, FL_FONT_ICONNAME ! }; ! ! static float fontscale = 0; ! ! void fl_set_font(char normal[], char bold[], ! char italic[], char fixed[], ! char icon[]) { int i; ! fontname[FL_NORMAL_STYLE] = normal; ! fontname[FL_BOLD_STYLE] = bold; ! fontname[FL_ITALIC_STYLE] = italic; ! fontname[FL_FIXED_STYLE] = fixed; ! fontname[FL_ICON_STYLE] = icon; ! /* Invalidate font cache */ ! bzero(thefont, sizeof(thefont)); ! bzero(smallfont, sizeof(smallfont)); ! bzero(normalfont, sizeof(normalfont)); ! bzero(largefont, sizeof(largefont)); } void fl_init_fonts() { ! if(fontscale == 0) { ! /* Kludge to handle fontmgr "bug" fix in >= 4.0.5: ! * Fonts are now scaled to appear as constant real size (Postscript style) ! * as opposed to constant size in pixels (as 3.x and 4.0.[1..4] fmgr did). ! * FORMS programs (at least fdesign'ed ones) assume constant pixel size, ! * so if this bugfix was applied, we apply the inverse transformation here. ! */ ! struct utsname whatami; ! uname(&whatami); ! fontscale = 1.0; /* Old systems work as we expect */ ! if(strcmp(whatami.release, "4.0.5") >= 0) ! fontscale = ((float)getgdesc(GD_XMMAX)/getgdesc(GD_XPMAX)) / 0.265; ! } ! ! fminit(); ! /* No need to do this now -- statically initialized. ! * fl_set_font(FL_FONT_NAME,FL_FONT_BOLDNAME, ! * FL_FONT_ITALICNAME,FL_FONT_FIXEDNAME, ! * FL_FONT_ICONNAME); ! */ ! } ! ! fmfonthandle ! fl_get_font(float size, int style) ! { ! fmfonthandle fnt = NULL; ! fmfonthandle *fp = &fnt; ! ! if (style < 0 || style >= 6) ! {fl_error("fl_get_font","Unknown font style"); return NULL;} ! if (size == FL_SMALL_FONT) fp = &smallfont[style]; ! else if (size == FL_NORMAL_FONT) fp = &normalfont[style]; ! else if (size == FL_LARGE_FONT) fp = &largefont[style]; ! if(*fp == NULL) { ! if(thefont[style] == NULL) { ! if(style == 0 || style == 4) ! thefont[0] = thefont[4] = fmfindfont(fontname[0]); ! else ! thefont[style] = fmfindfont(fontname[style]); ! } ! *fp = fmscalefont(thefont[style], size*fontscale); ! } ! if(*fp == NULL) ! fl_error("fl_get_font", "Unknown font"); ! return *fp; } float fl_get_char_height(float size, int style) *************** *** 95,109 **** { fmfontinfo info; fmfonthandle fnt; ! if (style < 0 || style >= 6) ! {fl_error("fl_get_char_height","Unknown font style"); return 0.0;} ! if (style == FL_ICON_STYLE) fnt = iconfont; ! else if (size == FL_SMALL_FONT) fnt = smallfont[style]; ! else if (size == FL_NORMAL_FONT) fnt = normalfont[style]; ! else if (size == FL_LARGE_FONT) fnt = largefont[style]; ! else fnt = fmscalefont(thefont[style],size); ! if (fnt == NULL) ! {fl_error("fl_get_char_height","Font does not exist."); return 0.0;} fmgetfontinfo(fnt,&info); return (float) info.height; } --- 168,175 ---- { fmfontinfo info; fmfonthandle fnt; ! if((fnt = fl_get_font(size, style)) == NULL) ! return 0.0; fmgetfontinfo(fnt,&info); return (float) info.height; } *************** *** 113,127 **** { fmfontinfo info; fmfonthandle fnt; ! if (style < 0 || style >= 6) ! {fl_error("fl_get_string_width","Unknown font style"); return 0.0;} ! if (style == FL_ICON_STYLE) fnt = iconfont; ! else if (size == FL_SMALL_FONT) fnt = smallfont[style]; ! else if (size == FL_NORMAL_FONT) fnt = normalfont[style]; ! else if (size == FL_LARGE_FONT) fnt = largefont[style]; ! else fnt = fmscalefont(thefont[style],size); ! if (fnt == NULL) ! {fl_error("fl_get_string_width","Font does not exist."); return 0.0;} fmgetfontinfo(fnt,&info); return (float) fmgetstrwidth(fnt,str); } --- 179,186 ---- { fmfontinfo info; fmfonthandle fnt; ! if((fnt = fl_get_font(size, style)) == NULL) ! return 0.0; fmgetfontinfo(fnt,&info); return (float) fmgetstrwidth(fnt,str); } *************** *** 138,173 **** Color Stuff. *********/ - static short fl_red[4096], fl_green[4096], fl_blue[4096]; void fl_init_colormap() { ! long cmwin, oldwin; ! int i; ! /* Read colormap colors into internal table */ ! oldwin = winget(); ! noport(); ! cmwin = winopen("CM"); ! for (i=0; i<4096; i++) ! getmcolor(i,&fl_red[i],&fl_green[i],&fl_blue[i]); ! winclose(cmwin); ! if (oldwin >= 0) winset(oldwin); ! /* Correct colors for small number of bitplanes */ ! if (getgdesc(GD_BITS_NORM_DBL_RED) <= 4) ! for (i=0; i<4096; i++) ! { ! fl_red[i] = 8 * (fl_red[i] / 8); ! fl_green[i] = 8 * (fl_green[i] / 8); ! fl_blue[i] = 8 * (fl_blue[i] / 8); } } void fl_color(int col) /* Sets a colormap index in RGB mode. */ { ! if (fl_rgbmode) ! RGBcolor(fl_red[col],fl_green[col],fl_blue[col]); ! else color(col); } --- 197,243 ---- Color Stuff. *********/ + static long fl_cmap[4096]; + void fl_init_colormap() { ! bzero(fl_cmap, sizeof(fl_cmap)); ! } ! ! void fl_getmcolor(int index, short *red, short *green, short *blue) ! { ! long v; ! short r,g,b; ! ! if(!fl_rgbmode) { ! getmcolor(index, red, green, blue); ! return; ! } ! if(index < 0 || index >= 4096) ! return; ! if((v = fl_cmap[index]) != 0) { ! *red = v & 0xFF; ! *green = (v>>8) & 0xFF; ! *blue = (v>>16) & 0xFF; ! } else { ! if(winget() <= 0) { ! noport(); ! winopen("CM"); } + getmcolor(index, red, green, blue); + fl_mapcolor(index, *red, *green, *blue); + } } void fl_color(int col) /* Sets a colormap index in RGB mode. */ { ! short r,g,b; ! if (fl_rgbmode) { ! fl_getmcolor(col, &r,&g,&b); ! RGBcolor(r,g,b); ! } else color(col); } *************** *** 174,194 **** void fl_mapcolor(int i, short red, short green, short blue) /* Changes a colormap index */ { ! if (fl_rgbmode) ! { fl_red[i] = red; fl_green[i] = green; fl_blue[i] = blue;} ! else mapcolor(i,red,green,blue); } - void fl_getmcolor(int i, short *red, short *green, short *blue) - /* Returns a colormap index */ - { - if (fl_rgbmode) - {*red = fl_red[i]; *green = fl_green[i]; *blue = fl_blue[i];} - else - getmcolor(i,red,green,blue); - } - /********* Drawing boxes. *********/ --- 244,257 ---- void fl_mapcolor(int i, short red, short green, short blue) /* Changes a colormap index */ { ! if (fl_rgbmode) { ! if(i >= 0 && i < 4096) ! fl_cmap[i] = 0xFF000000 | ((blue&0xFF) << 16) | ! ((green&0xFF) << 8) | ((red&0xFF)); ! } else mapcolor(i,red,green,blue); } /********* Drawing boxes. *********/ *************** *** 359,372 **** if (pos!=0 && (str == NULL || str[0] == '\0')) return; /* Set the font correctly. */ ! if (style < 0 || style >= 6) ! {fl_error("fl_drw_text_cursor","Unknown font style"); return;} ! if (style == FL_ICON_STYLE) fnt = iconfont; ! else if (size == FL_SMALL_FONT) fnt = smallfont[style]; ! else if (size == FL_NORMAL_FONT) fnt = normalfont[style]; ! else if (size == FL_LARGE_FONT) fnt = largefont[style]; ! else fnt = fmscalefont(thefont[style],size); ! if (fnt == NULL) {fl_error("fl_drw_test_cursor","Font does not exist."); return;} fmsetfont(fnt); fmgetfontinfo(fnt,&info); --- 422,428 ---- if (pos!=0 && (str == NULL || str[0] == '\0')) return; /* Set the font correctly. */ ! if((fnt = fl_get_font(size, style)) == NULL) {fl_error("fl_drw_test_cursor","Font does not exist."); return;} fmsetfont(fnt); fmgetfontinfo(fnt,&info); diff -r -c orig/FORMS/events.c new/FORMS/events.c *** orig/FORMS/events.c Tue Nov 12 06:51:35 1991 --- new/FORMS/events.c Thu May 28 17:58:51 1992 *************** *** 46,53 **** #define QSIZE 700 ! static int queued[MAXSGIDEVICE]; /* devices queued by user */ static short thedev[QSIZE]; /* The event queue */ static short theval[QSIZE]; static int head = 0 , tail = 0; --- 46,57 ---- #define QSIZE 700 ! static char queued[(MAXSGIDEVICE+7)/8]; /* devices queued by user */ + #define BITSET(cvec, bit) (cvec)[(bit) >> 3] |= 1 << ((bit)&7) + #define BITCLEAR(cvec, bit) (cvec)[(bit) >> 3] &= ~(1 << ((bit)&7)) + #define BITTEST(cvec, bit) ((cvec)[(bit) >> 3] & 1 << ((bit)&7)) + static short thedev[QSIZE]; /* The event queue */ static short theval[QSIZE]; static int head = 0 , tail = 0; *************** *** 67,81 **** /* initializes the event setting */ { int i; ! for (i=0; iw))/2; wy = (screenh - (long)(form->h))/2;} else if (place == FL_PLACE_MOUSE) { ! wx = (long) (getvaluator(MOUSEX) - 0.5*form->w); ! wy = (long) (getvaluator(MOUSEY) - 0.5*form->h); } else if (place == FL_PLACE_POSITION) { --- 149,157 ---- {wx = (screenw - (long)(form->w))/2; wy = (screenh - (long)(form->h))/2;} else if (place == FL_PLACE_MOUSE) { ! fl_get_raw_mouse(&wx, &wy); ! wx -= form->w / 2; ! wy -= form->h / 2; } else if (place == FL_PLACE_POSITION) { *************** *** 177,182 **** --- 178,186 ---- qdevice(LEFTARROWKEY); qdevice(RIGHTARROWKEY); qdevice(UPARROWKEY); qdevice(DOWNARROWKEY); qdevice(WINQUIT); + tie(MOUSE1, MOUSEX, MOUSEY); + tie(MOUSE2, MOUSEX, MOUSEY); + tie(MOUSE3, MOUSEX, MOUSEY); reshape_form(form); fl_redraw_form(form); /* Check whether the window appear under the mouse and generate an *************** *** 184,190 **** */ getorigin(&x,&y); getsize(&w,&h); ! mx = getvaluator(MOUSEX); my = getvaluator(MOUSEY); if (mx>=x && mx<=x+w && my>=y && my<=y+h) qenter(INPUTCHANGE, (short) form->window); if (oldwin > 0 ) winset(oldwin); --- 188,194 ---- */ getorigin(&x,&y); getsize(&w,&h); ! fl_get_raw_mouse(&mx, &my); if (mx>=x && mx<=x+w && my>=y && my<=y+h) qenter(INPUTCHANGE, (short) form->window); if (oldwin > 0 ) winset(oldwin); *************** *** 226,232 **** winset(form->window); getorigin(&x,&y); getsize(&w,&h); ! mx = getvaluator(MOUSEX); my = getvaluator(MOUSEY); if (mx>=x && mx<=x+w && my>=y && my<=y+h) qenter(INPUTCHANGE, 0); --- 230,236 ---- winset(form->window); getorigin(&x,&y); getsize(&w,&h); ! fl_get_raw_mouse(&mx, &my); if (mx>=x && mx<=x+w && my>=y && my<=y+h) qenter(INPUTCHANGE, 0); *************** *** 432,437 **** --- 436,452 ---- case MOUSE1: case MOUSE2: case MOUSE3: + /* If mouse position is tie()d to mouse button, take advantage of that! */ + if(qtest() == MOUSEX) { + short mx, my; + qread(&mx); + fl_qenter(MOUSEX, mx); + if(qtest() == MOUSEY) { + qread(&my); + fl_qenter(MOUSEY, my); + fl_mouse_click_at(mx, my); + } + } if (val) { if (getbutton(LEFTCTRLKEY) && getbutton(LEFTSHIFTKEY) && *************** *** 461,467 **** gives strange effects. To avoid this we only treat an enter event if the previous one was a leave event. ************************/ ! if (lastinputchange != 0) break; lastinputchange = val; if (mouseform != NULL) --- 476,488 ---- gives strange effects. To avoid this we only treat an enter event if the previous one was a leave event. ************************/ ! /* No, don't do that. It's quite possible to get a new window-enter ! * event without a preceding window-leave -- when one window pops up ! * over another one, which is common for popups! ! * The commented-out code below causes FORMS to hose its input focus. ! * -slevy 92.04.20 ! */ ! /* if (lastinputchange != 0) break; */ lastinputchange = val; if (mouseform != NULL) Only in new/FORMS: forms.h Only in new/FORMS: fouraxis.c diff -r -c orig/FORMS/objects.c new/FORMS/objects.c *** orig/FORMS/objects.c Thu Nov 28 08:12:45 1991 --- new/FORMS/objects.c Wed Jul 21 19:54:57 1993 *************** *** 383,389 **** if (obj == NULL) { fl_error("fl_redraw_object","Trying to draw NULL object."); return;} if (obj->form == NULL) return; ! if (obj->frozen || obj->form->frozen || ! obj->form->visible) return; winset(obj->form->window); if (obj->objclass == FL_BEGIN_GROUP) { --- 383,398 ---- if (obj == NULL) { fl_error("fl_redraw_object","Trying to draw NULL object."); return;} if (obj->form == NULL) return; ! if (obj->frozen) { ! obj->frozen = -1; ! return; ! } ! if(obj->form->frozen) { ! obj->form->frozen = -1; ! return; ! } ! if(! obj->form->visible) ! return; winset(obj->form->window); if (obj->objclass == FL_BEGIN_GROUP) { *************** *** 415,421 **** long oldwin = winget(); if (form == NULL) { fl_error("fl_redraw_form","Drawing NULL form."); return;} ! if (form->frozen || ! form->visible) return; winset(form->window); ob = form->first; while ( ob != NULL ) --- 424,434 ---- long oldwin = winget(); if (form == NULL) { fl_error("fl_redraw_form","Drawing NULL form."); return;} ! if (form->frozen) { ! form->frozen = -1; ! return; ! } ! if (! form->visible) return; winset(form->window); ob = form->first; while ( ob != NULL ) *************** *** 440,448 **** { ob = obj; while ( (ob = ob->next) != NULL && ob->objclass != FL_END_GROUP ) ! ob->frozen = 1; } ! obj->frozen = 1; } void fl_unfreeze_object(FL_OBJECT *obj) --- 453,461 ---- { ob = obj; while ( (ob = ob->next) != NULL && ob->objclass != FL_END_GROUP ) ! ob->frozen |= 1; } ! obj->frozen |= 1; } void fl_unfreeze_object(FL_OBJECT *obj) *************** *** 449,464 **** /* Enable drawing of object */ { FL_OBJECT *ob; if (obj == NULL) { fl_error("fl_freeze_object","Unfreezing NULL object."); return;} if (obj->objclass == FL_BEGIN_GROUP) { ob = obj; ! while ( (ob = ob->next) != NULL && ob->objclass != FL_END_GROUP ) ob->frozen = 0; } obj->frozen = 0; ! fl_redraw_object(obj); } void fl_freeze_form(FL_FORM *form) --- 462,482 ---- /* Enable drawing of object */ { FL_OBJECT *ob; + int touched = 0; if (obj == NULL) { fl_error("fl_freeze_object","Unfreezing NULL object."); return;} if (obj->objclass == FL_BEGIN_GROUP) { ob = obj; ! while ( (ob = ob->next) != NULL && ob->objclass != FL_END_GROUP ) { ! touched |= ob->frozen; ob->frozen = 0; + } } + touched |= obj->frozen; obj->frozen = 0; ! if(touched < 0) ! fl_redraw_object(obj); } void fl_freeze_form(FL_FORM *form) *************** *** 466,481 **** { if (form == NULL) { fl_error("fl_freeze_form","Freezing NULL form."); return;} ! form->frozen = 1; } void fl_unfreeze_form(FL_FORM *form) /* Enable drawing of form */ { if (form == NULL) { fl_error("fl_unfreeze_form","Unfreezing NULL form."); return;} form->frozen = 0; ! fl_redraw_form(form); } /*----------------------------------------------------------------------- --- 484,501 ---- { if (form == NULL) { fl_error("fl_freeze_form","Freezing NULL form."); return;} ! form->frozen |= 1; } void fl_unfreeze_form(FL_FORM *form) /* Enable drawing of form */ { + int touched; if (form == NULL) { fl_error("fl_unfreeze_form","Unfreezing NULL form."); return;} + touched = form->frozen; form->frozen = 0; ! if(touched < 0) fl_redraw_form(form); } /*----------------------------------------------------------------------- diff -r -c orig/FORMS/support.c new/FORMS/support.c *** orig/FORMS/support.c Mon Nov 11 13:46:10 1991 --- new/FORMS/support.c Wed Oct 20 18:52:34 1993 *************** *** 30,35 **** --- 30,39 ---- { if (initialized) return; initialized = TRUE; + if(winget() <= 0) { + noport(); + winopen(""); + } /* Set the graphics mode based on the machine type */ if (getgdesc(GD_BITS_NORM_SNG_RED) == 0) /* no rgbmode possible */ { fl_doublebuf = FALSE; fl_rgbmode = FALSE;} ... create new file demof01.c ... *** /dev/null Wed Oct 20 19:15:53 1993 --- new/DEMOS/demof01.c Mon Aug 10 19:21:28 1992 *************** *** 0 **** --- 1,62 ---- + #include "forms.h" + + FL_OBJECT *axis, *text, *quit; + + void + Quit(FL_OBJECT *obj, long val) + { + exit(0); + } + + void + TextIn(FL_OBJECT *obj, long val) + { + float x,y,z,w; + + if(sscanf(fl_get_input(obj), "%f %f %f", &x,&y,&z) == 3) + fl_set_fouraxis(axis, x,y,z); + sync_input(); + } + + void + AxisIn(FL_OBJECT *obj, long val) + { + sync_input(); + } + + sync_input() + { + char stuff[80]; + float x,y,z,w; + + fl_get_fouraxis(axis, &x,&y,&z,&w); + sprintf(stuff, "%.4f %.4f %.4f %.4f", x,y,z,w); + fl_set_input(text, stuff); + } + + main(argc, argv) + char *argv[]; + { + FL_FORM *mine; + FL_OBJECT *obj; + + fl_init(); + + mine = fl_bgn_form(FL_NO_BOX,250.0,250.0); + obj = fl_add_box(FL_UP_BOX,0.0,0.0,280.0,340.0,""); + axis = obj = fl_add_fouraxis(argc>1?atoi(argv[1]):FL_NORMAL_FOURAXIS,10.0,40.0,160.0,160.0,"4D axis"); + fl_set_call_back(obj,AxisIn,0); + quit = obj = fl_add_button(FL_NORMAL_BUTTON,180.0,20.0,60.0,60.0,"Quit"); + fl_set_call_back(obj,Quit,0); + text = obj = fl_add_input(FL_NORMAL_INPUT,10.0,210.0,230.0,30.0,""); + fl_set_object_color(obj,9,9); + fl_set_object_lstyle(obj,FL_BOLD_STYLE); + fl_set_call_back(obj,TextIn,3); + fl_end_form(); + + fl_show_form(mine, FL_PLACE_SIZE, 1, "Axis"); + sync_input(); + while(fl_do_forms()) + ; + exit(0); + } ... create new file demof02.c ... *** /dev/null Wed Oct 20 19:15:53 1993 --- new/DEMOS/demof02.c Mon Aug 10 19:00:04 1992 *************** *** 0 **** --- 1,84 ---- + #include "forms.h" + + FL_OBJECT *axis, *text[4], *quit; + + void + Quit(FL_OBJECT *obj, long val) + { + exit(0); + } + + void + TextIn(FL_OBJECT *obj, long val) + { + float b[4][4]; + + fl_get_fouraxis_basis(axis, &b[0][0]); + if(sscanf(fl_get_input(obj), "%f %f %f %f", + &b[0][val], &b[1][val], &b[2][val], &b[3][val]) == 4) { + fl_set_fouraxis_basis(axis, &b[0][0]); + sync_inputs(); + } + } + + void + AxisIn(FL_OBJECT *obj, long val) + { + sync_inputs(); + } + + sync_inputs() + { + char stuff[80]; + float basis[4][4]; + int i; + + fl_get_fouraxis_basis(axis, &basis[0][0]); + for(i = 0; i < 4; i++) { + sprintf(stuff, "%7.3f %7.3f %7.3f %7.3f", + basis[0][i], basis[1][i], basis[2][i], basis[3][i]); + fl_set_input(text[i], stuff); + } + } + + main() + { + FL_FORM *mine; + FL_OBJECT *obj; + + fl_init(); + + + mine = fl_bgn_form(FL_NO_BOX,280.0,340.0); + obj = fl_add_box(FL_UP_BOX,0.0,0.0,280.0,340.0,""); + axis = obj = fl_add_fouraxis(FL_NORMAL_FOURAXIS,10.0,40.0,160.0,160.0,"4D axis"); + fl_set_call_back(obj,AxisIn,0); + text[0] = obj = fl_add_input(FL_NORMAL_INPUT,30.0,300.0,240.0,30.0,"x'"); + fl_set_object_color(obj,11,11); + fl_set_object_lstyle(obj,FL_BOLD_STYLE); + fl_set_call_back(obj,TextIn,0); + quit = obj = fl_add_button(FL_NORMAL_BUTTON,200.0,20.0,60.0,60.0,"Quit"); + fl_set_call_back(obj,Quit,0); + text[1] = obj = fl_add_input(FL_NORMAL_INPUT,30.0,270.0,240.0,30.0,"y'"); + fl_set_object_color(obj,11,11); + fl_set_object_lstyle(obj,FL_BOLD_STYLE); + fl_set_call_back(obj,TextIn,1); + text[2] = obj = fl_add_input(FL_NORMAL_INPUT,30.0,240.0,240.0,30.0,"z'"); + fl_set_object_color(obj,11,11); + fl_set_object_lstyle(obj,FL_BOLD_STYLE); + fl_set_call_back(obj,TextIn,2); + text[3] = obj = fl_add_input(FL_NORMAL_INPUT,30.0,210.0,240.0,30.0,"w'"); + fl_set_object_color(obj,9,9); + fl_set_object_lstyle(obj,FL_BOLD_STYLE); + fl_set_call_back(obj,TextIn,3); + obj = fl_add_text(FL_NORMAL_TEXT,180.0,150.0,90.0,50.0,"w' is the\nchosen \n4D vector"); + obj = fl_add_box(FL_BORDER_BOX,178.0,146.0,90.0,1.0,""); + obj = fl_add_text(FL_NORMAL_TEXT,181.0,88.0,85.0,52.0,"x' y' z' are\northogonal\nto it."); + fl_end_form(); + + fl_show_form(mine, FL_PLACE_SIZE, 1, "Axis"); + sync_inputs(); + while(fl_do_forms()) + ; + exit(0); + } ... create new file formsstubs.c ... *** /dev/null Wed Oct 20 19:15:53 1993 --- new/DESIGN/formsstubs.c Tue Jan 12 21:17:17 1993 *************** *** 0 **** --- 1,156 ---- + /* + * Graphics stub routines. + * Includes minimal mg, GL and forms stubs, sufficient to link the viewer + * without -lforms[2] and without -lgl_s, as of 1/11/92. + */ + + #include + #include + + + /* GL stubs */ + deflinestyle() { ; } + setlinestyle() { ; } + pushattributes() { ; } + popattributes() { ; } + rot() { ; } + move() { ; } + draw() { ; } + viewport() { ; } + perspective() { ; } + linewidth() { ; } + blendfunction() { ; } + c4f() { ; } + RGBcolor() { ; } + RGBmode() { ; } + bgnclosedline() { ; } + bgnline() { ; } + bgnpolygon() { ; } + circ() { ; } + circf() { ; } + cmov2() { ; } + cmov2i() { ; } + color() { ; } + doublebuffer() { ; } + endclosedline() { ; } + endline() { ; } + endpolygon() { ; } + gconfig() { ; } + getbutton() { return 0; } + getcpos() { ; } + getmatrix(float T[4][4]) { memset(T, 0, 16*sizeof(float)); T[0][0] = T[1][1] = T[2][2] = T[3][3] = 1.0; } + getmcolor(int i, short *r, short *g, short *b) { + *r = i&1 ? 255:0; + *g = i&2 ? 255:0; + *b = i&4 ? 255:0; + } + getmmode() { return 2 /*MVIEWING*/; } + getorigin(long *x0, long *y0) { *x0 = *y0 = 0; } + getscrmask(long *x0, long *x1, long *y0, long *y1) { *x0 = *y0 = 0; *x1 = *y1 = 512; } + getsize(long *xsize, long *ysize) { *xsize = *ysize = 512; } + getvaluator() { static int v = 120; v++; v %= 512; return v; } + getviewport(short *x0, short *x1, short *y0, short *y1) { getscrmask(x0,x1,y0,y1); } + gl_beginstring() { ; } + gl_drawbitmap() { ; } + gl_endstring() { ; } + isqueued() { return 0; } + keepaspect() { ; } + loadmatrix() { ; } + lrectwrite() { ; } + mapcolor() { ; } + mmode() { ; } + noborder() { ; } + noport() { ; } + ortho2() { ; } + popmatrix() { ; } + popviewport() { ; } + prefposition() { ; } + prefsize() { ; } + pushmatrix() { ; } + pushviewport() { ; } + qdevice() { ; } + qenter() { ; } + qgetfd() { return 2; } + qread() {int c; printf("qread -- to continue: "); while((c=getchar()) > 0 && c != '\n') ; return 0; } + qtest() { return 0; } + rect() { ; } + rectf() { ; } + reshapeviewport() { ; } + ringbell() { write(2, "\7", 1); } + rotate() { ; } + scale() { ; } + screenspace() { ; } + scrmask() { ; } + swapbuffers() { ; } + tie() { ; } + translate() { ; } + unqdevice() { ; } + v2f() { ; } + winclose() { ; } + static int winno = 128; + winget() { return winno; } + winopen() { return ++winno; } + winpop() { ; } + winset() { ; } + + getgdesc(code) { + switch(code) { + + #define GD_XPMAX 0 + #define GD_YPMAX 1 + #define GD_XMMAX 2 + #define GD_YMMAX 3 + #define GD_ZMIN 4 + #define GD_ZMAX 5 + #define GD_BITS_NORM_SNG_RED 6 + #define GD_BITS_NORM_DBL_RED 9 + #define GD_BITS_NORM_SNG_CMODE 12 + #define GD_BITS_NORM_DBL_CMODE 13 + #define GD_BITS_NORM_SNG_MMAP 14 + #define GD_BITS_NORM_DBL_MMAP 15 + #define GD_BITS_NORM_ZBUFFER 16 + + case GD_BITS_NORM_DBL_RED: + case GD_BITS_NORM_SNG_RED: return 8; + case GD_XPMAX: return 1280; + case GD_YPMAX: return 1024; + case GD_XMMAX: return 450; + default: printf("getgdesc(%d)?\n", code); return -1; + } + } + + static long unfont; + + drawmode() { ; } + mapw2() { ; } + clear() { ; } + fmfonthandle fmfindfont(char *name) { return &unfont; } + fmgetfontinfo(fmfonthandle fnt, fmfontinfo *info) { + bzero(info, sizeof(*info)); + info->xsize = info->ysize = info->width = info->height = 10; + info->resolution = 100; + } + fmgetstrwidth(fmfonthandle fnt, char *str) { return strlen(str)*8; } + fmprstr() { ; } + fmfonthandle fmscalefont(fmfontinfo *font, double v) { return &unfont; } + void fmsetfont(fmfontinfo *font) { ; } + fminit() { ; } + arc() { ; } + arcf() { ; } + pnt() { ; } + polf2() { ; } + poly2() { ; } + draw2() { ; } + move2() { ; } + pclos() { ; } + pdr2() { ; } + pmv2() { ; } + addtopup() { ; } + dopup() { ; } + freepup() { ; } + newpup() { ; } + + fl_show_message(char *s1, char *s2, char *s3) + { + fprintf(stderr, "%s %s %s\n", s1, s2, s3); + } ... create new file colorwheel.tex ... *** /dev/null Wed Oct 20 19:15:53 1993 --- new/DOC/CLASSES/colorwheel.tex Wed Dec 30 14:43:50 1992 *************** *** 0 **** --- 1,99 ---- + \section{Colorwheel} + + \subsection*{Short Description} + + A colorwheel object allows the selction of colors by moving a point + around a hexagon using the HSV color scheme. The value of the + colorwheel is set and returned as an RGBA value. + + \subsection*{Adding an object} + + A colorwheel can be added to a form using the call + + \begin{verbatim} + FL_OBJECT *fl_add_colorwheel(int type, float x, float y, + float w, float h, char label[]) + \end{verbatim} + + The meaning of the parameters is as usual. The label by default is + placed below the box. + + \subsection*{Types} + + There is only one type of colorwheel at this time: FL\_NORMAL\_COLORWHEEL. + + \subsection*{Interaction} + + The display shows a Gouraud-shaded hexagon with a black cursor in the + middle. The cursor may be moved around inside the hexagon by clicking + or dragging the mouse. The color under the cursor is the color which + will be returned by fl\_get\_colorwheel(). + + There is no way for the user to set the intensity of the color using + only the colorwheel. HSV colorspace is actually a solid + three-dimensional hexagonal pyramid. Only a cross-section of the + pyramid is shown in the hexagon at any time (For more details, see + $\underline{Computer Graphics: Principles and Practice}$ by Foley, + vanDam, Feiner, and Hughes). The intensity may be set + programmatically using fl\_set\_colorwheel\_intensity(). In general, the + programmer will want to create a slider for this purpose and use + fl\_set\_colorwheel\_intensity() to set the intensity of the colorwheel + every time the value of the slider is changed. The colors of the + colorwheel will change to reflect the new intensity. When the + colorwheel is created, the intensity is set to 1.0, its maximum value. + The colors become darker as the intensity is lowered toward 0.0, at + which point the entire colorwheel will be black. + + There is also no way for the user of the colorwheel to set the alpha + (transparency) value of the color. Again, the programmer may want to + create a slider for this parameter. On computer systems which support + transparency, the colorwheel will fade in and out as the alpha value + is changed. Alpha starts set to 1.0, or fully opaque. A value of 0.0 + is equivalent to complete transparency. The alpha value may be + changed using the routine fl\_set\_colorwheel\_alpha(). + + \subsection*{Other routines} + + To set the value of the colorwheel, use the routines: + + \begin{verbatim} + void fl_set_colorwheel(FL_OBJECT *obj, float *color) + + void fl_set_colorwheel_intensity(FL_OBJECT *obj, float intensity) + + void fl_set_colorwheel_alpha(FL_OBJECT *obj, float alpha) + \end{verbatim} + + fl\_set\_colorwheel() sets the colorwheel to the rgb value specified in + the color array. Each component ranges between 0.0 and 1.0. This + routine may also change the intensity. + + fl\_set\_colorwheel\_intensity() sets the intensity to a value between + 0.0 and 1.0. + + fl\_set\_colorwheel\_alpha() sets the transparency to a value between 0.0 + and 1.0. + + To get the value of the colorwheel, use the routines: + + \begin{verbatim} + void fl_get_colorwheel(FL_OBJECT *obj, float *color) + + float fl_get_colorhweel_intensity(FL_OBJECT *obj) + + float fl_get_colorwheel_alpha(FL_OBJECT *obj) + \end{verbatim} + + The values are as described above. Note that the value returned by + fl\_get\_colorwheel() takes the current intensity into account. + + \subsection*{Attributes} + + Color1 controls the color of the background (default gray). + Color2 controls the color of the cursor (default black). + + \subsection*{Remarks} + + Since the colorwheel uses Gouraud shading and transparency, the form + must be in RGB mode (the default). For best results, it should also + be double-buffered (also the default). ... create new file fouraxis.tex ... *** /dev/null Wed Oct 20 19:15:53 1993 --- new/DOC/CLASSES/fouraxis.tex Mon Aug 10 19:04:32 1992 *************** *** 0 **** --- 1,167 ---- + % For each class, a file like this should exist + % It should also be added in class.tex + + \section{Fouraxis} + + \subsubsection*{Short description} + + A fouraxis allows the user to graphically specify a direction + in a four-dimensional space: + specifically a unit vector, where $x^2 + y^2 + z^2 + w^2 = 1$. + + It displays a wireframe sphere containing a set of movable axes, + whose intersection indicates the $(x,y,z)$ components of the 4-vector. + The $w$ component is computed from these. + + The object can return either the 4-vector itself, or a complete + 4x4 orthonormal basis matrix with the specified vector as one of its columns. + + \subsubsection*{Adding an object} + + A fouraxis can be added to a form using the call + + \begin{verbatim} + FL_OBJECT *fl_add_fouraxis(int type, float x, float y, + float w, float h, char label[]) + \end{verbatim} + + The meaning of the parameters is as usual. The label by default is + placed below the box. + + \subsubsection*{Types} + + Only one useful type of fouraxis exists at the moment: + + \verb+FL_NORMAL_FOURAXIS+, showing three orthogonal axes. + + \subsubsection*{Interaction} + + The display shows a wireframe sphere and three orthogonal lines: + a red vector extending from the origin to the $(x,y,z)$ component of the + chosen point, and two other vectors reaching from the $(x,y,z)$ point + to the surface of the unit sphere as a perspective aid. + + In the wireframe sphere, $x$ increases rightward, $y$ away from the viewer, + and $z$ upward. + + The left mouse button rotates the chosen $(x,y,z)$ point within the sphere, + keeping its radial component constant. Horizontal motion rotates + in longitude (the $x-y$ plane), while vertical motion rotates in latitude. + The right mouse button moves the chosen point radially. + + \vspace{.1 in} + To understand the 3-D picture's relation to the four-dimensional vector, + consider how a 2-D person could specify a direction in 3-D space. + For each direction in 3-space, there's a point on the surface of a unit sphere + ($x^2 + y^2 + z^2 = 1$). A 2-D person could choose a point on the + unit disk $x^2 + y^2 \le 1$, and take it to mean the vector whose endpoint + on the sphere lies directly above or below that point. The disk's center + corresponds to the north (or south) pole of the sphere, and the edge of the + disk to the sphere's equator. Generally, $z = \sqrt{1 - x^2 - y^2}$. + How to choose between the positive and negative hemispheres? + Note that for every direction with negative $z$ component there's + an exactly opposite direction with $z > 0$. For many purposes, + e.g. orthogonal projection or slicing, opposite directions are equivalent, + so we can simply limit $z$ to a single hemisphere. + + The fouraxis object lets you choose a point in the unit 3-ball + with $x^2 + y^2 + z^2 \le 1$, and computes $w$ to create a unit 4-vector + lying in the $w \ge 0$ hemisphere. + + + \vspace{.1 in} + In some applications you only want the fouraxis to be returned to the + application program when the user releases the mouse, i.e., not all the time. + The routine + \begin{verbatim} + void fl_set_fouraxis_return(FL_OBJECT *obj, int always) + \end{verbatim} + controls this; set {\em always} to FALSE to get this effect. + + + \subsubsection*{Other routines} + + To set the value of the fouraxis, use the routines: + + \begin{verbatim} + void fl_set_fouraxis(FL_OBJECT *obj, float x, float y, float z) + + void fl_set_fouraxis_basis(FL_OBJECT *obj, float *matrix) + \end{verbatim} + + The first form just sets the $(x,y,z)$ components, computing $w$ to form + a unit vector. The second form supplies a complete 4x4 basis matrix; + the fouraxis object orthogonalizes it (perturbing the matrix if it was + nearly singular) and uses the fourth column as the chosen $(x,y,z,w)$ vector. + (The user-supplied matrix is not changed.) + Orthogonalization begins with the fourth column, so if that's already a unit + vector, it becomes the exactly the chosen vector. + The matrix is assumed in row-major order, i.e. its "fourth column" is + $matrix[4*j + 3]$ for $0 \le j \le 3$. + + \vspace{.1 in} + To obtain the current values of the fouraxis, use + + \begin{verbatim} + void fl_get_fouraxis(FL_OBJECT *obj, + float *x, float *y, float *z, float *w) + + void fl_get_fouraxis_basis(FL_OBJECT *obj, float *matrix) + \end{verbatim} + + fl\_get\_fouraxis() returns the current components of the chosen vector. + fl\_get\_fouraxis\_basis() returns a complete orthonormal basis, whose + fourth column is the chosen vector. + + \vspace{.1 in} + The wireframe sphere's appearance may be adjusted with + \begin{verbatim} + void fl_set_fouraxis_grid(FL_OBJECT *obj, int lat, int lon, int color) + void fl_get_fouraxis_grid(FL_OBJECT *obj, int *lat, int *lon, int *color) + \end{verbatim} + specifying respectively the number of latitude and longitude circles + and their color; defaults are 9, 12, and 0 (black). + \verb+fl_set_fouraxis_grid()+ + sets the values; \verb+fl_get_fouraxis_grid()+ returns current values. + + \subsubsection*{Attributes} + + Color1 controls the color of the box (default gray), + color2 is the color of the radial vector (default red). + + \subsubsection*{Remarks} + + Demos appear in demof01.c and demof02.c. + + \vspace{.1 in} + The orthogonal blue axes bear no relation to the other vectors + in the orthonormal basis; they're simply a perspective guide! + + \vspace {.1 in} + The basis matrix might be useful in applications which take a + 3-D projection of a 4-D object. The 4x4 matrix $M$ specifies + a change of basis into a coordinate system whose fourth coordinate + is along the vector chosen with the fouraxis widget. + It's easy to construct either orthogonal or perspective projections into + 3-space using the basis. Given a 4-component column vector $(x,y,z,w)$ + representing a point $p$, let the product $M p = (x',y',z',w')$. + For orthogonal projection, just discard $w'$: $(x',y',z')$ is the result of + projecting $p$. For perspective projection, you'll need to specify a place + to project from; choose some constant $w'_0$, which should be outside the + range of $w'$ values of the 4-D object. The further $w'_0$ is from the + object's $w'$ range, the less the perspective distortion. + A perspective projection of $p$ is then $(x',y',z')/(w' - w'_0)$. + + The basis' $(x',y',z')$ directions are somewhat arbitrary. + The widget tries to change them as little as possible + from their initial condition (the identity matrix), or from the + latest state set with \verb+fl_set_fouraxis_basis()+. + + \vspace{.1 in} + Two experimental fouraxis types exist, which use different + perspective cues to show where the vector's tip lies in the 3-ball. + \verb+FL_CIRCLE_FOURAXIS+ simply draws a solid blue circle, showing the + sphere's intersection with the plane normal to the chosen vector. + \verb+FL_SPOKED_FOURAXIS+ shows a circle with five radial spokes. Neither one + looks as good as \verb+FL_NORMAL_FOURAXIS+ to my eye. + ... create new file colorwheel.h ... *** /dev/null Wed Oct 20 19:15:53 1993 --- new/FORMS/INCLUDE/colorwheel.h Wed Dec 30 16:55:33 1992 *************** *** 0 **** --- 1,24 ---- + #ifndef COLORWHEEL_H + #define COLORWHEEL_H + + #define FL_COLORWHEEL_BW FL_BUTTON_BW + + #define FL_COLORWHEEL_CURSOR .025 + + #define FL_COLORWHEEL 1492 + #define FL_NORMAL_COLORWHEEL 0 + + FL_OBJECT *fl_create_colorwheel(int type, float x, float y, float w, + float h, char label[]); + FL_OBJECT *fl_add_colorwheel(int type, float x, float y, float w, float h, + char label[]); + + void fl_set_colorwheel(FL_OBJECT *obj, float *color); + void fl_set_colorwheel_intensity(FL_OBJECT *obj, float intensity); + void fl_set_colorwheel_alpha(FL_OBJECT *obj, float alpha); + + void fl_get_colorwheel(FL_OBJECT *obj, float *color); + float fl_get_colorwheel_intensity(FL_OBJECT *obj); + float fl_get_colorwheel_alpha(FL_OBJECT *obj); + + #endif ... create new file fouraxis.h ... *** /dev/null Wed Oct 20 19:15:53 1993 --- new/FORMS/INCLUDE/fouraxis.h Mon Aug 31 11:09:53 1992 *************** *** 0 **** --- 1,41 ---- + /************ Object Class: Fouraxis (unit vector in 4-space) ************/ + + /***** Class *****/ + + #define FL_FOURAXIS 1034 + + /***** Types *****/ + + #define FL_NORMAL_FOURAXIS 0 + #define FL_CIRCLE_FOURAXIS 1 + #define FL_SPOKED_FOURAXIS 2 + + /***** Defaults *****/ + + #define FL_FOURAXIS_BOXTYPE FL_DOWN_BOX + #define FL_FOURAXIS_COL1 FL_COL1 + #define FL_FOURAXIS_COL2 1 + #define FL_FOURAXIS_LCOL FL_LCOL + #define FL_FOURAXIS_ALIGN FL_ALIGN_BOTTOM + + /***** Others *****/ + + #define FL_FOURAXIS_BW FL_BOUND_WIDTH + + /***** Routines *****/ + + FL_OBJECT *fl_create_fouraxis(int, float, float, float, float, char []); + FL_OBJECT *fl_add_fouraxis(int, float, float, float, float, char []); + + /* Set direction vector. w chosen to form unit vector */ + void fl_set_fouraxis(FL_OBJECT *, float x, float y, float z); + void fl_get_fouraxis(FL_OBJECT *, float *xp, float *yp, float *zp, float *wp); + /* Also maintains an orthonormal basis matrix, with column 3 + * (w) a unit vector in the chosen direction + * and other columns chosen appropriately. + */ + void fl_get_fouraxis_basis(FL_OBJECT *, float * /* really float[4][4] */); + void fl_set_fouraxis_basis(FL_OBJECT *, float * /* really float[4][4] */); + + void fl_set_fouraxis_return(FL_OBJECT *, int); + ... create new file colorwheel.c ... *** /dev/null Wed Oct 20 19:15:53 1993 --- new/FORMS/colorwheel.c Thu Oct 14 19:43:18 1993 *************** *** 0 **** --- 1,307 ---- + #include + #include + #include + #include + #include "forms.h" + + /* The colors at the vertices of the hexagon */ + static float colors[][4] = {{1, 1, 1, 1}, + {1, 0, 0, 1}, {1, 1, 0, 1}, {0, 1, 0, 1}, + {0, 1, 1, 1}, {0, 0, 1, 1}, {1, 0, 1, 1}}; + /* The vertices of the unit hexagon */ + static float verts[7][2]; + + + /* + * obj->spec contains: + * 14 floats containing the center followed by the vertices of the hexagon + * 2 floats containing the position of the pointer in the hexagon + */ + /* These macros rely on the object in question being stored in obj */ + typedef struct { + float pointer[2]; + float intensity; + float alpha; + float radius; + float colors[7][4]; + } SpecStruct; + + #define NEWRADIUS(a) (((a)->w < (a)->h ? (a)->w/2.0 : (a)->h/2.0)) + + #define CURSOR_RADIUS .95 + + #define SPEC_SIZE (sizeof(SpecStruct)) + #define VERT (((SpecStruct *)obj->spec)->vert) + #define POINTER (((SpecStruct *)obj->spec)->pointer) + #define INTENSITY (((SpecStruct *)obj->spec)->intensity) + #define ALPHAVAL (((SpecStruct *)obj->spec)->alpha) + #define RADIUS (((SpecStruct *)obj->spec)->radius) + #define COLOR (((SpecStruct *)obj->spec)->colors) + + #define MIN(a, b) ((a) < (b) ? (a) : (b)) + #define MAX(a, b) ((a) > (b) ? (a) : (b)) + + #define ONE(a) (MIN(MAX((a), 0.0), 1.0)) + + #define MAX3(a, b, c) \ + ((a) > (b) ? \ + ((a) > (c) ? (a) : (c)) : \ + ((b) > (c) ? (b) : (c))) + + #define MIN3(a, b, c) \ + ((a) < (b) ? \ + ((a) < (c) ? (a) : (c)) : \ + ((b) < (c) ? (b) : (c))) \ + + static int handle_colorwheel(FL_OBJECT *obj, int event, float mx, float my, + char key); + static float scale_to_hexagon(FL_OBJECT *obj, float x, float y); + + FL_OBJECT *fl_create_colorwheel(int type, float x, float y, float w, + float h, char label[]) + { + FL_OBJECT *obj; + + /* We might be recomputing these, but c'est la vie */ + verts[0][0] = verts[0][1] = 0.0; + + verts[1][0] = 1.0; + verts[4][0] = -verts[1][0]; + verts[1][1] = verts[4][1] = 0.0; + + verts[2][0] = verts[6][0] = cos(M_PI / 3.0); + verts[3][0] = verts[5][0] = -verts[2][0]; + verts[2][1] = verts[3][1] = sin(M_PI / 3.0); + verts[5][1] = verts[6][1] = -verts[2][1]; + + obj = fl_make_object(FL_COLORWHEEL, type, x, y, w, h, label, + handle_colorwheel); + + obj->boxtype = FL_UP_BOX; + obj->lcol = BLACK; + obj->col1 = FL_BUTTON_COL1; + obj->col2 = BLACK; + obj->align = FL_ALIGN_BOTTOM; + + obj->spec = (int *)malloc(SPEC_SIZE); + + POINTER[0] = POINTER[1] = 0.0; + RADIUS = NEWRADIUS(obj); + + INTENSITY = 1.0; + ALPHAVAL = 1.0; + + return obj; + } + + FL_OBJECT *fl_add_colorwheel(int type, float x, float y, float w, float h, + char label[]) + { + FL_OBJECT *obj; + obj = fl_create_colorwheel(type, x, y, w, h, label); + fl_add_object(fl_current_form, obj); + return obj; + } + + static int handle_colorwheel(FL_OBJECT *obj, int event, float mx, float my, + char key) + { + int i; + int center[2]; + float scalef; + + switch(event) { + case FL_DRAW: + + fl_drw_box(obj->boxtype, obj->x, obj->y, obj->w, obj->h, obj->col1, + FL_COLORWHEEL_BW); + for (i = 0; i < 7; i++) { + COLOR[i][0] = colors[i][0] * INTENSITY; + COLOR[i][1] = colors[i][1] * INTENSITY; + COLOR[i][2] = colors[i][2] * INTENSITY; + COLOR[i][3] = ALPHAVAL; + } + blendfunction(BF_SA, BF_MSA); + + center[0] = obj->x + obj->w / 2.0; + center[1] = obj->y + obj->h / 2.0; + pushmatrix(); + translate(center[0], center[1], 0.0); + RADIUS = NEWRADIUS(obj); + scale(RADIUS, RADIUS, RADIUS); + for (i = 0; i < 6; i++) { + bgnpolygon(); + c4f(COLOR[0]); + v2f(verts[0]); + + c4f(COLOR[i + 1]); + v2f(verts[i+1]); + + c4f(COLOR[((i+1)%6) + 1]); + v2f(verts[((i+1)%6)+1]); + endpolygon(); + } + scale(CURSOR_RADIUS, CURSOR_RADIUS, CURSOR_RADIUS); + fl_rect(POINTER[0] - FL_COLORWHEEL_CURSOR, + POINTER[1] - FL_COLORWHEEL_CURSOR, + 2.0 * FL_COLORWHEEL_CURSOR, 2.0 * FL_COLORWHEEL_CURSOR, + obj->col2); + popmatrix(); + fl_drw_text_beside(obj->align, obj->x, obj->y, obj->w, obj->h, + obj->lcol, obj->lsize, obj->lstyle, obj->label); + return 0; + case FL_PUSH: + case FL_RELEASE: + case FL_MOUSE: + RADIUS = NEWRADIUS(obj); + POINTER[0] = (mx - obj->w/2.0 - obj->x) / RADIUS; + POINTER[1] = (my - obj->h/2.0 - obj->y) / RADIUS; + + /* Get it within the hexagon vertically */ + scalef = scale_to_hexagon(obj, POINTER[0], POINTER[1]); + if (scalef < 1.0) { + POINTER[0] *= scalef; + POINTER[1] *= scalef; + } + + fl_redraw_object(obj); + return 1; + default: + return 0; + } + } + + void fl_set_colorwheel_alpha(FL_OBJECT *obj, float alpha) { + ALPHAVAL = ONE(alpha); + fl_redraw_object(obj); + } + + float fl_get_colorwheel_alpha(FL_OBJECT *obj) { + return ALPHAVAL; + } + + void fl_set_colorwheel_intensity(FL_OBJECT *obj, float intensity) { + INTENSITY = ONE(intensity); + fl_redraw_object(obj); + } + + float fl_get_colorwheel_intensity(FL_OBJECT *obj) { + return INTENSITY; + } + + void fl_set_colorwheel(FL_OBJECT *obj, float *color) + { + float h, s, v; + float min, max, delta, scale; + float r = ONE(color[0]), g = ONE(color[1]), b = ONE(color[2]); + + max = MAX3(r, g, b); + min = MIN3(r, g, b); + v = max; + if (max > .001) s = (max - min) / max; + else s = 0.0; + + if (s < .001) POINTER[0] = POINTER[1] = 0.0; + else { + delta = max - min; + if (r == max) h = (g - b) / delta; + else if (g == max) h = 2.0 + (b - r) / delta; + else if (b == max) h = 4.0 + (r - g) / delta; + h *= 60.0; + if (h < .001) h += 360.0; + + h = (h / 180.0) * M_PI; + scale = scale_to_hexagon(obj, cos(h), sin(h)); + POINTER[0] = cos(h) * s * scale; + POINTER[1] = sin(h) * s * scale; + } + + INTENSITY = v; + + fl_redraw_object(obj); + } + + void fl_get_colorwheel(FL_OBJECT *obj, float *color) + { + int i; + float f, p, q, t; + float h, s, v; + float radius; + + v = INTENSITY; + if (fabs(POINTER[0]) < .001 && fabs(POINTER[1]) < .001) { + color[0] = color[1] = color[2] = v; + return; + } + s = 1.0 / scale_to_hexagon(obj, POINTER[0], POINTER[1]); + /* The point must already be inside the hexagon, but we may be suffering + * from round-off error */ + if (s > 1.0) s = 1.0; + + h = (atan2(POINTER[1],POINTER[0]) / M_PI) * 180.0; + if (h < 0.0) h = 360.0 + h; + if (h >= 360.0) h = 0.0; + h = h / 60.0; + i = floor(h); + f = h - (float)i; + p = v * (1.0 - s); + q = v * (1.0 - (s * f)); + t = v * (1.0 - (s * (1.0 - f))); + switch(i) { + case 0: + color[0] = v; + color[1] = t; + color[2] = p; + break; + case 1: + color[0] = q; + color[1] = v; + color[2] = p; + break; + case 2: + color[0] = p; + color[1] = v; + color[2] = t; + break; + case 3: + color[0] = p; + color[1] = q; + color[2] = v; + break; + case 4: + color[0] = t; + color[1] = p; + color[2] = v; + break; + case 5: + color[0] = v; + color[1] = p; + color[2] = q; + break; + default: + break; + } + + } + + /* + * This finds the t that should multiply x and y to place the point + * on the hexagon. + * Returns 1000 ("large") if x == 0 && y == 0 + * < 1.0 = point outside + * > 1.0 = point inside + */ + #define HEX 1.73205 /* sqrt(3) */ + static float scale_to_hexagon(FL_OBJECT *obj, float x, float y) + { + x = fabs(x); + y = fabs(y); + if (y == 0) { + return x < .001 ? 1000 : 1/x; /* Scale X to horiz hexagon corner */ + } else if (x*HEX < y) { + return .5*HEX/y; /* Scale Y to top of hexagon, at sqrt(3)/2 */ + } else { + return HEX/(y + HEX*x); /* Scale to slanted hexagon side */ + } + } + #undef HEX ... create new file fouraxis.c ... *** /dev/null Wed Oct 20 19:15:53 1993 --- new/FORMS/fouraxis.c Fri Nov 6 10:14:05 1992 *************** *** 0 **** --- 1,397 ---- + /************************************************************************ + * * + * Object class: FOURAXIS * + * * + * Written by: Stuart Levy; adapted from Mark Overmars' POSITIONER * + * * + * Version 1.1 * + * Date: 28 May 1992 * + ************************************************************************/ + + #include + #include + #include + #include + #include + #include "forms.h" + + /* State of a fouraxis */ + typedef struct { + int gridcolor; /* color for grid drawing */ + int gridlong, gridlat; /* how many grid circles to draw */ + int colorless; /* Crosses in red/green/blue, else col2 */ + int allout; /* All crosses extend to sphere edge */ + + float rho, theta, phi; /* user-interface controls */ + float omx, omy; /* prev mouse position */ + int whatsdown; /* -1: omx,omy invalid. + * 0: left mouse down. 1: right mouse. + */ + float T[4][4]; /* Initial basis matrix, which we */ + /* should try to approximate */ + int always; /* whether always returning value */ + } SPEC; + + + #define X 0 + #define Y 1 + #define Z 2 + #define W 3 + + static void orthog4(float T[4][4]); + static void transpose(float *src, float *dst); + + + static void drawsphere(register SPEC *sp) + { + register int i; + static int setls = 0; + + if(!setls) { + deflinestyle(FL_FOURAXIS, 0xCCCC); + setls = 1; + } + pushattributes(); + pushmatrix(); + setlinestyle(FL_FOURAXIS); + for(i = sp->gridlong; --i >= 0; ) { + circ(0.0, 0.0, 1.0); + rot(180./sp->gridlong, 'y'); + } + popmatrix(); + pushmatrix(); + rot(90., 'x'); + circ(0.0, 0.0, 1.0); + for(i = sp->gridlat; --i > 0; ) { + float s = sin(M_PI_2 * i / sp->gridlat); + float c = fsqrt(1 - s*s); + + translate(0.0, 0.0, c); + circ(0.0, 0.0, s); + translate(0.0, 0.0, -2*c); + circ(0.0, 0.0, s); + translate(0.0, 0.0, c); + } + popmatrix(); + popattributes(); + } + + static void drawaxis(register SPEC *sp, FL_OBJECT *ob) + { + float v = fsqrt(1 - sp->rho * sp->rho); + int i; + + pushmatrix(); + pushattributes(); + rot(sp->theta, 'y'); + rot(sp->phi, 'z'); + move(0., 0., 0.); + draw(sp->allout ? 1. : sp->rho, 0., 0.); + + switch(ob->type & 7) { + case FL_NORMAL_FOURAXIS: + if(!sp->colorless) fl_color(4); + move(sp->rho, 0., 0.); + draw(sp->rho, v, 0.); + + move(sp->rho, 0., 0.); + draw(sp->rho, 0., v); + break; + case FL_SPOKED_FOURAXIS: + case FL_CIRCLE_FOURAXIS: + if(!sp->colorless) fl_color(4); + translate(sp->rho, 0., 0.); + rot(90., 'y'); + circ(0., 0., v); + if((ob->type & 7) == FL_CIRCLE_FOURAXIS) + break; + setlinestyle(FL_FOURAXIS); + for(i=0; i<5; i++) { + move(0., 0., 0.); + draw(v, 0., 0.); + rot(72., 'z'); + } + } + + popattributes(); + popmatrix(); + } + + static void draw_fouraxis(register FL_OBJECT *ob) + /* Draws a fouraxis */ + { + SPEC *sp = ((SPEC *)(ob->spec)); + Matrix T; + + float wx, wy; + + wx = FL_FOURAXIS_BW; + wy = FL_FOURAXIS_BW; + fl_drw_box(ob->boxtype,ob->x,ob->y,ob->w,ob->h,ob->col1,FL_FOURAXIS_BW); + fl_drw_text_beside(ob->align,ob->x,ob->y,ob->w,ob->h, + ob->lcol,ob->lsize,ob->lstyle,ob->label); + pushmatrix(); + pushviewport(); + pushattributes(); + viewport(ob->x + wx, ob->x + ob->w - wx, ob->y + wy, ob->y + ob->h - wy); + perspective(900, (float)(ob->w - 2*wx) / (ob->h - 2*wy), .5, 4); + translate(0., 0., -1.5); + fl_color(sp->gridcolor); + drawsphere(sp); + linewidth(2); + fl_color(ob->col2); + drawaxis(sp, ob); + popattributes(); + popviewport(); + popmatrix(); + } + + static int handle_mouse(FL_OBJECT *ob,float mx,float my, int key) + /* Handle a mouse position change */ + { + register SPEC *sp = ((SPEC *)(ob->spec)); + float du, dv; + + du = (mx - sp->omx) / ob->w; + dv = (my - sp->omy) / ob->h; + sp->omx = mx; + sp->omy = my; + if(sp->whatsdown < 0) { + sp->whatsdown = getbutton(RIGHTMOUSE); + return 0; + } + + if(du == 0 && dv == 0) + return 0; + + if(sp->whatsdown) { + sp->rho += .5 * (du-dv); /* rightmouse: rho (x motion) / w (y motion) */ + if(sp->rho < 0) sp->rho = 0; + else if(sp->rho > 1) sp->rho = 1; + } else { + sp->theta += 180. * du; /* leftmouse: theta (x) / phi (y) */ + sp->phi += 90. * dv; + if(sp->phi > 90.) sp->phi = 90.; + else if(sp->phi < -90.) sp->phi = -90.; + } + fl_redraw_object(ob); + + return 1; + } + + static int handle_fouraxis(FL_OBJECT *ob,int event,float mx,float my,int key) + /* Handles an event */ + { + SPEC *sp = (SPEC *) ob->spec; + switch (event) + { + case FL_DRAW: + draw_fouraxis(ob); + return 0; + case FL_PUSH: + case FL_MOUSE: + return ( handle_mouse(ob,mx,my,key) && sp->always); + case FL_RELEASE: + sp->whatsdown = -1; + return (! sp->always); + } + return 0; + } + + /*------------------------------*/ + + FL_OBJECT *fl_create_fouraxis(int type,float x,float y,float w,float h,char label[]) + /* creates an object */ + { + FL_OBJECT *ob; + register SPEC *sp; + + ob = fl_make_object(FL_FOURAXIS,type,x,y,w,h,label,handle_fouraxis); + ob->boxtype = FL_FOURAXIS_BOXTYPE; + ob->col1 = FL_FOURAXIS_COL1; + ob->col2 = FL_FOURAXIS_COL2; + ob->align = FL_FOURAXIS_ALIGN; + ob->lcol = FL_FOURAXIS_LCOL; + + ob->spec = (int *) malloc(sizeof(SPEC)); + sp = (SPEC *)ob->spec; + sp->rho = 0.5; + sp->theta = 45.; + sp->phi = 45.; + sp->whatsdown = -1; + sp->gridlong = 12; /* 24 meridians */ + sp->gridlat = 9; /* 18 parallels */ + sp->gridcolor = 0; /* black wireframe sphere */ + sp->colorless = type & 8; + sp->allout = type & 0x10; + sp->always = TRUE; + bzero(sp->T, 16*sizeof(float)); + + return ob; + } + + FL_OBJECT *fl_add_fouraxis(int type,float x,float y,float w,float h,char label[]) + /* Adds an object */ + { + FL_OBJECT *ob; + ob = fl_create_fouraxis(type,x,y,w,h,label); + fl_add_object(fl_current_form,ob); + return ob; + } + + void fl_set_fouraxis(FL_OBJECT *ob,float x, float y, float z) + /* Aims the axis */ + { + register SPEC *sp = (SPEC *)ob->spec; + float xy2 = x*x + y*y; + register int i,j; + /* Map to rho, theta, phi */ + sp->rho = fsqrt(xy2 + z*z); + sp->theta = (y == 0 && x == 0) ? 0 : (180/M_PI)*atan2(y,x); + sp->phi = (sp->rho == 0) ? 0 : (180/M_PI)*atan2(z, fsqrt(xy2)); + + sp->T[W][X] = x; sp->T[W][Y] = y; sp->T[W][Z] = z; + sp->T[W][W] = fsqrt(1 - xy2 + z*z); + + fl_redraw_object(ob); + } + + + void fl_get_fouraxis(FL_OBJECT *ob,float *x, float *y, float *z, float *w) + /* Returns the axis */ + { + register SPEC *sp = (SPEC *)ob->spec; + float r; + + *w = fsqrt(1 - sp->rho*sp->rho); + r = sp->rho * cos(sp->phi * M_PI/180); + *x = r * cos(sp->theta * M_PI/180); + *y = r * sin(sp->theta * M_PI/180); + *z = sp->rho * sin(sp->phi * M_PI/180); + } + + void fl_set_fouraxis_grid(FL_OBJECT *ob, int lat, int lon, int col) + { + register SPEC *sp = (SPEC *)ob->spec; + if(lat >= 0) sp->gridlat = lat; + if(lon >= 0) sp->gridlong = lon; + if(col >= 0) sp->gridcolor = col; + } + + void fl_get_fouraxis_grid(FL_OBJECT *ob, int *lat, int *lon, int *col) + { + register SPEC *sp = (SPEC *)ob->spec; + if(lat) *lat = sp->gridlat; + if(lon) *lon = sp->gridlong; + if(col) *col = sp->gridcolor; + } + + static void transpose(float *src, float *dst) + { + register int i, j; + register float v; + + for(i=0; i<4; i++) for(j=0; j<4; j++) + dst[i*4+j] = src[j*4+i]; + } + + void fl_set_fouraxis_basis(FL_OBJECT *ob, float *matrix) + { + register SPEC *sp = (SPEC *)ob->spec; + float T[4][4]; + + transpose(matrix, (float *)sp->T); + bcopy(sp->T, T, sizeof(T)); + orthog4(T); + fl_set_fouraxis(ob, T[W][X], T[W][Y], T[W][Z]); + } + + void fl_get_fouraxis_basis(FL_OBJECT *ob, float *matrix) + { + register SPEC *sp = (SPEC *)ob->spec; + float T[4][4]; + + bcopy(sp->T, T, sizeof(T)); + fl_get_fouraxis(ob, &T[W][X], &T[W][Y], &T[W][Z], &T[W][W]); + orthog4(T); + transpose((float *)T, matrix); + } + + void fl_set_fouraxis_return(FL_OBJECT *ob, int value) + /* Sets whether to return value all the time */ + { + ((SPEC *)(ob->spec))->always = value; + } + + + #include + + typedef float Point[4]; + + #define DOT(a, b) ((a)[0]*(b)[0] + (a)[1]*(b)[1] + (a)[2]*(b)[2] + (a)[3]*(b)[3]) + #define VCOPY(src,dst) bcopy((char*)(src), (char*)(dst), sizeof(Point)) + #define VSCALE(s, dst) (dst)[0]*=s, (dst)[1]*=s, (dst)[2]*=s, (dst)[3]*=s + + #define VSSUB(src,s, dst) { register float t = s; \ + (dst)[0] -= t*(src)[0], \ + (dst)[1] -= t*(src)[1], \ + (dst)[2] -= t*(src)[2], \ + (dst)[3] -= t*(src)[3]; \ + } + + /* + * orthog4() accepts three 4-space vectors -- pw, pz, py -- and + * constructs an orthogonal basis of unit vectors X, Y, Z, W where + * W = normalized pw, + * Z is the normalized projection of pz on the space orthogonal to pw, + * Y is the normalized projection of py on the plane orthogonal to pw and pz, + * X is perpendicular to the other three. + * In degenerate cases (zero or nearly coplanar vectors pw, pz, py), + * the vectors are arbitrarily perturbed until they're distinct. + * Result is a 4x4 matrix representing a transformation from + * the supplied coordinate system to the newly constructed one. + * The vectors X, Y, Z, W appear as columns 0, 1, 2, 3 of the resulting matrix. + */ + static void + orthog4(register float M[4][4]) + { + register float s; + register int k; + + s = DOT(M[3],M[3]); + if(s == 0) + M[3][3] = 1.0; + else { + s = 1/fsqrt(s); + VSCALE(s, M[3]); + } + + for(k = 2; ; k++, k %= 4) { + VSSUB(M[3], DOT(M[3],M[2]), M[2]); + if((s = DOT(M[2],M[2])) > 0.05) + break; + M[2][k] += 1.0; + } + + VSCALE(1/fsqrt(s), M[2]); + + for(k = 1; ; k++, k %= 4) { + VSSUB(M[3], DOT(M[3],M[1]), M[1]); + VSSUB(M[2], DOT(M[2],M[1]), M[1]); + s = DOT(M[1],M[1]); + if(s > 0.05) + break; + M[1][k] += 1.0; + } + + for(k = 0; ; k++, k %= 4) { + VSSUB(M[3], DOT(M[3],M[0]), M[0]); + VSSUB(M[2], DOT(M[2],M[0]), M[0]); + VSSUB(M[1], DOT(M[1],M[0]), M[0]); + if((s = DOT(M[0],M[0])) > 0.05) + break; + M[0][k] += 1.0; + } + VSCALE(1/fsqrt(s), M[0]); + } +