/* * xvgam.c * * callable functions: * */ /* Copyright Notice * ================ * Copyright 1989, 1990, 1991, 1992, 1993 by John Bradley * * Permission to use, copy, and distribute XV in its entirety, for * non-commercial purposes, is hereby granted without fee, provided that * this license information and copyright notice appear in all copies. * * Note that distributing XV 'bundled' in with ANY product is considered * to be a 'commercial purpose'. * * Also note that any copies of XV that are distributed MUST be built * and/or configured to be in their 'unregistered copy' mode, so that it * is made obvious to the user that XV is shareware, and that they should * consider donating, or at least reading this License Info. * * The software may be modified for your own purposes, but modified * versions may NOT be distributed without prior consent of the author. * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author be held liable for any damages * arising from the use of this software. * * If you would like to do something with XV that this copyright * prohibits (such as distributing it with a commercial product, * using portions of the source in some other program, etc.), please * contact the author (preferably via email). Arrangements can * probably be worked out. * * XV is shareware for PERSONAL USE only. You may use XV for your own * amusement, and if you find it nifty, useful, generally cool, or of * some value to you, your non-deductable donation would be greatly * appreciated. $25 is the suggested donation, though, of course, * larger donations are quite welcome. Folks who donate $25 or more * can receive a Real Nice bound copy of the XV manual for no extra * charge. * * Commercial, government, and institutional users MUST register their * copies of XV, for the exceedingly REASONABLE price of just $25 per * workstation/X terminal. Site licenses are available for those who * wish to run XV on a large number of machines. Contact the author * for more details. * * The author may be contacted via: * US Mail: John Bradley * 1053 Floyd Terrace * Bryn Mawr, PA 19010 * * Phone: (215) 898-8813 * EMail: bradley@cis.upenn.edu */ #include "xv.h" #include "bitmaps.h" #define GAMW 664 #define GAMH 518 #define GAMbutF 386 #define CMAPX 10 #define CMAPY 17 #define CMAPCW 12 #define CMAPCH 9 #define CMAPW (CMAPCW * 16) #define CMAPH (CMAPCH * 16) #define MAXUNDO 32 #define BUTTH 23 #define N_HMAP 6 /* # of Hue modification remappings */ #define N_HDBUTT 5 #define HDB_ROTL 0 #define HDB_ROTR 1 #define HDB_EXPND 2 #define HDB_SHRNK 3 #define HDB_FLIP 4 #define N_HDBUTT2 4 #define HDB_DESAT 2 #define HDB_SAT 3 #define HD_CLEAR 0x01 /* clears inside of hue dial */ #define HD_FRAME 0x02 #define HD_HANDS 0x04 #define HD_DIR 0x08 #define HD_VALS 0x10 #define HD_TITLE 0x20 #define HD_CLHNDS 0x40 #define HD_BUTTS 0x80 #define HD_ALL (HD_FRAME | HD_HANDS | HD_DIR | HD_VALS | HD_TITLE | HD_BUTTS) #define HD_RADIUS 30 /* radius of bounding circle of HDIALs */ #define DEG2RAD (3.14159 / 180.0) #define RAD2DEG (180.0 / 3.14159) /* stuff for colormap Undo button */ struct cmapstate { byte rm[256], gm[256], bm[256]; int cellgroup[256]; int curgroup; int maxgroup; int editColor; } prevcmap, tmpcmap; struct hmap { int src_st; int src_en; int src_ccw; int dst_st; int dst_en; int dst_ccw; }; struct gamstate { struct hmap hmap[N_HMAP]; int hueRBnum; /* 1 - 6 */ int wht_stval, wht_satval, wht_enab; int satval; GRAF_STATE istate, rstate, gstate, bstate; } undo[MAXUNDO], preset[4], defstate; struct gamstate *defLoadState; static int uptr, uhead, utail; typedef struct huedial { Window win; /* window that dial exists in */ int x,y; /* coordinates of center of dial */ int range; /* 0 = single value, 1 = range */ int stval; /* start of range (ONLY val ifnot range) */ int enval; /* end of range */ int ccwise; /* 1 if range goes ccwise, 0 if cwise */ char *str; /* title string */ u_long fg,bg; /* colors */ int satval; /* saturation value on non-range dial */ BUTT hdbutt[N_HDBUTT]; CBUTT enabCB; void (*drawobj)(); } HDIAL; static BUTT hueclrB; static CBUTT enabCB, autoCB, resetCB, dragCB; static HDIAL srcHD, dstHD, whtHD; static DIAL satDial, rhDial, gsDial, bvDial; static GRAF intGraf, rGraf, gGraf, bGraf; static RBUTT *hueRB; static Window cmapF, hsvF, rgbF, modF, butF; static struct hmap hmap[N_HMAP]; static int hremap[360]; static int defAutoApply; static int hsvnonlinear = 0; #ifdef __STDC__ static void computeHSVlinear(void); static void changedGam(void); static void drawGam(int,int,int,int); static void drawBut(int,int,int,int); static void drawArrow(int, int); static void drawCmap(void); static void clickCmap(int,int,int); static void clickGam(int,int); static void selectCell(int,int); static int deladdCell(int, int); static void doCmd(int); static void SetHSVmode(void); static void applyGamma(int); static void calcHistEQ(int *, int *, int *); static void saveGamState(void); static void gamUndo(void); static void gamRedo(void); static void ctrls2gamstate(struct gamstate *); static void gamstate2ctrls(struct gamstate *); static void rndCols(void); static void saveCMap(struct cmapstate *); static void restoreCMap(struct cmapstate *); static void parseResources(void); static void makeResources(void); static void dragGamma(void); static void dragHueDial(void); static void dragEditColor(void); static void HDCreate(HDIAL *, Window, int, int, int, int, int, int, char *, u_long, u_long); static void HDRedraw(HDIAL *, int); static int HDClick(HDIAL *, int, int); static int HDTrack(HDIAL *, int, int); static int hdg2xdg(int); static void pol2xy(int, int, double, int, int *, int *); static int computeHDval(HDIAL *, int, int); static void initHmap(void); static void init1hmap(int); static void dials2hmap(void); static void hmap2dials(void); static void build_hremap(void); #else static void computeHSVlinear(); static void changedGam(), drawGam(), drawBut(), drawArrow(), drawCmap(); static void clickCmap(), clickGam(), selectCell(); static void doCmd(), applyGamma(), calcHistEQ(); static int deladdCell(); static void SetHSVmode(), saveGamState(), gamUndo(), gamRedo(); static void ctrls2gamstate(), gamstate2ctrls(); static void rndCols(), saveCMap(), restoreCMap(), parseResources(); static void makeResources(); static void dragGamma(), dragHueDial(), dragEditColor(); static void HDCreate(), HDRedraw(), pol2xy(); static int HDClick(), HDTrack(), hdg2xdg(), computeHDval(); static void initHmap(), init1hmap(), dials2hmap(), hmap2dials(); static void build_hremap(); #endif #define CMAPF_WIDE 212 #define CMAPF_HIGH 322 #define BUTF_WIDE 212 #define BUTF_HIGH 96 #define MODF_WIDE 212 #define MODF_HIGH 70 #define HSVF_WIDE 205 #define HSVF_HIGH 500 #define RGBF_WIDE 185 #define RGBF_HIGH 500 #undef TIMING_TEST #ifdef TIMING_TEST #include #endif /***************************/ static void printUTime(str) char *str; { #ifdef TIMING_TEST int i; struct rusage ru; i = getrusage(RUSAGE_SELF, &ru); fprintf(stderr,"%s: utime = %ld.%ld seconds\n", str, ru.ru_utime.tv_sec, ru.ru_utime.tv_usec); #endif } /***************************************************/ void CreateGam(geom, gam, rgam, ggam, bgam, defpreset) char *geom; double gam, rgam, ggam, bgam; int defpreset; { XSetWindowAttributes xswa; gamW = CreateWindow("xv color editor", "XVcedit", geom, GAMW, GAMH, infofg,infobg, 0); if (!gamW) FatalError("can't create cedit window!"); cmapF = XCreateSimpleWindow(theDisp,gamW, 10, 8,CMAPF_WIDE,CMAPF_HIGH, 1,infofg,infobg); butF = XCreateSimpleWindow(theDisp,gamW, 10, 336,BUTF_WIDE,BUTF_HIGH, 1,infofg,infobg); modF = XCreateSimpleWindow(theDisp,gamW, 10, 438,MODF_WIDE,MODF_HIGH, 1,infofg,infobg); hsvF = XCreateSimpleWindow(theDisp,gamW, 242, 8,HSVF_WIDE,HSVF_HIGH, 1,infofg,infobg); rgbF = XCreateSimpleWindow(theDisp,gamW, 467, 8,RGBF_WIDE,RGBF_HIGH, 1,infofg,infobg); if (!cmapF || !butF || !modF || !hsvF || !rgbF) FatalError("couldn't create frame windows"); #ifdef BACKING_STORE xswa.backing_store = WhenMapped; XChangeWindowAttributes(theDisp, cmapF, CWBackingStore, &xswa); XChangeWindowAttributes(theDisp, butF, CWBackingStore, &xswa); XChangeWindowAttributes(theDisp, modF, CWBackingStore, &xswa); XChangeWindowAttributes(theDisp, hsvF, CWBackingStore, &xswa); #endif XSelectInput(theDisp, gamW, ExposureMask); XSelectInput(theDisp, cmapF, ExposureMask | ButtonPressMask); XSelectInput(theDisp, butF, ExposureMask | ButtonPressMask); XSelectInput(theDisp, modF, ExposureMask | ButtonPressMask); XSelectInput(theDisp, hsvF, ExposureMask | ButtonPressMask); XSelectInput(theDisp, rgbF, ExposureMask); if (ctrlColor) XSetWindowBackground(theDisp, gamW, locol); else XSetWindowBackgroundPixmap(theDisp, gamW, grayTile); /********** COLORMAP editing doo-wahs ***********/ BTCreate(&gbut[G_BCOLUNDO], cmapF, 5, 165, 66, BUTTH, "ColUndo", infofg, infobg, hicol, locol); BTCreate(&gbut[G_BCOLREV], cmapF, 5 + 66 + 1, 165, 67, BUTTH, "Revert", infofg, infobg, hicol, locol); BTCreate(&gbut[G_BHSVRGB], cmapF, 5+66+67+2, 165, 66, BUTTH, "RGB/HSV", infofg, infobg, hicol, locol); BTCreate(&gbut[G_BMONO], cmapF, 5, 189, 66, BUTTH, "Grey", infofg, infobg, hicol, locol); BTCreate(&gbut[G_BRV], cmapF, 5 + 66 + 1, 189, 67, BUTTH, "RevVid", infofg, infobg, hicol, locol); BTCreate(&gbut[G_BRNDCOL], cmapF, 5 + 66 + 67 + 2, 189, 66, BUTTH, "Random", infofg, infobg, hicol, locol); DCreate(&rhDial, cmapF, 5, 215, 66, 100, 0,360,180, 5, infofg, infobg, hicol, locol, "Hue", NULL); DCreate(&gsDial, cmapF, 72, 215, 66, 100, 0,360,180, 5, infofg, infobg, hicol, locol, "Sat.", NULL); DCreate(&bvDial, cmapF, 139, 215, 66, 100, 0,360,180, 5, infofg, infobg, hicol, locol, "Value", NULL); rhDial.drawobj = gsDial.drawobj = bvDial.drawobj = dragEditColor; /*********** CONTROL BUTTONS ***********/ /* positioning constants for buttons. (arranged as 4x4 grid...) */ #define BXSPACE 53 #define BYSPACE (BUTTH+1) #define BX0 0 #define BX1 (BX0 + BXSPACE) #define BX2 (BX0 + BXSPACE*2) #define BX3 (BX0 + BXSPACE*3) #define BY0 0 #define BY1 (BY0 + BYSPACE) #define BY2 (BY0 + BYSPACE*2) #define BY3 (BY0 + BYSPACE*3) BTCreate(&gbut[G_BAPPLY], butF, BX0,BY0, 52,BUTTH,"Apply", infofg,infobg,hicol,locol); BTCreate(&gbut[G_BNOGAM], butF, BX0,BY1, 52,BUTTH,"NoMod", infofg,infobg,hicol,locol); BTCreate(&gbut[G_BMAXCONT],butF, BX0,BY2, 52,BUTTH,"Norm", infofg,infobg,hicol,locol); BTCreate(&gbut[G_BHISTEQ], butF, BX0,BY3, 52,BUTTH,"HistEq", infofg,infobg,hicol,locol); BTCreate(&gbut[G_BUP_BR],butF, BX1,BY0, 52,BUTTH,"Brite", infofg,infobg,hicol,locol); BTCreate(&gbut[G_BDN_BR],butF, BX1,BY1, 52,BUTTH,"Dim", infofg,infobg,hicol,locol); BTCreate(&gbut[G_BUP_CN],butF, BX1,BY2, 52,BUTTH,"Sharp", infofg,infobg,hicol,locol); BTCreate(&gbut[G_BDN_CN],butF, BX1,BY3, 52,BUTTH,"Dull", infofg,infobg,hicol,locol); BTCreate(&gbut[G_BRESET],butF, BX2, BY0, 52,BUTTH,"Reset", infofg,infobg,hicol,locol); BTCreate(&gbut[G_B1], butF, BX2, BY1, 25,BUTTH,"1", infofg,infobg,hicol,locol); BTCreate(&gbut[G_B2], butF, BX2+26,BY1, 26,BUTTH,"2", infofg,infobg,hicol,locol); BTCreate(&gbut[G_B3], butF, BX2, BY2, 25,BUTTH,"3", infofg,infobg,hicol,locol); BTCreate(&gbut[G_B4], butF, BX2+26,BY2, 26,BUTTH,"4", infofg,infobg,hicol,locol); BTCreate(&gbut[G_BSET], butF, BX2, BY3, 52,BUTTH,"Set", infofg,infobg,hicol,locol); BTCreate(&gbut[G_BUNDO], butF, BX3, BY0, 52,BUTTH,"Undo", infofg,infobg,hicol,locol); BTCreate(&gbut[G_BREDO], butF, BX3, BY1, 52,BUTTH,"Redo", infofg,infobg,hicol,locol); BTCreate(&gbut[G_BGETRES],butF,BX3, BY2, 52,BUTTH,"CutRes", infofg,infobg,hicol,locol); BTCreate(&gbut[G_BCLOSE],butF, BX3, BY3, 52,BUTTH,"Close", infofg,infobg,hicol,locol); gbut[G_BSET].toggle = 1; gbut[G_BUNDO].active = 0; gbut[G_BREDO].active = 0; CBCreate(&enabCB, modF,2,2, "Display with HSV/RGB mods.", infofg,infobg,hicol,locol); CBCreate(&autoCB, modF,2,2+17, "Auto-apply HSV/RGB mods.", infofg,infobg,hicol,locol); CBCreate(&dragCB, modF,2,2+17*2,"Auto-apply while dragging.", infofg,infobg,hicol,locol); CBCreate(&resetCB,modF,2,2+17*3,"Auto-reset on new image.", infofg,infobg,hicol,locol); enabCB.val = autoCB.val = resetCB.val = dragCB.val = 1; defAutoApply = autoCB.val; /************ HSV editing doo-wahs **************/ HDCreate(&srcHD, hsvF, 52, 65, 1, 0, 30, 0, "From", infofg, infobg); HDCreate(&dstHD, hsvF, 154, 65, 1, 0, 30, 0, "To", infofg, infobg); HDCreate(&whtHD, hsvF, 50,243, 0, 0, 0, 0, "White",infofg, infobg); srcHD.drawobj = dstHD.drawobj = whtHD.drawobj = dragHueDial; DCreate(&satDial, hsvF, 100, 199, 100, 121, -100, 100, 0, 5, infofg, infobg,hicol,locol, "Saturation", "%"); hueRB = RBCreate(NULL, hsvF, 7, 153, "1", infofg, infobg,hicol,locol); RBCreate (hueRB,hsvF, 47, 153, "2", infofg, infobg,hicol,locol); RBCreate (hueRB,hsvF, 87, 153, "3", infofg, infobg,hicol,locol); RBCreate (hueRB,hsvF, 7, 170, "4", infofg, infobg,hicol,locol); RBCreate (hueRB,hsvF, 47, 170, "5", infofg, infobg,hicol,locol); RBCreate (hueRB,hsvF, 87, 170, "6", infofg, infobg,hicol,locol); BTCreate(&hueclrB, hsvF, 127, 158, 70, BUTTH, "Reset", infofg, infobg,hicol,locol); initHmap(); hmap2dials(); build_hremap(); InitGraf(&intGraf); CreateGraf(&intGraf, hsvF, 20, 339, infofg, infobg, "Intensity"); /********* RGB color correction doo-wahs ***********/ InitGraf(&rGraf); CreateGraf(&rGraf, rgbF, 10, 20, infofg, infobg, "Red"); InitGraf(&gGraf); CreateGraf(&gGraf, rgbF, 10, 179, infofg, infobg, "Green"); InitGraf(&bGraf); CreateGraf(&bGraf, rgbF, 10, 338, infofg, infobg, "Blue"); satDial.drawobj = dragGamma; intGraf.drawobj = rGraf.drawobj = gGraf.drawobj = bGraf.drawobj = dragGamma; SetHSVmode(); ctrls2gamstate(&defstate); /* set up preset0 as a '2-color' preset */ ctrls2gamstate(&preset[0]); Str2Graf(&preset[0].istate,"L 4 : 0,0 : 127,0 : 128,255 : 255,255"); /* set up preset1 as a '8-color' preset */ ctrls2gamstate(&preset[1]); Str2Graf(&preset[1].rstate,"L 4 : 0,0 : 127,0 : 128,255 : 255,255"); Str2Graf(&preset[1].gstate,"L 4 : 0,0 : 127,0 : 128,255 : 255,255"); Str2Graf(&preset[1].bstate,"L 4 : 0,0 : 127,0 : 128,255 : 255,255"); /* set up preset2 as a 'temperature' pseudo-color preset */ ctrls2gamstate(&preset[2]); Str2Graf(&preset[2].rstate,"S 4 : 0,0 : 105,0 : 155,140 : 255,255"); Str2Graf(&preset[2].gstate,"S 5 : 0,0 : 57,135 : 127,255 : 198,135 : 255,0"); Str2Graf(&preset[2].bstate,"S 4 : 0,255 : 100,140 : 150,0 : 255,0"); /* set up preset3 as a 'map' pseudo-color preset */ ctrls2gamstate(&preset[3]); Str2Graf(&preset[3].rstate,"L 4 : 0,0 : 66,0 : 155,255 : 255,146"); Str2Graf(&preset[3].gstate,"L 5 : 0,0 : 28,0 : 75,255 : 162,210 : 255,46"); Str2Graf(&preset[3].bstate,"L 5 : 0,105 : 19,255 : 66,232 : 108,62:255,21"); parseResources(); CBSetActive(&dragCB, (allocMode == AM_READWRITE)); /* deal with passed in [r,g,b]gam values. If <0.0, ignore them */ if (gam>=0.0) { char str[64]; sprintf(str, "G %f", gam); if (Str2Graf(&defstate.istate, str)) { /* unable to parse */ } } if (rgam>=0.0 && ggam>=0.0 && bgam>=0.0) { char str[64]; sprintf(str, "G %f", rgam); Str2Graf(&defstate.rstate, str); sprintf(str, "G %f", ggam); Str2Graf(&defstate.gstate, str); sprintf(str, "G %f", bgam); Str2Graf(&defstate.bstate, str); } if (defpreset) defLoadState = &preset[defpreset-1]; else defLoadState = &defstate; gamstate2ctrls(defLoadState); /* defstate may have changed */ uptr = utail = uhead = 0; ctrls2gamstate(&undo[0]); #ifdef BACKING_STORE xswa.backing_store = WhenMapped; XChangeWindowAttributes(theDisp, intGraf.win, CWBackingStore, &xswa); XChangeWindowAttributes(theDisp, rGraf.win, CWBackingStore, &xswa); XChangeWindowAttributes(theDisp, gGraf.win, CWBackingStore, &xswa); XChangeWindowAttributes(theDisp, bGraf.win, CWBackingStore, &xswa); XChangeWindowAttributes(theDisp, intGraf.gwin, CWBackingStore, &xswa); XChangeWindowAttributes(theDisp, rGraf.gwin, CWBackingStore, &xswa); XChangeWindowAttributes(theDisp, gGraf.gwin, CWBackingStore, &xswa); XChangeWindowAttributes(theDisp, bGraf.gwin, CWBackingStore, &xswa); #endif XMapSubwindows(theDisp, cmapF); XMapSubwindows(theDisp, hsvF); XMapSubwindows(theDisp, rgbF); XMapSubwindows(theDisp, gamW); computeHSVlinear(); } /***************************************************/ int GamCheckEvent(xev) XEvent *xev; { /* check event to see if it's for one of our subwindows. If it is, deal accordingly, and return '1'. Otherwise, return '0' */ int rv; rv = 1; if (xev->type == Expose) { int x,y,w,h; XExposeEvent *e = (XExposeEvent *) xev; x = e->x; y = e->y; w = e->width; h = e->height; /* throw away excess redraws for 'dumb' windows */ if (e->count > 0 && (e->window == satDial.win || e->window == rhDial.win || e->window == gsDial.win || e->window == bvDial.win || e->window == cmapF || e->window == modF || e->window == intGraf.win || e->window == rGraf.win || e->window == gGraf.win || e->window == bGraf.win || e->window == intGraf.gwin || e->window == rGraf.gwin || e->window == gGraf.gwin || e->window == bGraf.gwin || e->window == rgbF)) {} else if (e->window == gamW) drawGam(x, y, w, h); else if (e->window == butF) drawBut(x, y, w, h); else if (e->window == satDial.win) DRedraw(&satDial); else if (e->window == rhDial.win) DRedraw(&rhDial); else if (e->window == gsDial.win) DRedraw(&gsDial); else if (e->window == bvDial.win) DRedraw(&bvDial); else if (e->window == intGraf.win) RedrawGraf(&intGraf, 0); else if (e->window == rGraf.win) RedrawGraf(&rGraf, 0); else if (e->window == gGraf.win) RedrawGraf(&gGraf, 0); else if (e->window == bGraf.win) RedrawGraf(&bGraf, 0); else if (e->window == intGraf.gwin) RedrawGraf(&intGraf, 1); else if (e->window == rGraf.gwin) RedrawGraf(&rGraf, 1); else if (e->window == gGraf.gwin) RedrawGraf(&gGraf, 1); else if (e->window == bGraf.gwin) RedrawGraf(&bGraf, 1); else if (e->window == cmapF) drawCmap(); else if (e->window == modF) { Draw3dRect(modF, 0,0, MODF_WIDE-1, MODF_HIGH-1, R3D_IN, 2, hicol, locol, infobg); CBRedraw(&enabCB); CBRedraw(&autoCB); CBRedraw(&dragCB); CBRedraw(&resetCB); } else if (e->window == hsvF) { XRectangle xr; xr.x = x; xr.y = y; xr.width = e->width; xr.height = e->height; XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted); Draw3dRect(hsvF, 0,0, HSVF_WIDE-1, HSVF_HIGH-1, R3D_IN, 2, hicol, locol, infobg); XSetForeground(theDisp, theGC, infofg); ULineString(hsvF, "HSV Modification", 3, 2+ASCENT); HDRedraw(&srcHD, HD_ALL); HDRedraw(&dstHD, HD_ALL); HDRedraw(&whtHD, HD_ALL); RBRedraw(hueRB, -1); BTRedraw(&hueclrB); XSetClipMask(theDisp, theGC, None); } else if (e->window == rgbF) { Draw3dRect(rgbF, 0,0, RGBF_WIDE-1, RGBF_HIGH-1, R3D_IN, 2, hicol, locol, infobg); XSetForeground(theDisp, theGC, infofg); ULineString(rgbF, "RGB Modification", 3, 2+ASCENT); } else rv = 0; } else if (xev->type == ButtonPress) { XButtonEvent *e = (XButtonEvent *) xev; int i,x,y; x = e->x; y = e->y; if (e->button == Button1) { if (e->window == butF) clickGam(x,y); else if (e->window == cmapF) clickCmap(x,y,1); else if (e->window == modF) { if (CBClick(&enabCB,x,y)) { if (CBTrack(&enabCB)) applyGamma(0); /* enabCB changed, regen */ } else if (CBClick(&autoCB,x,y)) { if (CBTrack(&autoCB)) { defAutoApply = autoCB.val; if (autoCB.val) applyGamma(0); /* auto-apply turned on, apply */ } } else if (CBClick(&dragCB,x,y)) { if (CBTrack(&dragCB)) { if (dragCB.val) applyGamma(0); /* drag turned on, apply now */ } } else if (CBClick(&resetCB,x,y)) CBTrack(&resetCB); } else if (e->window == hsvF) { if (HDClick(&srcHD, x,y) || HDClick(&dstHD, x,y)) { dials2hmap(); build_hremap(); changedGam(); } else if (HDClick(&whtHD, x,y)) changedGam(); else if (PTINRECT(x,y,hueclrB.x, hueclrB.y, hueclrB.w, hueclrB.h)) { if (BTTrack(&hueclrB)) { /* RESET */ dstHD.stval = srcHD.stval; dstHD.enval = srcHD.enval; dstHD.ccwise = srcHD.ccwise; HDRedraw(&dstHD, HD_ALL | HD_CLEAR); dials2hmap(); build_hremap(); changedGam(); } } else if ((i=RBClick(hueRB,x,y)) >= 0) { dials2hmap(); if (RBTrack(hueRB, i)) hmap2dials(); } } else if (e->window == intGraf.win) { GRAF_STATE gs; if (ClickGraf(&intGraf, e->subwindow, x,y)) { GetGrafState(&intGraf, &gs); changedGam(); } } else if (e->window == rGraf.win) { if (ClickGraf(&rGraf, e->subwindow, x,y)) changedGam(); } else if (e->window == gGraf.win) { if (ClickGraf(&gGraf, e->subwindow, x,y)) changedGam(); } else if (e->window == bGraf.win) { if (ClickGraf(&bGraf, e->subwindow, x,y)) changedGam(); } else if (e->window == satDial.win) { if (DTrack(&satDial, x, y)) changedGam(); } else if (e->window == rhDial.win || e->window == gsDial.win || e->window == bvDial.win) { if ((e->window == rhDial.win && DTrack(&rhDial, x,y)) || (e->window == gsDial.win && DTrack(&gsDial, x,y)) || (e->window == bvDial.win && DTrack(&bvDial, x,y))) { saveCMap(&prevcmap); BTSetActive(&gbut[G_BCOLUNDO],1); ApplyEditColor(0); } } else rv = 0; } else if (e->button == Button2) { if (e->window == cmapF) clickCmap(x, y, 2); else rv = 0; } else if (e->button == Button3) { if (e->window == cmapF) clickCmap(x, y, 3); else rv = 0; } else rv = 0; } else if (xev->type == KeyPress) { XKeyEvent *e = (XKeyEvent *) xev; char buf[128]; KeySym ks; int stlen; stlen = XLookupString(e,buf,128,&ks,(XComposeStatus *) NULL); buf[stlen] = '\0'; if (!stlen) return 0; else if (e->window == intGraf.win) rv = GrafKey(&intGraf,buf); else if (e->window == rGraf.win ) rv = GrafKey(&rGraf,buf); else if (e->window == gGraf.win ) rv = GrafKey(&gGraf,buf); else if (e->window == bGraf.win ) rv = GrafKey(&bGraf,buf); else rv = 0; if (rv>1) changedGam(); /* hit 'enter' in one of Graf's */ } else rv = 0; return rv; } /***************************************************/ static void computeHSVlinear() { /* determine linearity of HSV controls to avoid semi-expensive (and error-inducing) HSV calculations */ int i; hsvnonlinear = 0; for (i=0; i<360 && hremap[i] == i; i++); if (i!=360) hsvnonlinear++; if (whtHD.enabCB.val && whtHD.satval) hsvnonlinear++; if (satDial.val != 0) hsvnonlinear++; /* check intensity graf */ for (i=0; i<256 && intGraf.func[i]==i; i++); if (i<256) hsvnonlinear++; } /***************************************************/ static void changedGam() { /* called whenever an HSV/RGB gamma ctrl has changed applies change to image if autoCB.val is set */ computeHSVlinear(); saveGamState(); if (autoCB.val) applyGamma(0); } /***************************************************/ void GamBox(vis) int vis; { if (vis) XMapRaised(theDisp, gamW); else XUnmapWindow(theDisp, gamW); gamUp = vis; } /***************************************************/ static void drawGam(x,y,w,h) int x,y,w,h; { XRectangle xr; xr.x = x; xr.y = y; xr.width = w; xr.height = h; XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted); drawArrow(232,178); drawArrow(457,178); XSetClipMask(theDisp, theGC, None); } /***************************************************/ static void drawBut(x,y,w,h) int x,y,w,h; { int i; XRectangle xr; xr.x = x; xr.y = y; xr.width = w; xr.height = h; XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted); for (i=0; i= numcols) return; x = CMAPX + (cellno%16)*CMAPCW; y = CMAPY + (cellno/16)*CMAPCH; if (!sel) { /* unhighlight a cell */ XSetForeground(theDisp, theGC, cols[cellno]); XFillRectangle(theDisp, cmapF, theGC, x+1, y+1, CMAPCW-1,CMAPCH-1); } else { /* highlight a cell */ XSetForeground(theDisp, theGC, infobg); XDrawRectangle(theDisp, cmapF, theGC, x+1, y+1, CMAPCW-2,CMAPCH-2); XSetForeground(theDisp, theGC, infofg); XDrawRectangle(theDisp, cmapF, theGC, x+2, y+2, CMAPCW-4,CMAPCH-4); } } /***************************************************/ static void clickGam(x,y) int x,y; { int i; BUTT *bp; for (i=0; iwin == butF && PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) break; } /* if 'Set' is lit, and we didn't click 'set' or 'Reset' or '1'..'4', turn it off */ if (i!=G_BSET && i!=G_B1 && i!=G_B2 && i!=G_B3 && i!=G_B4 && i!=G_BRESET && gbut[G_BSET].lit) { gbut[G_BSET].lit = 0; BTRedraw(&gbut[G_BSET]); } if (iwin == cmapF && PTINRECT(x,y,bp->x, bp->y, bp->w, bp->h)) break; } if (i0, clicked on something in same group remove target from group curgroup>0, clicked on something in different group merge groups. (target group gets set equal to current values) curgroup>0, clicked on something in no group add target to curgroup curgroup=0, clicked on something in a group add editColor to target group, set curgroup = target group target group gets current values curgroup=0, clicked on something in no group create a new group, add both cells to it */ rv = 0; if (first) mode = ADDORDEL; if (curgroup) { if ((mode!=ADDONLY) && cellgroup[cnum] == curgroup) { /* remove target from curgroup. If it's the last one, delete group */ for (i=0,j=0; i1) { /* remove target cell from group */ cellgroup[cnum] = 0; selectCell(cnum,0); mode = DELONLY; if (cnum==editColor) { /* set editColor to first cell in group */ for (i=0; i0) { /* merge clicked-on group into curgroup */ mode = ADDONLY; rv = 1; j = cellgroup[cnum]; for (i=0; i255) j=255; fsgamcr[i] = j; } } /*********************/ static void doCmd(cmd) int cmd; { int i; GRAF_STATE gs; switch (cmd) { case G_BAPPLY: if (enabCB.val != 1) { enabCB.val = 1; CBRedraw(&enabCB); } applyGamma(0); break; case G_BNOGAM: if (enabCB.val != 0) { enabCB.val = 0; CBRedraw(&enabCB); } applyGamma(0); break; case G_BUNDO: gamUndo(); break; case G_BREDO: gamRedo(); break; case G_BCLOSE: GamBox(0); break; case G_BHISTEQ: DoHistEq(); changedGam(); break; case G_BDN_BR: case G_BUP_BR: GetGrafState(&intGraf, &gs); for (i=0; i < gs.nhands; i++) { if (cmd==G_BUP_BR) gs.hands[i].y += 10; else gs.hands[i].y -= 10; RANGE(gs.hands[i].y, 0, 255); } SetGrafState(&intGraf, &gs); changedGam(); break; case G_BUP_CN: GetGrafState(&intGraf, &gs); for (i=0; i < gs.nhands; i++) { if (gs.hands[i].x < 128) gs.hands[i].y -= 10; else gs.hands[i].y += 10; RANGE(gs.hands[i].y, 0, 255); } SetGrafState(&intGraf, &gs); changedGam(); break; case G_BDN_CN: GetGrafState(&intGraf, &gs); for (i=0; i < gs.nhands; i++) { if (gs.hands[i].y < 128) { gs.hands[i].y += 10; if (gs.hands[i].y > 128) gs.hands[i].y = 128; } else { gs.hands[i].y -= 10; if (gs.hands[i].y < 128) gs.hands[i].y = 128; } } SetGrafState(&intGraf, &gs); changedGam(); break; case G_BMAXCONT: DoNorm(); changedGam(); break; case G_BRESET: case G_B1: case G_B2: case G_B3: case G_B4: { struct gamstate *ptr = &defstate; if (cmd==G_B1) ptr = &preset[0]; else if (cmd==G_B2) ptr = &preset[1]; else if (cmd==G_B3) ptr = &preset[2]; else if (cmd==G_B4) ptr = &preset[3]; else if (cmd==G_BRESET) ptr = &defstate; if (gbut[G_BSET].lit) { ctrls2gamstate(ptr); gbut[G_BSET].lit = 0; BTRedraw(&gbut[G_BSET]); } else gamstate2ctrls(ptr); } break; case G_BSET: break; case G_BHSVRGB: hsvmode = !hsvmode; SetHSVmode(); saveGamState(); break; case G_BCOLREV: { struct cmapstate tmp1cmap; int gchg; for (i=0; i0; i--, ep++) hist[rgb[*ep]]++; /* compute minv/maxv values */ for (i=0; i<256 && !hist[i]; i++); *rminv = i; for (i=255; i>0 && !hist[i]; i--); *rmaxv = i; } else { /* PIC24 */ int v,minv,maxv; for (i=0; i<256; i++) hist[i] = 0; minv = 255; maxv = 0; for (i=0,ep=epic; imaxv) maxv = v; hist[v]++; } *rminv = minv; *rmaxv = maxv; } if (DEBUG) { fprintf(stderr,"intensity histogram: "); for (i=0; i<256; i++) fprintf(stderr,"%d ", hist[i]); fprintf(stderr,"\n\n"); } /* compute histeq curve */ total = topbin = 0; for (i=0; i<256; i++) { histeq[i] = (total * 255) / ((unsigned long) eWIDE * eHIGH); if (hist[i]) topbin = i; total += hist[i]; } /* stretch range, as histeq[255] is probably *not* equal to 255 */ maxv = (histeq[topbin]) ? histeq[topbin] : 255; /* avoid div by 0 */ for (i=0; i<256; i++) histeq[i] = (histeq[i] * 255) / maxv; if (DEBUG) { fprintf(stderr,"intensity eq curve: "); for (i=0; i<256; i++) fprintf(stderr,"%d ", histeq[i]); fprintf(stderr,"\n\n"); } /* play it safe: do a range check on histeq */ for (i=0; i<256; i++) RANGE(histeq[i],0,255); } /*********************/ void DoHistEq() { int i, histeq[256], minv, maxv; calcHistEQ(histeq, &minv, &maxv); /* ignore minv,maxv */ for (i=0; i<256; i++) intGraf.func[i] = histeq[i]; for (i=0; i< intGraf.nhands; i++) intGraf.hands[i].y = intGraf.func[intGraf.hands[i].x]; intGraf.entergamma = 0; if (gamUp) { XClearWindow(theDisp, intGraf.gwin); RedrawGraf(&intGraf, 1); } } /*********************/ void DoNorm() { int i, minv, maxv, v; GRAF_STATE gs; minv = 255; maxv = 0; if (picType == PIC8) { for (i=0; imaxv) maxv = v; } } else { int histeq[256]; calcHistEQ(histeq, &minv, &maxv); /* ignore histeq */ } GetGrafState(&intGraf, &gs); gs.spline = 0; gs.entergamma = 0; gs.gammamode = 0; gs.nhands = 4; gs.hands[0].x = 0; gs.hands[0].y = 0; gs.hands[1].x = minv; gs.hands[1].y = 0; gs.hands[2].x = maxv; gs.hands[2].y = 255; gs.hands[3].x = 255; gs.hands[3].y = 255; if (minv<1) { gs.hands[1].x = gs.hands[1].y = 1; } if (maxv>254) { gs.hands[2].x = gs.hands[2].y = 254; } SetGrafState(&intGraf, &gs); } /*********************/ void GammifyColors() { int i; if (picType != PIC8) return; if (enabCB.val) { for (i=0; i1) fprintf(stderr,"Gammify: %d,%d,%d",rv,gv,bv); if (!hsvnonlinear) { if (DEBUG>1) fprintf(stderr," HSV stage skipped (is linear)"); } else { rgb2hsv(rv, gv, bv, &h, &s, &v); if (DEBUG>1) fprintf(stderr," -> %f,%f,%f",h,s,v); /* map near-black to black to avoid weird effects */ if (v <= .0625) s = 0.0; /* apply intGraf.func[] function to 'v' (the intensity) */ vi = (int) floor((v * 255.0) + 0.5); if (DEBUG>1) fprintf(stderr," (vi=%d)",vi); v = intGraf.func[vi] / 255.0; if (DEBUG>1) fprintf(stderr," (v=%f)",v); if (h>=0) { hi = (int) h; if (hi<0) hi += 360; if (hi>=360) hi -= 360; h = (double) hremap[hi]; } else { if (whtHD.enabCB.val) { h = (double) whtHD.stval; s = (double) whtHD.satval / 100.0; /* special case: if stval = satval = 0, set hue = -1 */ if (whtHD.stval == 0 && whtHD.satval == 0) h = -1.0; } } /* apply satDial value to s */ s = s + ((double) satDial.val) / 100.0; if (s<0.0) s = 0.0; if (s>1.0) s = 1.0; hsv2rgb(h,s,v,&rv, &gv, &bv); if (DEBUG>1) fprintf(stderr," -> %d,%d,%d",rv,gv,bv); } rMap[col] = rGraf.func[rv]; gMap[col] = gGraf.func[gv]; bMap[col] = bGraf.func[bv]; if (DEBUG>1) fprintf(stderr," -> %d,%d,%d\n",rMap[col],gMap[col],bMap[col]); } /*********************/ void rgb2hsv(r,g,b, hr, sr, vr) int r, g, b; double *hr, *sr, *vr; { double rd, gd, bd, h, s, v, max, min, del, rc, gc, bc; /* convert RGB to HSV */ rd = r / 255.0; /* rd,gd,bd range 0-1 instead of 0-255 */ gd = g / 255.0; bd = b / 255.0; /* compute maximum of rd,gd,bd */ if (rd>=gd) { if (rd>=bd) max = rd; else max = bd; } else { if (gd>=bd) max = gd; else max = bd; } /* compute minimum of rd,gd,bd */ if (rd<=gd) { if (rd<=bd) min = rd; else min = bd; } else { if (gd<=bd) min = gd; else min = bd; } del = max - min; v = max; if (max != 0.0) s = (del) / max; else s = 0.0; h = NOHUE; if (s != 0.0) { rc = (max - rd) / del; gc = (max - gd) / del; bc = (max - bd) / del; if (rd==max) h = bc - gc; else if (gd==max) h = 2 + rc - bc; else if (bd==max) h = 4 + gc - rc; h = h * 60; if (h<0) h += 360; } *hr = h; *sr = s; *vr = v; } /*********************/ void hsv2rgb(h, s, v, rr, gr, br) double h, s, v; int *rr, *gr, *br; { int j; double rd, gd, bd; double f, p, q, t; /* convert HSV back to RGB */ if (h==NOHUE || s==0.0) { rd = v; gd = v; bd = v; } else { if (h==360.0) h = 0.0; h = h / 60.0; j = (int) floor(h); if (j<0) j=0; /* either h or floor seem to go neg on some sys */ f = h - j; p = v * (1-s); q = v * (1 - (s*f)); t = v * (1 - (s*(1 - f))); switch (j) { case 0: rd = v; gd = t; bd = p; break; case 1: rd = q; gd = v; bd = p; break; case 2: rd = p; gd = v; bd = t; break; case 3: rd = p; gd = q; bd = v; break; case 4: rd = t; gd = p; bd = v; break; case 5: rd = v; gd = p; bd = q; break; default: rd = v; gd = t; bd = p; break; /* never happen */ } } *rr = (int) floor((rd * 255.0) + 0.5); *gr = (int) floor((gd * 255.0) + 0.5); *br = (int) floor((bd * 255.0) + 0.5); } /*********************/ static void ctrls2gamstate(gs) struct gamstate *gs; { xvbcopy((char *) hmap, (char *) gs->hmap, sizeof(hmap)); gs->wht_stval = whtHD.stval; gs->wht_satval = whtHD.satval; gs->wht_enab = whtHD.enabCB.val; gs->hueRBnum = RBWhich(hueRB); gs->satval = satDial.val; GetGrafState(&intGraf,&gs->istate); GetGrafState(&rGraf, &gs->rstate); GetGrafState(&gGraf, &gs->gstate); GetGrafState(&bGraf, &gs->bstate); } /*********************/ static void gamstate2ctrls(gs) struct gamstate *gs; { int changed = 0; struct hmap *hm; if (gs->hueRBnum != RBWhich(hueRB)) { RBSelect(hueRB, gs->hueRBnum); changed++; } if (xvbcmp((char *) hmap, (char *) gs->hmap, sizeof(hmap))) { /*hmap chngd*/ xvbcopy((char *) gs->hmap, (char *) hmap, sizeof(hmap)); build_hremap(); changed++; hm = &(gs->hmap[gs->hueRBnum]); if (srcHD.stval != hm->src_st || srcHD.enval != hm->src_en || srcHD.ccwise != hm->src_ccw) { srcHD.stval = hm->src_st; srcHD.enval = hm->src_en; srcHD.ccwise = hm->src_ccw; HDRedraw(&srcHD, HD_ALL | HD_CLEAR); } if (dstHD.stval != hm->dst_st || dstHD.enval != hm->dst_en || dstHD.ccwise != hm->dst_ccw) { dstHD.stval = hm->dst_st; dstHD.enval = hm->dst_en; dstHD.ccwise = hm->dst_ccw; HDRedraw(&dstHD, HD_ALL | HD_CLEAR); } } if (whtHD.stval != gs->wht_stval || whtHD.satval != gs->wht_satval || whtHD.enabCB.val != gs->wht_enab) { whtHD.stval = gs->wht_stval; whtHD.satval = gs->wht_satval; whtHD.enabCB.val = gs->wht_enab; CBRedraw(&whtHD.enabCB); HDRedraw(&whtHD, HD_ALL | HD_CLEAR); changed++; } if (gs->satval != satDial.val) { DSetVal(&satDial,gs->satval); changed++; } if (SetGrafState(&intGraf, &gs->istate)) changed++; if (SetGrafState(&rGraf, &gs->rstate)) changed++; if (SetGrafState(&gGraf, &gs->gstate)) changed++; if (SetGrafState(&bGraf, &gs->bstate)) changed++; if (changed) changedGam(); } static int nosave_kludge = 0; /*********************/ static void saveGamState() { /* increment uptr, sticks current state into uptr set utail = uptr If utail==uhead, increment uhead (buffer full, throw away earliest) */ if (nosave_kludge) return; uptr = (uptr+1) % MAXUNDO; ctrls2gamstate(&undo[uptr]); utail = uptr; if (utail == uhead) uhead = (uhead + 1) % MAXUNDO; BTSetActive(&gbut[G_BUNDO],1); BTSetActive(&gbut[G_BREDO],0); } /*********************/ static void gamUndo() { /* if uptr!=uhead decements uptr, restores state pointed to by uptr if uptr now == uhead, turn off 'Undo' button */ if (uptr != uhead) { /* this should always be true when gamUndo called */ uptr = (uptr + MAXUNDO - 1) % MAXUNDO; nosave_kludge = 1; gamstate2ctrls(&undo[uptr]); nosave_kludge = 0; if (uptr == uhead) BTSetActive(&gbut[G_BUNDO],0); if (uptr != utail) BTSetActive(&gbut[G_BREDO],1); } } /*********************/ static void gamRedo() { /* if uptr != utail increments uptr, restores state pointed to by uptr if uptr now == utail, turn off 'Redo' button */ if (uptr != utail) { /* this should always be true when gamRedo called */ uptr = (uptr + 1) % MAXUNDO; nosave_kludge = 1; gamstate2ctrls(&undo[uptr]); nosave_kludge = 0; if (uptr != uhead) BTSetActive(&gbut[G_BUNDO],1); if (uptr == utail) BTSetActive(&gbut[G_BREDO],0); } } /*********************/ static void rndCols() { int i,j; for (i=0; irm[i] = rcmap[i]; cst->gm[i] = gcmap[i]; cst->bm[i] = bcmap[i]; cst->cellgroup[i] = cellgroup[i]; } cst->curgroup = curgroup; cst->maxgroup = maxgroup; cst->editColor = editColor; } /*********************/ static void restoreCMap(cst) struct cmapstate *cst; { int i; for (i=0; i<256; i++) { rcmap[i] = cst->rm[i]; gcmap[i] = cst->gm[i]; bcmap[i] = cst->bm[i]; cellgroup[i] = cst->cellgroup[i]; } curgroup = cst->curgroup; maxgroup = cst->maxgroup; editColor = cst->editColor; } /*********************/ static void parseResources() { char gname[80], tmp[80], tmp1[256]; int i,j; struct gamstate *gsp, gs; /* look for the simple coledit-related resources */ if (rd_flag("autoApply")) autoCB.val = def_int; if (rd_flag("dragApply")) dragCB.val = def_int; if (rd_flag("displayMods")) enabCB.val = def_int; if (rd_flag("autoReset")) resetCB.val = def_int; defAutoApply = autoCB.val; /* look for preset/default resources */ for (i=0; i<5; i++) { if (i) { sprintf(gname,"preset%d",i); gsp = &preset[i-1]; } else { sprintf(gname,"default"); gsp = &defstate; } xvbcopy((char *) gsp, (char *) &gs, sizeof(struct gamstate)); /* load 'gs' with defaults */ for (j=0; j<6; j++) { /* xv.*.huemap resources */ sprintf(tmp, "%s.huemap%d", gname, j+1); if (rd_str_cl(tmp, "Setting.Huemap")) { /* got one */ int fst, fen, tst, ten; char fcw[32], tcw[32]; if (DEBUG) fprintf(stderr,"parseResource 'xv.%s: %s'\n",tmp, def_str); lower_str(def_str); if (sscanf(def_str,"%d %d %s %d %d %s", &fst, &fen, fcw, &tst, &ten, tcw) != 6) { fprintf(stderr,"%s: unable to parse resource 'xv.%s: %s'\n", cmd, tmp, def_str); } else { RANGE(fst, 0, 359); RANGE(fen, 0, 359); RANGE(tst, 0, 359); RANGE(ten, 0, 359); gs.hmap[j].src_st = fst; gs.hmap[j].src_en = fen; gs.hmap[j].src_ccw = (strcmp(fcw,"ccw") == 0); gs.hmap[j].dst_st = tst; gs.hmap[j].dst_en = ten; gs.hmap[j].dst_ccw = (strcmp(tcw,"ccw") == 0); } } } sprintf(tmp, "%s.whtmap", gname); /* xv.*.whtmap resource */ if (rd_str_cl(tmp, "Setting.Whtmap")) { /* got one */ int wst, wsat, enab; if (DEBUG) fprintf(stderr,"parseResource 'xv.%s: %s'\n",tmp, def_str); if (sscanf(def_str,"%d %d %d", &wst, &wsat, &enab) != 3) { fprintf(stderr,"%s: unable to parse resource 'xv.%s: %s'\n", cmd, tmp, def_str); } else { /* successful parse */ RANGE(wst, 0, 359); RANGE(wsat, 0, 100); gs.wht_stval = wst; gs.wht_satval = wsat; gs.wht_enab = enab; } } sprintf(tmp, "%s.satval", gname); /* xv.*.satval resource */ if (rd_str_cl(tmp, "Setting.Satval")) { /* got one */ int sat; if (DEBUG) fprintf(stderr,"parseResource 'xv.%s: %s'\n",tmp, def_str); if (sscanf(def_str,"%d", &sat) != 1) { fprintf(stderr,"%s: unable to parse resource 'xv.%s: %s'\n", cmd, tmp, def_str); } else { /* successful parse */ RANGE(sat, -100, 100); gs.satval = sat; } } for (j=0; j<4; j++) { /* xv.*.*graf resources */ GRAF_STATE gstat, *gsgst; switch (j) { case 0: sprintf(tmp, "%s.igraf", gname); gsgst = &gs.istate; break; case 1: sprintf(tmp, "%s.rgraf", gname); gsgst = &gs.rstate; break; case 2: sprintf(tmp, "%s.ggraf", gname); gsgst = &gs.gstate; break; case 3: sprintf(tmp, "%s.bgraf", gname); gsgst = &gs.bstate; break; default: sprintf(tmp, "%s.bgraf", gname); gsgst = &gs.bstate; break; } if (rd_str_cl(tmp, "Setting.Graf")) { /* got one */ strcpy(tmp1, def_str); xvbcopy((char *) gsgst, (char *) &gstat, sizeof(GRAF_STATE)); if (DEBUG) fprintf(stderr,"parseResource 'xv.%s: %s'\n",tmp, tmp1); if (!Str2Graf(&gstat, tmp1)) { /* successful parse */ xvbcopy((char *) &gstat, (char *) gsgst, sizeof(GRAF_STATE)); } } } /* copy (potentially) modified gs back to default/preset */ xvbcopy((char *) &gs, (char *) gsp, sizeof(struct gamstate)); } } /*********************/ static void makeResources() { char rsrc[2000]; /* wild over-estimation */ char gname[40], rname[64], tmp[256], tmp1[256]; struct gamstate gstate; int i; rsrc[0] = '\0'; /* write out current state */ ctrls2gamstate(&gstate); strcpy(gname, "xv.default"); /* write out huemap resources */ for (i=0; i<6; i++) { if (1 || gstate.hmap[i].src_st != gstate.hmap[i].dst_st || gstate.hmap[i].src_en != gstate.hmap[i].dst_en || gstate.hmap[i].src_ccw != gstate.hmap[i].dst_ccw) { sprintf(tmp, "%s.huemap%d: %3d %3d %3s %3d %3d %3s\n", gname, i+1, gstate.hmap[i].src_st, gstate.hmap[i].src_en, gstate.hmap[i].src_ccw ? "CCW" : "CW", gstate.hmap[i].dst_st, gstate.hmap[i].dst_en, gstate.hmap[i].dst_ccw ? "CCW" : "CW"); strcat(rsrc, tmp); } } /* write out whtmap resource */ if (1 || gstate.wht_stval || gstate.wht_satval || gstate.wht_enab != 1) { sprintf(tmp, "%s.whtmap: %d %d %d\n", gname, gstate.wht_stval, gstate.wht_satval, gstate.wht_enab); strcat(rsrc, tmp); } /* write out satval resource */ if (1 || gstate.satval) { sprintf(tmp, "%s.satval: %d\n", gname, gstate.satval); strcat(rsrc, tmp); } /* write out graf resources */ for (i=0; i<4; i++) { GRAF_STATE *gfstat; switch (i) { case 0: sprintf(rname, "%s.igraf", gname); gfstat = &gstate.istate; break; case 1: sprintf(rname, "%s.rgraf", gname); gfstat = &gstate.rstate; break; case 2: sprintf(rname, "%s.ggraf", gname); gfstat = &gstate.gstate; break; case 3: sprintf(rname, "%s.bgraf", gname); gfstat = &gstate.bstate; break; default: sprintf(rname, "%s.bgraf", gname); gfstat = &gstate.bstate; break; } Graf2Str(gfstat, tmp1); sprintf(tmp, "%s: %s\n", rname, tmp1); strcat(rsrc, tmp); } XStoreBytes(theDisp, rsrc, strlen(rsrc)); } /*****************************/ static void dragGamma () { /* called through DIAL.drawobj and GRAF.drawobj while gamma ctrls are being dragged applies change to image if dragCB.val is set does NOT call saveGamState() (as changedGam does) */ if (dragCB.val && dragCB.active) { hsvnonlinear = 1; /* force HSV calculations during drag */ applyGamma(0); } } /*****************************/ static void dragHueDial() { /* called through HDIAL.drawobj while hue gamma ctrls are being dragged applies change to image if dragCB.val is set does NOT call saveGamState() (as changedGam does) */ if (dragCB.val && dragCB.active) { dials2hmap(); build_hremap(); hsvnonlinear = 1; /* force HSV calculations during drag */ applyGamma(0); } } /*****************************/ static void dragEditColor () { /* called through DIAL.drawobj while color editor ctrls are being dragged applies change to image if dragCB.val is set does NOT call saveCMap(&prevcmap); BTSetActive(&gbut[G_BCOLUNDO],1); */ if (dragCB.val && dragCB.active) ApplyEditColor(0); } /**********************************************/ /************* HUE wheel functions ***********/ /**********************************************/ static int hdb_pixmaps_built = 0; static Pixmap hdbpix1[N_HDBUTT]; static Pixmap hdbpix2[N_HDBUTT2]; #define PW 15 #define PH 15 /**************************************************/ static void HDCreate(hd, win, x, y, r, st, en, ccwise, str, fg, bg) HDIAL *hd; Window win; int x,y,r,st,en,ccwise; char *str; u_long fg,bg; { int i; hd->win = win; hd->x = x; hd->y = y; hd->range = r; hd->stval = st; hd->enval = en; hd->satval = 0; hd->ccwise = ccwise; hd->str = str; hd->fg = fg; hd->bg = bg; hd->drawobj = NULL; if (!hdb_pixmaps_built) { hdbpix1[HDB_ROTL] = XCreatePixmapFromBitmapData(theDisp, win, h_rotl_bits, PW,PH, 1, 0, 1); hdbpix1[HDB_ROTR] = XCreatePixmapFromBitmapData(theDisp, win, h_rotr_bits, PW,PH, 1, 0, 1); hdbpix1[HDB_FLIP] = XCreatePixmapFromBitmapData(theDisp, win, h_flip_bits, PW,PH, 1, 0, 1); hdbpix1[HDB_EXPND] = XCreatePixmapFromBitmapData(theDisp, win, h_sinc_bits, PW,PH, 1, 0, 1); hdbpix1[HDB_SHRNK] = XCreatePixmapFromBitmapData(theDisp, win, h_sdec_bits, PW,PH, 1, 0, 1); hdbpix2[HDB_SAT] = XCreatePixmapFromBitmapData(theDisp, win, h_sat_bits, PW,PH, 1, 0, 1); hdbpix2[HDB_DESAT] = XCreatePixmapFromBitmapData(theDisp, win, h_desat_bits, PW,PH, 1, 0, 1); hdbpix2[HDB_ROTL] = hdbpix1[HDB_ROTL]; hdbpix2[HDB_ROTR] = hdbpix1[HDB_ROTR]; } if (hd->range) { BTCreate(&hd->hdbutt[HDB_ROTL], win, x-50,y+60,18,18,NULL,fg,bg, hicol,locol); BTCreate(&hd->hdbutt[HDB_ROTR], win, x-30,y+60,18,18,NULL,fg,bg, hicol,locol); BTCreate(&hd->hdbutt[HDB_FLIP], win, x-10,y+60,18,18,NULL,fg,bg, hicol, locol); BTCreate(&hd->hdbutt[HDB_EXPND],win, x+10,y+60,18,18,NULL,fg,bg, hicol, locol); BTCreate(&hd->hdbutt[HDB_SHRNK],win, x+30,y+60,18,18,NULL,fg,bg, hicol, locol); for (i=0; ihdbutt[i].pix = hdbpix1[i]; hd->hdbutt[i].pw = PW; hd->hdbutt[i].ph = PH; } } else { BTCreate(&hd->hdbutt[HDB_ROTL], win, x-39,y+60,18,18,NULL,fg,bg, hicol, locol); BTCreate(&hd->hdbutt[HDB_ROTR], win, x-19,y+60,18,18,NULL,fg,bg, hicol, locol); BTCreate(&hd->hdbutt[HDB_DESAT],win, x+1, y+60,18,18,NULL,fg,bg, hicol, locol); BTCreate(&hd->hdbutt[HDB_SAT], win, x+21,y+60,18,18,NULL,fg,bg, hicol,locol); CBCreate(&hd->enabCB, win, x+23, y-44, "", fg, bg, hicol,locol); hd->enabCB.val = 1; for (i=0; ihdbutt[i].pix = hdbpix2[i]; hd->hdbutt[i].pw = PW; hd->hdbutt[i].ph = PH; } } } /**************************************************/ static void HDRedraw(hd, flags) HDIAL *hd; int flags; { int i, x, y, x1, y1; double a; if (flags & HD_CLEAR) { XSetForeground(theDisp, theGC, hd->bg); XFillArc(theDisp, hd->win, theGC, hd->x-(HD_RADIUS-1),hd->y-(HD_RADIUS-1), (HD_RADIUS-1)*2, (HD_RADIUS-1)*2, 0, 360*64); } if (flags & HD_FRAME) { static char *colstr = "RYGCBM"; char tstr[2]; XSetForeground(theDisp, theGC, hd->fg); XDrawArc(theDisp, hd->win, theGC, hd->x - HD_RADIUS, hd->y - HD_RADIUS, HD_RADIUS*2, HD_RADIUS*2, 0, 360*64); for (i=0; i<6; i++) { int kldg; if (i==2 || i==5) kldg = -1; else kldg = 0; a = hdg2xdg(i*60) * DEG2RAD; pol2xy(hd->x, hd->y, a, HD_RADIUS+1, &x, &y); pol2xy(hd->x, hd->y, a, HD_RADIUS+4+kldg, &x1, &y1); XDrawLine(theDisp, hd->win, theGC, x,y,x1,y1); tstr[0] = colstr[i]; tstr[1] = '\0'; pol2xy(hd->x, hd->y, a, HD_RADIUS+10, &x, &y); CenterString(hd->win, tstr, x,y); } } if (flags & HD_HANDS || flags & HD_CLHNDS) { if (flags & HD_CLHNDS) XSetForeground(theDisp, theGC, hd->bg); else XSetForeground(theDisp, theGC, hd->fg); if (hd->range ) { if (flags & HD_HANDS) /* draw center dot */ XFillRectangle(theDisp, hd->win, theGC, hd->x-1, hd->y-1, 3,3); a = hdg2xdg(hd->stval) * DEG2RAD; pol2xy(hd->x, hd->y, a, HD_RADIUS - 4, &x, &y); XDrawLine(theDisp, hd->win, theGC, hd->x, hd->y, x,y); if (flags & HD_CLHNDS) XFillRectangle(theDisp, hd->win, theGC, x-2,y-2, 5,5); else { XSetForeground(theDisp, theGC, hd->bg); XFillRectangle(theDisp, hd->win, theGC, x-1, y-1, 3,3); XSetForeground(theDisp, theGC, hd->fg); XDrawPoint(theDisp, hd->win, theGC, x, y); XDrawRectangle(theDisp, hd->win, theGC, x-2, y-2, 4,4); } a = hdg2xdg(hd->enval) * DEG2RAD; pol2xy(hd->x, hd->y, a, HD_RADIUS - 4, &x, &y); XDrawLine(theDisp, hd->win, theGC, hd->x, hd->y, x,y); if (flags & HD_CLHNDS) XFillRectangle(theDisp, hd->win, theGC, x-2,y-2, 5,5); else { XSetForeground(theDisp, theGC, hd->bg); XFillRectangle(theDisp, hd->win, theGC, x-1, y-1, 3,3); XSetForeground(theDisp, theGC, hd->fg); XDrawPoint(theDisp, hd->win, theGC, x, y); XDrawRectangle(theDisp, hd->win, theGC, x-2, y-2, 4,4); } } else { /* not a range; hue/sat dial */ int r; /* compute x,y position from stval/satval */ a = hdg2xdg(hd->stval) * DEG2RAD; r = ((HD_RADIUS - 4) * hd->satval) / 100; pol2xy(hd->x, hd->y, a, r, &x, &y); if (flags & HD_CLHNDS) XFillRectangle(theDisp, hd->win, theGC, x-2,y-2, 5,5); else { XFillRectangle(theDisp, hd->win, theGC, hd->x-1, hd->y-1, 3,3); XSetForeground(theDisp, theGC, hd->bg); XFillRectangle(theDisp, hd->win, theGC, x-1, y-1, 3,3); XSetForeground(theDisp, theGC, hd->fg); XDrawPoint(theDisp, hd->win, theGC, x, y); XDrawRectangle(theDisp, hd->win, theGC, x-2, y-2, 4,4); } } } if ((flags & HD_DIR || flags & HD_CLHNDS) && hd->range) { int xdg1, xdg2, xdlen; if (flags & HD_CLHNDS) XSetForeground(theDisp, theGC, hd->bg); else XSetForeground(theDisp, theGC, hd->fg); if (hd->ccwise) { xdg1 = hdg2xdg(hd->stval); xdg2 = hdg2xdg(hd->enval); } else { xdg1 = hdg2xdg(hd->enval); xdg2 = hdg2xdg(hd->stval); } xdlen = xdg2 - xdg1; if (xdlen<0) xdlen += 360; /* note: 0 len means no range */ if (xdlen>1) { XDrawArc(theDisp, hd->win, theGC, hd->x - ((HD_RADIUS*3)/5), hd->y - ((HD_RADIUS*3)/5), (HD_RADIUS*6)/5, (HD_RADIUS*6)/5, xdg1 * 64, xdlen * 64); } if (xdlen > 16) { xdg1 = hdg2xdg(hd->enval); if (hd->ccwise) xdg2 = xdg1-10; else xdg2 = xdg1+10; pol2xy(hd->x, hd->y, xdg2 * DEG2RAD, ((HD_RADIUS*3)/5) + 3, &x, &y); pol2xy(hd->x, hd->y, xdg1 * DEG2RAD, ((HD_RADIUS*3)/5), &x1,&y1); XDrawLine(theDisp, hd->win, theGC, x, y, x1, y1); if (hd->ccwise) xdg2 = xdg1-16; else xdg2 = xdg1+16; pol2xy(hd->x, hd->y, xdg2 * DEG2RAD, ((HD_RADIUS*3)/5) - 2, &x, &y); XDrawLine(theDisp, hd->win, theGC, x, y, x1, y1); } } if (flags & HD_VALS) { char vstr[32]; XSetFont(theDisp, theGC, monofont); XSetForeground(theDisp, theGC, hd->fg); XSetBackground(theDisp, theGC, hd->bg); if (hd->range) { sprintf(vstr,"%3d\007,%3d\007 %s", hd->stval, hd->enval, hd->ccwise ? "CCW" : " CW"); } else { sprintf(vstr,"%3d\007 %3d%%", hd->stval, hd->satval); } XDrawImageString(theDisp, hd->win, theGC, hd->x - XTextWidth(monofinfo, vstr, strlen(vstr))/2, hd->y + HD_RADIUS + 24, vstr, strlen(vstr)); XSetFont(theDisp, theGC, mfont); } if (flags & HD_TITLE) { XSetForeground(theDisp, theGC, hd->fg); ULineString(hd->win, hd->str, hd->x - HD_RADIUS - 15, hd->y - HD_RADIUS - 4); } if (flags & HD_BUTTS) { if (hd->range) { for (i=0; ihdbutt[i]); } else { for (i=0; ihdbutt[i]); CBRedraw(&hd->enabCB); } } if (!hd->range && !hd->enabCB.val) { /* draw dimmed */ XSync(theDisp, False); DimRect(hd->win, hd->x-HD_RADIUS-15, hd->y-HD_RADIUS-4-ASCENT, 2*HD_RADIUS+30,(2*HD_RADIUS+4+ASCENT+80), hd->bg); XSync(theDisp, False); CBRedraw(&hd->enabCB); } } /**************************************************/ static int HDClick(hd,mx,my) HDIAL *hd; int mx, my; { /* called when a click received. checks whether HDTrack needs to be called. Returns '1' if click is in HD dial area, 0 otherwise */ int bnum,maxb; BUTT *bp = (BUTT *) NULL; if (CBClick(&hd->enabCB, mx, my)) { if (CBTrack(&hd->enabCB)) { HDRedraw(hd, HD_ALL); return 1; } } if (!hd->range && !hd->enabCB.val) return 0; /* disabled */ if ( ((mx - hd->x) * (mx - hd->x) + (my - hd->y) * (my - hd->y)) < (HD_RADIUS * HD_RADIUS)) { return HDTrack(hd,mx,my); } if (hd->range) maxb = N_HDBUTT; else maxb = N_HDBUTT2; for (bnum=0; bnumhdbutt[bnum]; if (PTINRECT(mx,my, bp->x, bp->y, bp->w, bp->h)) break; } if (bnum==maxb) return 0; if (bnum==HDB_FLIP && hd->range) { if (BTTrack(bp)) { int t; HDRedraw(hd, HD_CLHNDS); t = hd->stval; hd->stval = hd->enval; hd->enval = t; hd->ccwise = !hd->ccwise; HDRedraw(hd, HD_HANDS | HD_DIR | HD_VALS); if (hd->drawobj) (hd->drawobj)(); return 1; } return 0; } else { /* track buttons til mouse up */ Window rW, cW; int rx,ry,x,y; unsigned int mask; bp->lit = 1; BTRedraw(bp); /* light it up */ /* loop until mouse is released */ while (XQueryPointer(theDisp,hd->win,&rW,&cW,&rx,&ry,&x,&y,&mask)) { if (!(mask & Button1Mask)) break; /* button released */ /* check to see if state needs toggling */ if (( bp->lit && !PTINRECT(x,y,bp->x,bp->y,bp->w,bp->h)) || (!bp->lit && PTINRECT(x,y,bp->x,bp->y,bp->w,bp->h))) { bp->lit = !bp->lit; BTRedraw(bp); } if (bp->lit) { switch (bnum) { case HDB_ROTL: HDRedraw(hd, HD_CLHNDS); hd->stval--; if (hd->stval<0) hd->stval += 360; hd->enval--; if (hd->enval<0) hd->enval += 360; HDRedraw(hd, HD_HANDS | HD_DIR | HD_VALS); break; case HDB_ROTR: HDRedraw(hd, HD_CLHNDS); hd->stval++; if (hd->stval>=360) hd->stval -= 360; hd->enval++; if (hd->enval>=360) hd->enval -= 360; HDRedraw(hd, HD_HANDS | HD_DIR | HD_VALS); break; /* case HDB_DESAT: */ /* case HDB_SAT: */ case HDB_EXPND: case HDB_SHRNK: if (hd->range) { if ((bnum == HDB_EXPND) && (( hd->ccwise && hd->enval == (hd->stval+1)) || (!hd->ccwise && hd->enval == (hd->stval-1)))) { /* max size: can't grow */ } else if (bnum == HDB_SHRNK && hd->stval == hd->enval) { /* min size, can't shrink */ } else { /* can shrink or grow */ HDRedraw(hd, HD_CLHNDS); if ((bnum==HDB_EXPND && hd->ccwise) || (bnum==HDB_SHRNK && !hd->ccwise)) { if ((hd->stval & 1) == (hd->enval & 1)) hd->stval = (hd->stval + 1 + 360) % 360; else hd->enval = (hd->enval - 1 + 360) % 360; } else { if ((hd->stval & 1) == (hd->enval & 1)) hd->stval = (hd->stval - 1 + 360) % 360; else hd->enval = (hd->enval + 1 + 360) % 360; } HDRedraw(hd, HD_HANDS | HD_DIR | HD_VALS); } } else { /* hue/sat dial: SAT/DESAT */ if (bnum == HDB_DESAT && hd->satval>0) { HDRedraw(hd, HD_CLHNDS); hd->satval--; if (hd->satval<0) hd->satval = 0; HDRedraw(hd, HD_HANDS | HD_VALS); } else if (bnum == HDB_SAT && hd->satval<100) { HDRedraw(hd, HD_CLHNDS); hd->satval++; if (hd->satval>100) hd->satval = 100; HDRedraw(hd, HD_HANDS | HD_VALS); } } break; } if (hd->drawobj) (hd->drawobj)(); Timer(150); } } XFlush(theDisp); } if (bp->lit) { bp->lit = 0; BTRedraw(bp); } return 1; } /**************************************************/ static int HDTrack(hd,mx,my) HDIAL *hd; int mx,my; { /* called when clicked in dial area. tracks dragging handles around... returns '1' if anything changed */ Window rW,cW; int rx,ry, x,y, ival,j, rv; unsigned int mask; rv = 0; if (!hd->range) { /* hue/sat dial */ int ihue, isat, newhue, newsat; double dx,dy,dist; ihue = hd->stval; isat = hd->satval; /* loop until mouse is released */ while (XQueryPointer(theDisp,hd->win,&rW,&cW,&rx,&ry,&x,&y,&mask)) { if (!(mask & Button1Mask)) break; /* button released */ /* compute new value based on mouse pos */ newhue = computeHDval(hd, x,y); if (newhue<0) newhue = hd->stval; /* at 'spaz' point, keep hue const */ dx = x - hd->x; dy = y - hd->y; dist = sqrt(dx*dx + dy*dy); newsat = (int) (dist / ((double) (HD_RADIUS - 4)) * 100); RANGE(newsat,0,100); if (newhue != hd->stval || newsat != hd->satval) { HDRedraw(hd, HD_CLHNDS); hd->stval = newhue; hd->satval = newsat; HDRedraw(hd, HD_HANDS | HD_VALS); if (hd->drawobj) (hd->drawobj)(); } } rv = (hd->stval != ihue || hd->satval != isat); } else { /* the hard case */ double a; int handle = 0, *valp; /* determine if we're in either of the handles */ a = hdg2xdg(hd->stval) * DEG2RAD; pol2xy(hd->x, hd->y, a, HD_RADIUS-4, &x,&y); if (PTINRECT(mx,my,x-3,y-3,7,7)) handle = 1; a = hdg2xdg(hd->enval) * DEG2RAD; pol2xy(hd->x, hd->y, a, HD_RADIUS-4, &x,&y); if (PTINRECT(mx,my,x-3,y-3,7,7)) handle = 2; if (!handle) { /* not in either, rotate both */ int oldj, len, origj; if (!hd->ccwise) { len = ((hd->enval - hd->stval + 360) % 360); oldj = (hd->stval + len/2 + 360) % 360; } else { len = ((hd->stval - hd->enval + 360) % 360); oldj = (hd->enval + len/2 + 360) % 360; } origj = j = oldj; while (XQueryPointer(theDisp,hd->win,&rW,&cW,&rx,&ry,&x,&y,&mask)) { if (!(mask & Button1Mask)) break; /* button released */ /* compute new value based on mouse pos */ j = computeHDval(hd, x,y); if (j>=0 && j != oldj) { oldj = j; HDRedraw(hd, HD_CLHNDS); if (!hd->ccwise) { hd->stval = (j - len/2 + 360) % 360; hd->enval = (j + len/2 + 360) % 360; } else { hd->stval = (j + len/2 + 360) % 360; hd->enval = (j - len/2 + 360) % 360; } HDRedraw(hd, HD_HANDS | HD_DIR | HD_VALS); if (hd->drawobj) (hd->drawobj)(); } } rv = (origj != j); } else { /* in one of the handles */ if (handle==1) valp = &(hd->stval); else valp = &(hd->enval); ival = *valp; /* loop until mouse is released */ while (XQueryPointer(theDisp,hd->win,&rW,&cW,&rx,&ry,&x,&y,&mask)) { if (!(mask & Button1Mask)) break; /* button released */ /* compute new value based on mouse pos */ j = computeHDval(hd, x,y); if (j>=0 && j != *valp) { int ndist, ddist; HDRedraw(hd, HD_CLHNDS); if (!hd->ccwise) { ddist = (hd->enval - hd->stval + 360) % 360; if (handle==1) ndist = (hd->enval - j + 360) % 360; else ndist = (j - hd->stval + 360) % 360; } else { ddist = (hd->stval - hd->enval + 360) % 360; if (handle==1) ndist = (j - hd->enval + 360) % 360; else ndist = (hd->stval - j + 360) % 360; } if (abs(ddist - ndist) >= 180 && ddist<180) hd->ccwise = !hd->ccwise; *valp = j; HDRedraw(hd, HD_HANDS | HD_DIR | HD_VALS); if (hd->drawobj) (hd->drawobj)(); } } rv = (*valp != ival); } } return rv; } /**************************************************/ static int hdg2xdg(hdg) int hdg; { int xdg; xdg = 270 - hdg; if (xdg < 0) xdg += 360; if (xdg > 360) xdg -= 360; return xdg; } /**************************************************/ static void pol2xy(cx, cy, ang, rad, xp, yp) int cx, cy, rad, *xp, *yp; double ang; { *xp = cx + (int) (cos(ang) * (double) rad); *yp = cy - (int) (sin(ang) * (double) rad); } /***************************************************/ static int computeHDval(hd, x, y) HDIAL *hd; int x, y; { int dx, dy; double angle; /* compute dx, dy (distance from center). Note: +dy is *up* */ dx = x - hd->x; dy = hd->y - y; /* if too close to center, return -1 (invalid) avoid 'spazzing' */ if (abs(dx) < 3 && abs(dy) < 3) return -1; /* figure out angle of vector dx,dy */ if (dx==0) { /* special case */ if (dy>0) angle = 90.0; else angle = -90.0; } else if (dx>0) angle = atan((double) dy / (double) dx) * RAD2DEG; else angle = atan((double) -dy / (double) -dx) * RAD2DEG + 180.0; angle = 270 - angle; /* map into h-degrees */ if (angle >= 360.0) angle -= 360.0; if (angle < 0.0) angle += 360.0; return (int) angle; } /****************************************************/ static void initHmap() { int i; for (i=0; i%d) ", a1, a2); } if (DEBUG) fprintf(stderr,"\n"); } } } } /*********************/ byte *GammifyPic24(pic24, wide, high) byte *pic24; int wide,high; { /* applies HSV/RGB modifications to each pixel in given 24-bit image. creates and returns a new picture, or NULL on failure. Also, checks to see if the result will be the same as the input, and if so, also returns NULL, as a time-saving maneuver */ byte *pp, *op; int i,j; int rv, gv, bv, vi, hi; byte *outpic; int min, max, del, h, s, v; int f, p, q, t, vs100, vsf10000; int hsvmod, rgbmod; outpic = (byte *) NULL; if (!enabCB.val) return outpic; /* mods turned off */ printUTime("start of GammifyPic24"); /* check for HSV/RGB control linearity */ hsvmod = rgbmod = 0; /* check HUE remapping */ for (i=0; i<360 && hremap[i] == i; i++); if (i!=360) hsvmod++; if (whtHD.enabCB.val && whtHD.satval) hsvmod++; if (satDial.val != 0) hsvmod++; /* check intensity graf */ for (i=0; i<256; i++) { if (intGraf.func[i] != i) break; } if (i<256) hsvmod++; /* check R,G,B grafs simultaneously */ for (i=0; i<256; i++) { if (rGraf.func[i] != i || gGraf.func[i] != i || bGraf.func[i] != i) break; } if (i<256) rgbmod++; if (!hsvmod && !rgbmod) return outpic; /* apparently, it's linear */ WaitCursor(); printUTime("NonLINEAR"); outpic = (byte *) malloc(wide * high * 3); if (!outpic) return outpic; pp = pic24; op = outpic; for (i=wide * high; i; i--) { if ((i&0x7fff)==0) WaitCursor(); rv = *pp++; gv = *pp++; bv = *pp++; if (hsvmod) { /* convert RGB to HSV */ /* the HSV computed will be int's ranging -1..359, 0..100, 0..255 */ max = (rv>gv) ? rv : gv; /* compute maximum of rv,gv,bv */ if (maxbv) min=bv; del = max - min; v = max; if (max != 0) s = (del * 100) / max; else s = 0; h = NOHUE; if (s) { if (rv==max) h = ((gv - bv) * 100) / del; else if (gv==max) h = 200 + ((bv - rv) * 100) / del; else if (bv==max) h = 400 + ((rv - gv) * 100) / del; /* h is in range -100..500 (= -1.0 .. 5.0) */ if (h<0) h += 600; /* h is in range 000..600 (0.0 .. 6.0) */ h = (h * 60) / 100; /* h is in range 0..360 */ if (h>=360) h -= 360; } /* apply HSV mods */ /* map near-black to black to avoid weird effects */ if (v <= 16) s = 0; /* apply intGraf.func[] function to 'v' (the intensity) */ v = intGraf.func[v]; /* do Hue remapping */ if (h>=0) h = hremap[h]; else { /* NOHUE */ if (whtHD.enabCB.val && (whtHD.stval || whtHD.satval)) { h = whtHD.stval; s = whtHD.satval; } } /* apply satDial value to s */ s = s + satDial.val; if (s< 0) s = 0; if (s>100) s = 100; /* convert HSV back to RGB */ if (h==NOHUE || !s) { rv = gv = bv = v; } else { if (h==360) h = 0; h = (h*100) / 60; /* h is in range 000..599 (0.0 - 5.99) */ j = h - (h%100); /* j = 000, 100, 200, 300, 400, 500 */ f = h - j; /* 'fractional' part of h (00..99) */ vs100 = (v*s)/100; vsf10000 = (v*s*f)/10000; p = v - vs100; q = v - vsf10000; t = v - vs100 + vsf10000; switch (j) { case 000: rv = v; gv = t; bv = p; break; case 100: rv = q; gv = v; bv = p; break; case 200: rv = p; gv = v; bv = t; break; case 300: rv = p; gv = q; bv = v; break; case 400: rv = t; gv = p; bv = v; break; case 500: rv = v; gv = p; bv = q; break; default: rv = gv = bv = 0; /* never happens */ } } } /* if hsvmod */ *op++ = rGraf.func[rv]; *op++ = gGraf.func[gv]; *op++ = bGraf.func[bv]; } printUTime("end of GammifyPic24"); return outpic; } /*********************/ void GamSetAutoApply(val) int val; { /* turns auto apply checkbox on/off. If val == -1, sets to 'default' val */ if (!gamW) return; /* not created yet. shouldn't happen */ if (val < 0) autoCB.val = defAutoApply; else autoCB.val = val; CBRedraw(&autoCB); }