/* * editpal.c * * Edits VGA 256-color palettes. * * Key to initials: * * EAN - Ethan Nagel [70022,2552] * * JJB - Juan J. Buhler [jbuhler@gidef.edu.ar] * * TIW - Tim Wegner * * AMC - Andrew McCarthy [andrewmc@netsoc.ucd.ie] * * Revision History: * * 10-22-90 EAN Initial release. * * 10-23-90 EAN "Discovered" get_line/put_line functions, integrated * them in (instead of only getcolor/putcolor). Much * faster! * Redesigned color editors (now at top of palette) and * re-assigned some keys. * Added (A)uto option. * Fixed memory allocation problem. Now uses shared * FRACTINT data area (strlocn). Uses 6 bytes DS. * * 10-27-90 EAN Added save to memory option - will save screen image to * memory, if enough mem avail. (disk otherwise). * Added s(T)ripe mode - works like (S)hade except only * changes every n'th entry. * Added temporary palette save/restore. (Can work like * an undo feature.) Thanks to Pieter Branderhorst for * idea. * * 10-28-90 EAN The (H)ide function now makes the palette invisible, * while allowing any other operations (except '\\' - * move/resize) to continue. * * 10-29-90 PB (in EAN's absence, ) * Change 'c' to 'd' and 's' to '=' for below. * Add 'l' to load palette from .map, 's' to store .map. * Add 'c' to invoke color cycling. * Change cursor to use whatever colors it can from * the palette (not fixed 0 and 255). * Restore colors 0 and 255 to real values whenever * palette is not on display. * Rotate 255 colors instead of 254. * Reduce cursor blink rate. * * 11-15-90 EAN Minor "bug" fixes. Continuous rotation now at a fixed * rate - once every timer tick (18.2 sec); Blanks out * color samples when rotating; Editors no longer rotate * with the colors in color rotation mode; Eliminated * (Z)oom mode; other minor fixes. * * 01-05-91 PB Add 'w' function to convert to greyscale. * * 01-16-91 PB Change rotate function to use new cyclerange stuff. * * 01-29-91 EAN Made all colors editable. The two reserved colors are * X'ed out. They can be edited but the color is not * visible. (There is an X over the sample instead.) * Changed default reserved colors to 254 & 255. * Added 'v' command to set the reserved colors to those * under the editors. * Added 'o' command to set the rotate range to between * the two editors. * Modified 'w' function: * uses internal function to do conversion (not BIOS) * will convert only current color if in 'x' mode or * range between editors in 'y' mode or entire palette * if in "normal" mode. * * 02-08-91 EAN Improved 16 color support. In 16 color mode, colors * 16-255 have a dot over them and are editable but not * visible (like the two reserved colors). * * 09-08-91 SWT Added 'n' command to make a negative color palette: * will convert only current color if in 'x' mode or * range between editors in 'y' mode or entire palette * if in "normal" mode. * * 03-03-92 JJB Added '!', '@' and '#' commands to swap RG, GB and * RB columns (sorry, I didn't find better keys) * * 10-03-92 TIW Minor changes for Jiim support, primarily changing * variables from static to global. * * 2-11-93 EAN Added full Undo ('U' key) and Redo ('E' key) * capability. Works pretty much as you'd expect * it to. * * 3-6-93 EAN Modified "freestyle" mode, written by RB, to integrate * into palette editor more completely and work with * undo logic. * Added status area under the "fractint" message to * display current state of editor. A = Auto mode, * X, Y = exclusion modes, F = freesyle mode, T = stripe * mode is waiting for #. * * 03-21-97 AMC Made '"' work the same as '@' and made 'œ' work like * (seems to work) '#' for those of us on this side of the Atlantic! * The original palette is now stored in the other slots * on startup, so you can 'undo all' if you haven't * overwritten them already. Undo could do this, but * this is handy. */ #ifdef DEBUG_UNDO #include "mdisp.h" /* EAN 930211 *** Debug Only *** */ #endif #include #ifndef XFRACT #include #else #include #endif #ifdef __TURBOC__ # include /* to get mem...() declarations */ #endif /* see Fractint.c for a description of the "include" hierarchy */ #include "port.h" #include "prototyp.h" /* * misc. #defines */ #define FONT_DEPTH 8 /* font size */ #define CSIZE_MIN 8 /* csize cannot be smaller than this */ #define CURSOR_SIZE 5 /* length of one side of the x-hair cursor */ #ifndef XFRACT #define CURSOR_BLINK_RATE 3 /* timer ticks between cursor blinks */ #else #define CURSOR_BLINK_RATE 300 /* timer ticks between cursor blinks */ #endif #define FAR_RESERVE 8192L /* amount of far mem we will leave avail. */ #define MAX_WIDTH 1024 /* palette editor cannot be wider than this */ char scrnfile[] = "FRACTINT.$$1"; /* file where screen portion is */ /* stored */ char undofile[] = "FRACTINT.$$2"; /* file where undo list is stored */ #define TITLE "FRACTINT" #define TITLE_LEN (8) #define newx(size) mem_alloc(size) #define new(class) (class *)(mem_alloc(sizeof(class))) #define delete(block) block=NULL /* just for warning */ #ifdef XFRACT int editpal_cursor = 0; #endif /* * Stuff from fractint */ #if 0 /* declarations moved to PRORTOTYPE.H - this left for docs */ BYTE dacbox[256][3]; /* DAC spindac() will use */ int sxdots; /* width of physical screen */ int sydots; /* depth of physical screen */ int sxoffs; /* start of logical screen */ int syoffs; /* start of logical screen */ int lookatmouse; /* mouse mode for getakey(), etc */ int strlocn[]; /* 10K buffer to store classes in */ int colors; /* # colors avail. */ int color_bright; /* brightest color in palette */ int color_dark; /* darkest color in palette */ int color_medium; /* nearest to medbright gray color */ int rotate_lo, rotate_hi; int debugflag; #endif int using_jiim = 0; /* * basic data types */ typedef struct { BYTE red, green, blue; } PALENTRY; /* * static data */ static BYTE far *font8x8 = NULL; BYTE *line_buff; /* must be alloced!!! */ static BYTE fg_color, bg_color; static BOOLEAN reserve_colors; static BOOLEAN inverse; static float gamma_val = 1; /* * Interface to FRACTINT's graphics stuff */ static void setpal(int pal, int r, int g, int b) { dacbox[pal][0] = (BYTE)r; dacbox[pal][1] = (BYTE)g; dacbox[pal][2] = (BYTE)b; spindac(0,1); } static void setpalrange(int first, int how_many, PALENTRY *pal) { memmove(dacbox+first, pal, how_many*3); spindac(0,1); } static void getpalrange(int first, int how_many, PALENTRY *pal) { memmove(pal, dacbox+first, how_many*3); } static void rotatepal(PALENTRY *pal, int dir, int lo, int hi) { /* rotate in either direction */ PALENTRY hold; int size; size = 1 + (hi-lo); if ( dir > 0 ) { while ( dir-- > 0 ) { memmove(&hold, &pal[hi], 3); memmove(&pal[lo+1], &pal[lo], 3*(size-1)); memmove(&pal[lo], &hold, 3); } } else if ( dir < 0 ) { while ( dir++ < 0 ) { memmove(&hold, &pal[lo], 3); memmove(&pal[lo], &pal[lo+1], 3*(size-1)); memmove(&pal[hi], &hold, 3); } } } static void clip_put_line(int row, int start, int stop, BYTE *pixels) { if ( row < 0 || row >= sydots || start > sxdots || stop < 0 ) return ; if ( start < 0 ) { pixels += -start; start = 0; } if ( stop >= sxdots ) stop = sxdots - 1; if ( start > stop ) return ; put_line(row, start, stop, pixels); } static void clip_get_line(int row, int start, int stop, BYTE *pixels) { if ( row < 0 || row >= sydots || start > sxdots || stop < 0 ) return ; if ( start < 0 ) { pixels += -start; start = 0; } if ( stop >= sxdots ) stop = sxdots - 1; if ( start > stop ) return ; get_line(row, start, stop, pixels); } void clip_putcolor(int x, int y, int color) { if ( x < 0 || y < 0 || x >= sxdots || y >= sydots ) return ; putcolor(x, y, color); } int clip_getcolor(int x, int y) { if ( x < 0 || y < 0 || x >= sxdots || y >= sydots ) return (0); return ( getcolor(x, y) ); } void hline(int x, int y, int width, int color) { memset(line_buff, color, width); clip_put_line(y, x, x+width-1, line_buff); } void vline(int x, int y, int depth, int color) { while (depth-- > 0) clip_putcolor(x, y++, color); } void getrow(int x, int y, int width, char *buff) { clip_get_line(y, x, x+width-1, (BYTE *)buff); } void putrow(int x, int y, int width, char *buff) { clip_put_line(y, x, x+width-1, (BYTE *)buff); } static void vgetrow(int x, int y, int depth, char *buff) { while (depth-- > 0) *buff++ = (char)clip_getcolor(x, y++); } static void vputrow(int x, int y, int depth, char *buff) { while (depth-- > 0) clip_putcolor(x, y++, (BYTE)(*buff++)); } static void fillrect(int x, int y, int width, int depth, int color) { while (depth-- > 0) hline(x, y++, width, color); } static void rect(int x, int y, int width, int depth, int color) { hline(x, y, width, color); hline(x, y+depth-1, width, color); vline(x, y, depth, color); vline(x+width-1, y, depth, color); } void displayc(int x, int y, int fg, int bg, int ch) { int xc, yc; BYTE t; BYTE far *ptr; if( font8x8 == NULL) if ( (font8x8 = findfont(0)) == NULL ) return ; ptr = ((BYTE far *)font8x8) + ch*FONT_DEPTH; for (yc=0; ycred - (int) p1->red ) / num, gm = (double)((int) p2->green - (int) p1->green) / num, bm = (double)((int) p2->blue - (int) p1->blue ) / num; for (curr=0; currred == p2->red ) ? p1->red : (int) p1->red + (int) ( rm * curr )); pal[curr].green = (BYTE)((p1->green == p2->green) ? p1->green : (int) p1->green + (int) ( gm * curr )); pal[curr].blue = (BYTE)((p1->blue == p2->blue ) ? p1->blue : (int) p1->blue + (int) ( bm * curr )); } else { pal[curr].red = (BYTE)((p1->red == p2->red ) ? p1->red : (int) (p1->red + pow(curr/(double)(num-1),gamma_val)*num*rm)); pal[curr].green = (BYTE)((p1->green == p2->green) ? p1->green : (int) (p1->green + pow(curr/(double)(num-1),gamma_val)*num*gm)); pal[curr].blue = (BYTE)((p1->blue == p2->blue ) ? p1->blue : (int) (p1->blue + pow(curr/(double)(num-1),gamma_val)*num*bm)); } } } /* Swap RG GB & RB columns */ static void rotcolrg(PALENTRY pal[], int num) { int curr; int dummy; for (curr=0; curr<=num; curr++) { dummy = pal[curr].red; pal[curr].red = pal[curr].green; pal[curr].green = (BYTE)dummy; } } static void rotcolgb(PALENTRY pal[], int num) { int curr; int dummy; for (curr=0; curr<=num; curr++) { dummy = pal[curr].green; pal[curr].green = pal[curr].blue; pal[curr].blue = (BYTE)dummy; } } static void rotcolbr(PALENTRY pal[], int num) { int curr; int dummy; for (curr=0; curr<=num; curr++) { dummy = pal[curr].red; pal[curr].red = pal[curr].blue; pal[curr].blue = (BYTE)dummy; } } /* * convert a range of colors to grey scale */ static void palrangetogrey(PALENTRY pal[], int first, int how_many) { PALENTRY *curr; BYTE val; for (curr = &pal[first]; how_many>0; how_many--, curr++) { val = (BYTE) ( ((int)curr->red*30 + (int)curr->green*59 + (int)curr->blue*11) / 100 ); curr->red = curr->green = curr->blue = (BYTE)val; } } /* * convert a range of colors to their inverse */ static void palrangetonegative(PALENTRY pal[], int first, int how_many) { PALENTRY *curr; for (curr = &pal[first]; how_many>0; how_many--, curr++) { curr->red = (BYTE)(63 - curr->red); curr->green = (BYTE)(63 - curr->green); curr->blue = (BYTE)(63 - curr->blue); } } /* * draw and horizontal/vertical dotted lines */ static void hdline(int x, int y, int width) { int ctr; BYTE *ptr; for (ctr=0, ptr=line_buff; ctr= bx) && (y >= by) && (x < bx+bw) && (y < by+bd)) ); } static void draw_diamond(int x, int y, int color) { putcolor (x+2, y+0, color); hline (x+1, y+1, 3, color); hline (x+0, y+2, 5, color); hline (x+1, y+3, 3, color); putcolor (x+2, y+4, color); } /* * Class: Cursor * * Purpose: Draw the blinking cross-hair cursor. * * Note: Only one Cursor can exist (referenced through the_cursor). * IMPORTANT: Call Cursor_Construct before you use any other * Cursor_ function! Call Cursor_Destroy before exiting to * deallocate memory. */ struct _Cursor { int x, y; int hidden; /* >0 if mouse hidden */ long last_blink; BOOLEAN blink; #if 0 char t[CURSOR_SIZE], /* save line segments here */ b[CURSOR_SIZE], l[CURSOR_SIZE], r[CURSOR_SIZE]; #endif char t[CURSOR_SIZE]; /* save line segments here */ char b[CURSOR_SIZE]; char l[CURSOR_SIZE]; char r[CURSOR_SIZE]; } ; #define Cursor struct _Cursor /* private: */ static void Cursor__Draw (void); static void Cursor__Save (void); static void Cursor__Restore (void); /* public: */ #ifdef NOT_USED static BOOLEAN Cursor_IsHidden (void); #endif static Cursor *the_cursor = NULL; BOOLEAN Cursor_Construct(void) { if (the_cursor != NULL) return(FALSE); the_cursor = new(Cursor); the_cursor->x = sxdots/2; the_cursor->y = sydots/2; the_cursor->hidden = 1; the_cursor->blink = FALSE; the_cursor->last_blink = 0; return (TRUE); } void Cursor_Destroy(void) { if (the_cursor != NULL) delete(the_cursor); the_cursor = NULL; } static void Cursor__Draw(void) { int color; find_special_colors(); color = (the_cursor->blink) ? color_medium : color_dark; vline(the_cursor->x, the_cursor->y-CURSOR_SIZE-1, CURSOR_SIZE, color); vline(the_cursor->x, the_cursor->y+2, CURSOR_SIZE, color); hline(the_cursor->x-CURSOR_SIZE-1, the_cursor->y, CURSOR_SIZE, color); hline(the_cursor->x+2, the_cursor->y, CURSOR_SIZE, color); } static void Cursor__Save(void) { vgetrow(the_cursor->x, the_cursor->y-CURSOR_SIZE-1, CURSOR_SIZE, the_cursor->t); vgetrow(the_cursor->x, the_cursor->y+2, CURSOR_SIZE, the_cursor->b); getrow(the_cursor->x-CURSOR_SIZE-1, the_cursor->y, CURSOR_SIZE, the_cursor->l); getrow(the_cursor->x+2, the_cursor->y, CURSOR_SIZE, the_cursor->r); } static void Cursor__Restore(void) { vputrow(the_cursor->x, the_cursor->y-CURSOR_SIZE-1, CURSOR_SIZE, the_cursor->t); vputrow(the_cursor->x, the_cursor->y+2, CURSOR_SIZE, the_cursor->b); putrow(the_cursor->x-CURSOR_SIZE-1, the_cursor->y, CURSOR_SIZE, the_cursor->l); putrow(the_cursor->x+2, the_cursor->y, CURSOR_SIZE, the_cursor->r); } void Cursor_SetPos(int x, int y) { if (!the_cursor->hidden) Cursor__Restore(); the_cursor->x = x; the_cursor->y = y; if (!the_cursor->hidden) { Cursor__Save(); Cursor__Draw(); } } #ifdef NOT_USED static int Cursor_IsHidden(void) { return ( the_cursor->hidden ); } #endif void Cursor_Move(int xoff, int yoff) { if ( !the_cursor->hidden ) Cursor__Restore(); the_cursor->x += xoff; the_cursor->y += yoff; if (the_cursor->x < 0) the_cursor->x = 0; if (the_cursor->y < 0) the_cursor->y = 0; if (the_cursor->x >= sxdots) the_cursor->x = sxdots-1; if (the_cursor->y >= sydots) the_cursor->y = sydots-1; if ( !the_cursor->hidden ) { Cursor__Save(); Cursor__Draw(); } } int Cursor_GetX(void) { return(the_cursor->x); } int Cursor_GetY(void) { return(the_cursor->y); } void Cursor_Hide(void) { if ( the_cursor->hidden++ == 0 ) Cursor__Restore(); } void Cursor_Show(void) { if ( --the_cursor->hidden == 0) { Cursor__Save(); Cursor__Draw(); } } #ifdef XFRACT void Cursor_StartMouseTracking() { editpal_cursor = 1; } void Cursor_EndMouseTracking() { editpal_cursor = 0; } #endif /* See if the cursor should blink yet, and blink it if so */ void Cursor_CheckBlink(void) { long tick; tick = readticker(); if ( (tick - the_cursor->last_blink) > CURSOR_BLINK_RATE ) { the_cursor->blink = (BOOLEAN)((the_cursor->blink) ? FALSE : TRUE); the_cursor->last_blink = tick; if ( !the_cursor->hidden ) Cursor__Draw(); } else if ( tick < the_cursor->last_blink ) the_cursor->last_blink = tick; } int Cursor_WaitKey(void) /* blink cursor while waiting for a key */ { #ifndef XFRACT while ( !keypressed() ) { Cursor_CheckBlink(); } #else while ( !waitkeypressed(1) ) { Cursor_CheckBlink(); } #endif return( keypressed() ); } /* * Class: MoveBox * * Purpose: Handles the rectangular move/resize box. */ struct _MoveBox { int x, y; int base_width, base_depth; int csize; BOOLEAN moved; BOOLEAN should_hide; char *t, *b, *l, *r; } ; #define MoveBox struct _MoveBox /* private: */ static void MoveBox__Draw (MoveBox *this); static void MoveBox__Erase (MoveBox *this); static void MoveBox__Move (MoveBox *this, int key); /* public: */ static MoveBox *MoveBox_Construct (int x, int y, int csize, int base_width, int base_depth); static void MoveBox_Destroy (MoveBox *this); static BOOLEAN MoveBox_Process (MoveBox *this); /* returns FALSE if ESCAPED */ static BOOLEAN MoveBox_Moved (MoveBox *this); static BOOLEAN MoveBox_ShouldHide (MoveBox *this); static int MoveBox_X (MoveBox *this); static int MoveBox_Y (MoveBox *this); static int MoveBox_CSize (MoveBox *this); static void MoveBox_SetPos (MoveBox *this, int x, int y); static void MoveBox_SetCSize (MoveBox *this, int csize); static MoveBox *MoveBox_Construct(int x, int y, int csize, int base_width, int base_depth) { MoveBox *this = new(MoveBox); this->x = x; this->y = y; this->csize = csize; this->base_width = base_width; this->base_depth = base_depth; this->moved = FALSE; this->should_hide = FALSE; this->t = newx(sxdots); this->b = newx(sxdots); this->l = newx(sydots); this->r = newx(sydots); return(this); } static void MoveBox_Destroy(MoveBox *this) { delete(this->t); delete(this->b); delete(this->l); delete(this->r); delete(this); } static BOOLEAN MoveBox_Moved(MoveBox *this) { return(this->moved); } static BOOLEAN MoveBox_ShouldHide(MoveBox *this) { return(this->should_hide); } static int MoveBox_X(MoveBox *this) { return(this->x); } static int MoveBox_Y(MoveBox *this) { return(this->y); } static int MoveBox_CSize(MoveBox *this) { return(this->csize); } static void MoveBox_SetPos(MoveBox *this, int x, int y) { this->x = x; this->y = y; } static void MoveBox_SetCSize(MoveBox *this, int csize) { this->csize = csize; } static void MoveBox__Draw(MoveBox *this) /* private */ { int width = this->base_width + this->csize*16+1, depth = this->base_depth + this->csize*16+1; int x = this->x, y = this->y; getrow (x, y, width, this->t); getrow (x, y+depth-1, width, this->b); vgetrow(x, y, depth, this->l); vgetrow(x+width-1, y, depth, this->r); hdline(x, y, width); hdline(x, y+depth-1, width); vdline(x, y, depth); vdline(x+width-1, y, depth); } static void MoveBox__Erase(MoveBox *this) /* private */ { int width = this->base_width + this->csize*16+1, depth = this->base_depth + this->csize*16+1; vputrow(this->x, this->y, depth, this->l); vputrow(this->x+width-1, this->y, depth, this->r); putrow(this->x, this->y, width, this->t); putrow(this->x, this->y+depth-1, width, this->b); } #define BOX_INC 1 #define CSIZE_INC 2 static void MoveBox__Move(MoveBox *this, int key) { BOOLEAN done = FALSE; BOOLEAN first = TRUE; int xoff = 0, yoff = 0; while ( !done ) { switch(key) { case RIGHT_ARROW_2: xoff += BOX_INC*4; break; case RIGHT_ARROW: xoff += BOX_INC; break; case LEFT_ARROW_2: xoff -= BOX_INC*4; break; case LEFT_ARROW: xoff -= BOX_INC; break; case DOWN_ARROW_2: yoff += BOX_INC*4; break; case DOWN_ARROW: yoff += BOX_INC; break; case UP_ARROW_2: yoff -= BOX_INC*4; break; case UP_ARROW: yoff -= BOX_INC; break; default: done = TRUE; } if (!done) { if (!first) getakey(); /* delete key from buffer */ else first = FALSE; key = keypressed(); /* peek at the next one... */ } } xoff += this->x; yoff += this->y; /* (xoff,yoff) = new position */ if (xoff < 0) xoff = 0; if (yoff < 0) yoff = 0; if (xoff+this->base_width+this->csize*16+1 > sxdots) xoff = sxdots - (this->base_width+this->csize*16+1); if (yoff+this->base_depth+this->csize*16+1 > sydots) yoff = sydots - (this->base_depth+this->csize*16+1); if ( xoff!=this->x || yoff!=this->y ) { MoveBox__Erase(this); this->y = yoff; this->x = xoff; MoveBox__Draw(this); } } static BOOLEAN MoveBox_Process(MoveBox *this) { int key; int orig_x = this->x, orig_y = this->y, orig_csize = this->csize; MoveBox__Draw(this); #ifdef XFRACT Cursor_StartMouseTracking(); #endif for(;;) { Cursor_WaitKey(); key = getakey(); if (key==ENTER || key==ENTER_2 || key==ESC || key=='H' || key=='h') { if (this->x != orig_x || this->y != orig_y || this->csize != orig_csize) this->moved = TRUE; else this->moved = FALSE; break; } switch(key) { case UP_ARROW: case DOWN_ARROW: case LEFT_ARROW: case RIGHT_ARROW: case UP_ARROW_2: case DOWN_ARROW_2: case LEFT_ARROW_2: case RIGHT_ARROW_2: MoveBox__Move(this, key); break; case PAGE_UP: /* shrink */ if (this->csize > CSIZE_MIN) { int t = this->csize - CSIZE_INC; int change; if (t < CSIZE_MIN) t = CSIZE_MIN; MoveBox__Erase(this); change = this->csize - t; this->csize = t; this->x += (change*16) / 2; this->y += (change*16) / 2; MoveBox__Draw(this); } break; case PAGE_DOWN: /* grow */ { int max_width = min(sxdots, MAX_WIDTH); if (this->base_depth+(this->csize+CSIZE_INC)*16+1 < sydots && this->base_width+(this->csize+CSIZE_INC)*16+1 < max_width ) { MoveBox__Erase(this); this->x -= (CSIZE_INC*16) / 2; this->y -= (CSIZE_INC*16) / 2; this->csize += CSIZE_INC; if (this->y+this->base_depth+this->csize*16+1 > sydots) this->y = sydots - (this->base_depth+this->csize*16+1); if (this->x+this->base_width+this->csize*16+1 > max_width) this->x = max_width - (this->base_width+this->csize*16+1); if (this->y < 0) this->y = 0; if (this->x < 0) this->x = 0; MoveBox__Draw(this); } } break; } } #ifdef XFRACT Cursor_EndMouseTracking(); #endif MoveBox__Erase(this); this->should_hide = (BOOLEAN)((key == 'H' || key == 'h') ? TRUE : FALSE); return( (BOOLEAN)((key==ESC) ? FALSE : TRUE) ); } /* * Class: CEditor * * Purpose: Edits a single color component (R, G or B) * * Note: Calls the "other_key" function to process keys it doesn't use. * The "change" function is called whenever the value is changed * by the CEditor. */ struct _CEditor { int x, y; char letter; int val; BOOLEAN done; BOOLEAN hidden; #ifndef XFRACT void (*other_key)(int key, struct _CEditor *ce, VOIDPTR info); void (*change)(struct _CEditor *ce, VOIDPTR info); #else void (*other_key)(); void (*change)(); #endif void *info; } ; #define CEditor struct _CEditor /* public: */ #ifndef XFRACT static CEditor *CEditor_Construct( int x, int y, char letter, void (*other_key)(int,CEditor*,void*), void (*change)(CEditor*,void*), VOIDPTR info); static void CEditor_Destroy (CEditor *this); static void CEditor_Draw (CEditor *this); static void CEditor_SetPos (CEditor *this, int x, int y); static void CEditor_SetVal (CEditor *this, int val); static int CEditor_GetVal (CEditor *this); static void CEditor_SetDone (CEditor *this, BOOLEAN done); static void CEditor_SetHidden (CEditor *this, BOOLEAN hidden); static int CEditor_Edit (CEditor *this); #else static CEditor *CEditor_Construct( int , int , char , void (*other_key)(), void (*change)(), VOIDPTR ); static void CEditor_Destroy (CEditor *); static void CEditor_Draw (CEditor *); static void CEditor_SetPos (CEditor *, int , int ); static void CEditor_SetVal (CEditor *, int ); static int CEditor_GetVal (CEditor *); static void CEditor_SetDone (CEditor *, BOOLEAN ); static void CEditor_SetHidden (CEditor *, BOOLEAN ); static int CEditor_Edit (CEditor *); #endif #define CEditor_WIDTH (8*3+4) #define CEditor_DEPTH (8+4) #ifndef XFRACT static CEditor *CEditor_Construct( int x, int y, char letter, void (*other_key)(int,CEditor*,VOIDPTR), void (*change)(CEditor*, VOIDPTR), VOIDPTR info) #else static CEditor *CEditor_Construct( int x, int y, char letter, void (*other_key)(), void (*change)(), VOIDPTR info) #endif { CEditor *this = new(CEditor); this->x = x; this->y = y; this->letter = letter; this->val = 0; this->other_key = other_key; this->hidden = FALSE; this->change = change; this->info = info; return(this); } #ifdef __TURBOC__ # pragma argsused /* kills "arg not used" warning */ #endif #ifdef __CLINT__ # pragma argsused /* kills "arg not used" warning */ #endif static void CEditor_Destroy(CEditor *this) { delete(this); } static void CEditor_Draw(CEditor *this) { if (this->hidden) return; Cursor_Hide(); displayf(this->x+2, this->y+2, fg_color, bg_color, "%c%02d", this->letter, this->val); Cursor_Show(); } static void CEditor_SetPos(CEditor *this, int x, int y) { this->x = x; this->y = y; } static void CEditor_SetVal(CEditor *this, int val) { this->val = val; } static int CEditor_GetVal(CEditor *this) { return(this->val); } static void CEditor_SetDone(CEditor *this, BOOLEAN done) { this->done = done; } static void CEditor_SetHidden(CEditor *this, BOOLEAN hidden) { this->hidden = hidden; } static int CEditor_Edit(CEditor *this) { int key; int diff; this->done = FALSE; if (!this->hidden) { Cursor_Hide(); rect(this->x, this->y, CEditor_WIDTH, CEditor_DEPTH, fg_color); Cursor_Show(); } #ifdef XFRACT Cursor_StartMouseTracking(); #endif while ( !this->done ) { Cursor_WaitKey(); key = getakey(); switch( key ) { case PAGE_UP: if (this->val < 63) { this->val += 5; if (this->val > 63) this->val = 63; CEditor_Draw(this); this->change(this, this->info); } break; case '+': case CTL_PLUS: /*RB*/ diff = 1; while ( keypressed() == key ) { getakey(); ++diff; } if (this->val < 63) { this->val += diff; if (this->val > 63) this->val = 63; CEditor_Draw(this); this->change(this, this->info); } break; case PAGE_DOWN: if (this->val > 0) { this->val -= 5; if (this->val < 0) this->val = 0; CEditor_Draw(this); this->change(this, this->info); } break; case '-': case CTL_MINUS: /*RB*/ diff = 1; while ( keypressed() == key ) { getakey(); ++diff; } if (this->val > 0) { this->val -= diff; if (this->val < 0) this->val = 0; CEditor_Draw(this); this->change(this, this->info); } break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': this->val = (key - '0') * 10; if (this->val > 63) this->val = 63; CEditor_Draw(this); this->change(this, this->info); break; default: this->other_key(key, this, this->info); break; } /* switch */ } /* while */ #ifdef XFRACT Cursor_EndMouseTracking(); #endif if (!this->hidden) { Cursor_Hide(); rect(this->x, this->y, CEditor_WIDTH, CEditor_DEPTH, bg_color); Cursor_Show(); } return(key); } /* * Class: RGBEditor * * Purpose: Edits a complete color using three CEditors for R, G and B */ struct _RGBEditor { int x, y; /* position */ int curr; /* 0=r, 1=g, 2=b */ int pal; /* palette number */ BOOLEAN done; BOOLEAN hidden; CEditor *color[3]; /* color editors 0=r, 1=g, 2=b */ #ifndef XFRACT void (*other_key)(int key, struct _RGBEditor *e, VOIDPTR info); void (*change)(struct _RGBEditor *e, VOIDPTR info); #else void (*other_key)(); void (*change)(); #endif void *info; } ; #define RGBEditor struct _RGBEditor /* private: */ static void RGBEditor__other_key (int key, CEditor *ceditor, VOIDPTR info); static void RGBEditor__change (CEditor *ceditor, VOIDPTR info); /* public: */ #ifndef XFRACT static RGBEditor *RGBEditor_Construct(int x, int y, void (*other_key)(int,RGBEditor*,void*), void (*change)(RGBEditor*,void*), VOIDPTR info); #else static RGBEditor *RGBEditor_Construct(int x, int y, void (*other_key)(), void (*change)(), VOIDPTR info); #endif static void RGBEditor_Destroy (RGBEditor *this); static void RGBEditor_SetPos (RGBEditor *this, int x, int y); static void RGBEditor_SetDone (RGBEditor *this, BOOLEAN done); static void RGBEditor_SetHidden(RGBEditor *this, BOOLEAN hidden); static void RGBEditor_BlankSampleBox(RGBEditor *this); static void RGBEditor_Update (RGBEditor *this); static void RGBEditor_Draw (RGBEditor *this); static int RGBEditor_Edit (RGBEditor *this); static void RGBEditor_SetRGB (RGBEditor *this, int pal, PALENTRY *rgb); static PALENTRY RGBEditor_GetRGB (RGBEditor *this); #define RGBEditor_WIDTH 62 #define RGBEditor_DEPTH (1+1+CEditor_DEPTH*3-2+2) #define RGBEditor_BWIDTH ( RGBEditor_WIDTH - (2+CEditor_WIDTH+1 + 2) ) #define RGBEditor_BDEPTH ( RGBEditor_DEPTH - 4 ) #ifndef XFRACT static RGBEditor *RGBEditor_Construct(int x, int y, void (*other_key)(int,RGBEditor*,void*), void (*change)(RGBEditor*,void*), VOIDPTR info) #else static RGBEditor *RGBEditor_Construct(int x, int y, void (*other_key)(), void (*change)(), VOIDPTR info) #endif { RGBEditor *this = new(RGBEditor); static FCODE letter[] = "RGB"; int ctr; for (ctr=0; ctr<3; ctr++) this->color[ctr] = CEditor_Construct(0, 0, letter[ctr], RGBEditor__other_key, RGBEditor__change, this); RGBEditor_SetPos(this, x, y); this->curr = 0; this->pal = 1; this->hidden = FALSE; this->other_key = other_key; this->change = change; this->info = info; return(this); } static void RGBEditor_Destroy(RGBEditor *this) { CEditor_Destroy(this->color[0]); CEditor_Destroy(this->color[1]); CEditor_Destroy(this->color[2]); delete(this); } static void RGBEditor_SetDone(RGBEditor *this, BOOLEAN done) { this->done = done; } static void RGBEditor_SetHidden(RGBEditor *this, BOOLEAN hidden) { this->hidden = hidden; CEditor_SetHidden(this->color[0], hidden); CEditor_SetHidden(this->color[1], hidden); CEditor_SetHidden(this->color[2], hidden); } static void RGBEditor__other_key(int key, CEditor *ceditor, VOIDPTR info) /* private */ { RGBEditor *this = (RGBEditor *)info; switch( key ) { case 'R': case 'r': if (this->curr != 0) { this->curr = 0; CEditor_SetDone(ceditor, TRUE); } break; case 'G': case 'g': if (this->curr != 1) { this->curr = 1; CEditor_SetDone(ceditor, TRUE); } break; case 'B': case 'b': if (this->curr != 2) { this->curr = 2; CEditor_SetDone(ceditor, TRUE); } break; case DELETE: /* move to next CEditor */ case CTL_ENTER_2: /*double click rt mouse also! */ if ( ++this->curr > 2) this->curr = 0; CEditor_SetDone(ceditor, TRUE); break; case INSERT: /* move to prev CEditor */ if ( --this->curr < 0) this->curr = 2; CEditor_SetDone(ceditor, TRUE); break; default: this->other_key(key, this, this->info); if (this->done) CEditor_SetDone(ceditor, TRUE); break; } } #ifdef __TURBOC__ # pragma argsused /* kills "arg not used" warning */ #endif #ifdef __CLINT__ # pragma argsused /* kills "arg not used" warning */ #endif static void RGBEditor__change(CEditor *ceditor, VOIDPTR info) /* private */ { RGBEditor *this = (RGBEditor *)info; ceditor = NULL; /* just for warning */ if ( this->pal < colors && !is_reserved(this->pal) ) setpal(this->pal, CEditor_GetVal(this->color[0]), CEditor_GetVal(this->color[1]), CEditor_GetVal(this->color[2])); this->change(this, this->info); } static void RGBEditor_SetPos(RGBEditor *this, int x, int y) { this->x = x; this->y = y; CEditor_SetPos(this->color[0], x+2, y+2); CEditor_SetPos(this->color[1], x+2, y+2+CEditor_DEPTH-1); CEditor_SetPos(this->color[2], x+2, y+2+CEditor_DEPTH-1+CEditor_DEPTH-1); } static void RGBEditor_BlankSampleBox(RGBEditor *this) { if (this->hidden) return ; Cursor_Hide(); fillrect(this->x+2+CEditor_WIDTH+1+1, this->y+2+1, RGBEditor_BWIDTH-2, RGBEditor_BDEPTH-2, bg_color); Cursor_Show(); } static void RGBEditor_Update(RGBEditor *this) { int x1 = this->x+2+CEditor_WIDTH+1+1, y1 = this->y+2+1; if (this->hidden) return ; Cursor_Hide(); if ( this->pal >= colors ) { fillrect(x1, y1, RGBEditor_BWIDTH-2, RGBEditor_BDEPTH-2, bg_color); draw_diamond(x1+(RGBEditor_BWIDTH-5)/2, y1+(RGBEditor_BDEPTH-5)/2, fg_color); } else if ( is_reserved(this->pal) ) { int x2 = x1+RGBEditor_BWIDTH-3, y2 = y1+RGBEditor_BDEPTH-3; fillrect(x1, y1, RGBEditor_BWIDTH-2, RGBEditor_BDEPTH-2, bg_color); draw_line(x1, y1, x2, y2, fg_color); draw_line(x1, y2, x2, y1, fg_color); } else fillrect(x1, y1, RGBEditor_BWIDTH-2, RGBEditor_BDEPTH-2, this->pal); CEditor_Draw(this->color[0]); CEditor_Draw(this->color[1]); CEditor_Draw(this->color[2]); Cursor_Show(); } static void RGBEditor_Draw(RGBEditor *this) { if (this->hidden) return ; Cursor_Hide(); drect(this->x, this->y, RGBEditor_WIDTH, RGBEditor_DEPTH); fillrect(this->x+1, this->y+1, RGBEditor_WIDTH-2, RGBEditor_DEPTH-2, bg_color); rect(this->x+1+CEditor_WIDTH+2, this->y+2, RGBEditor_BWIDTH, RGBEditor_BDEPTH, fg_color); RGBEditor_Update(this); Cursor_Show(); } static int RGBEditor_Edit(RGBEditor *this) { int key; this->done = FALSE; if (!this->hidden) { Cursor_Hide(); rect(this->x, this->y, RGBEditor_WIDTH, RGBEditor_DEPTH, fg_color); Cursor_Show(); } while ( !this->done ) key = CEditor_Edit( this->color[this->curr] ); if (!this->hidden) { Cursor_Hide(); drect(this->x, this->y, RGBEditor_WIDTH, RGBEditor_DEPTH); Cursor_Show(); } return (key); } static void RGBEditor_SetRGB(RGBEditor *this, int pal, PALENTRY *rgb) { this->pal = pal; CEditor_SetVal(this->color[0], rgb->red); CEditor_SetVal(this->color[1], rgb->green); CEditor_SetVal(this->color[2], rgb->blue); } static PALENTRY RGBEditor_GetRGB(RGBEditor *this) { PALENTRY pal; pal.red = (BYTE)CEditor_GetVal(this->color[0]); pal.green = (BYTE)CEditor_GetVal(this->color[1]); pal.blue = (BYTE)CEditor_GetVal(this->color[2]); return(pal); } /* * Class: PalTable * * Purpose: This is where it all comes together. Creates the two RGBEditors * and the palette. Moves the cursor, hides/restores the screen, * handles (S)hading, (C)opying, e(X)clude mode, the "Y" exclusion * mode, (Z)oom option, (H)ide palette, rotation, etc. * */ enum stored_at_values { NOWHERE, DISK, MEMORY } ; /* Modes: Auto: "A", " " Exclusion: "X", "Y", " " Freestyle: "F", " " S(t)ripe mode: "T", " " */ struct _PalTable { int x, y; int csize; int active; /* which RGBEditor is active (0,1) */ int curr[2]; RGBEditor *rgb[2]; MoveBox *movebox; BOOLEAN done; BOOLEAN exclude; BOOLEAN auto_select; PALENTRY pal[256]; FILE *undo_file; BOOLEAN curr_changed; int num_redo; int hidden; int stored_at; FILE *file; char far *memory; PALENTRY far *save_pal[8]; PALENTRY fs_color; int top,bottom; /* top and bottom colours of freestyle band */ int bandwidth; /*size of freestyle colour band */ BOOLEAN freestyle; } ; #define PalTable struct _PalTable /* private: */ static void PalTable__DrawStatus (PalTable *this, BOOLEAN stripe_mode); static void PalTable__HlPal (PalTable *this, int pnum, int color); static void PalTable__Draw (PalTable *this); static BOOLEAN PalTable__SetCurr (PalTable *this, int which, int curr); static BOOLEAN PalTable__MemoryAlloc (PalTable *this, long size); static void PalTable__SaveRect (PalTable *this); static void PalTable__RestoreRect (PalTable *this); static void PalTable__SetPos (PalTable *this, int x, int y); static void PalTable__SetCSize (PalTable *this, int csize); static int PalTable__GetCursorColor(PalTable *this); static void PalTable__DoCurs (PalTable *this, int key); static void PalTable__Rotate (PalTable *this, int dir, int lo, int hi); static void PalTable__UpdateDAC (PalTable *this); static void PalTable__other_key (int key, RGBEditor *rgb, VOIDPTR info); static void PalTable__SaveUndoData(PalTable *this, int first, int last); static void PalTable__SaveUndoRotate(PalTable *this, int dir, int first, int last); static void PalTable__UndoProcess (PalTable *this, int delta); static void PalTable__Undo (PalTable *this); static void PalTable__Redo (PalTable *this); static void PalTable__change (RGBEditor *rgb, VOIDPTR info); /* public: */ static PalTable *PalTable_Construct (void); static void PalTable_Destroy (PalTable *this); static void PalTable_Process (PalTable *this); static void PalTable_SetHidden (PalTable *this, BOOLEAN hidden); static void PalTable_Hide (PalTable *this, RGBEditor *rgb, BOOLEAN hidden); #define PalTable_PALX (1) #define PalTable_PALY (2+RGBEditor_DEPTH+2) #define UNDO_DATA (1) #define UNDO_DATA_SINGLE (2) #define UNDO_ROTATE (3) /* - Freestyle code - */ static void PalTable__CalcTopBottom(PalTable *this) { if (this->curr[this->active] < this->bandwidth ) this->bottom = 0; else this->bottom = (this->curr[this->active]) - this->bandwidth; if (this->curr[this->active] > (255-this->bandwidth) ) this->top = 255; else this->top = (this->curr[this->active]) + this->bandwidth; } static void PalTable__PutBand(PalTable *this, PALENTRY *pal) { int r,b,a; /* clip top and bottom values to stop them running off the end of the DAC */ PalTable__CalcTopBottom(this); /* put bands either side of current colour */ a = this->curr[this->active]; b = this->bottom; r = this->top; pal[a] = this->fs_color; if (r != a && a != b) { mkpalrange(&pal[a], &pal[r], &pal[a], r-a, 1); mkpalrange(&pal[b], &pal[a], &pal[b], a-b, 1); } } /* - Undo.Redo code - */ static void PalTable__SaveUndoData(PalTable *this, int first, int last) { int num; if ( this->undo_file == NULL ) return ; num = (last - first) + 1; #ifdef DEBUG_UNDO mprintf("%6ld Writing Undo DATA from %d to %d (%d)", ftell(this->undo_file), first, last, num); #endif fseek(this->undo_file, 0, SEEK_CUR); if ( num == 1 ) { putc(UNDO_DATA_SINGLE, this->undo_file); putc(first, this->undo_file); fwrite(this->pal+first, 3, 1, this->undo_file); putw( 1 + 1 + 3 + sizeof(int), this->undo_file); } else { putc(UNDO_DATA, this->undo_file); putc(first, this->undo_file); putc(last, this->undo_file); fwrite(this->pal+first, 3, num, this->undo_file); putw(1 + 2 + (num*3) + sizeof(int), this->undo_file); } this->num_redo = 0; } static void PalTable__SaveUndoRotate(PalTable *this, int dir, int first, int last) { if ( this->undo_file == NULL ) return ; #ifdef DEBUG_UNDO mprintf("%6ld Writing Undo ROTATE of %d from %d to %d", ftell(this->undo_file), dir, first, last); #endif fseek(this->undo_file, 0, SEEK_CUR); putc(UNDO_ROTATE, this->undo_file); putc(first, this->undo_file); putc(last, this->undo_file); putw(dir, this->undo_file); putw(1 + 2 + sizeof(int), this->undo_file); this->num_redo = 0; } static void PalTable__UndoProcess(PalTable *this, int delta) /* undo/redo common code */ { /* delta = -1 for undo, +1 for redo */ int cmd = getc(this->undo_file); switch( cmd ) { case UNDO_DATA: case UNDO_DATA_SINGLE: { int first, last, num; PALENTRY temp[256]; if ( cmd == UNDO_DATA ) { first = (unsigned char)getc(this->undo_file); last = (unsigned char)getc(this->undo_file); } else /* UNDO_DATA_SINGLE */ first = last = (unsigned char)getc(this->undo_file); num = (last - first) + 1; #ifdef DEBUG_UNDO mprintf(" Reading DATA from %d to %d", first, last); #endif fread(temp, 3, num, this->undo_file); fseek(this->undo_file, -(num*3), SEEK_CUR); /* go to start of undo/redo data */ fwrite(this->pal+first, 3, num, this->undo_file); /* write redo/undo data */ memmove(this->pal+first, temp, num*3); PalTable__UpdateDAC(this); RGBEditor_SetRGB(this->rgb[0], this->curr[0], &(this->pal[this->curr[0]])); RGBEditor_SetRGB(this->rgb[1], this->curr[1], &(this->pal[this->curr[1]])); RGBEditor_Update(this->rgb[0]); RGBEditor_Update(this->rgb[1]); break; } case UNDO_ROTATE: { int first = (unsigned char)getc(this->undo_file); int last = (unsigned char)getc(this->undo_file); int dir = getw(this->undo_file); #ifdef DEBUG_UNDO mprintf(" Reading ROTATE of %d from %d to %d", dir, first, last); #endif PalTable__Rotate(this, delta*dir, first, last); break; } default: #ifdef DEBUG_UNDO mprintf(" Unknown command: %d", cmd); #endif break; } fseek(this->undo_file, 0, SEEK_CUR); /* to put us in read mode */ getw(this->undo_file); /* read size */ } static void PalTable__Undo(PalTable *this) { int size; long pos; if ( ftell(this->undo_file) <= 0 ) /* at beginning of file? */ { /* nothing to undo -- exit */ return ; } fseek(this->undo_file, -(int)sizeof(int), SEEK_CUR); /* go back to get size */ size = getw(this->undo_file); fseek(this->undo_file, -size, SEEK_CUR); /* go to start of undo */ #ifdef DEBUG_UNDO mprintf("%6ld Undo:", ftell(this->undo_file)); #endif pos = ftell(this->undo_file); PalTable__UndoProcess(this, -1); fseek(this->undo_file, pos, SEEK_SET); /* go to start of this block */ ++this->num_redo; } static void PalTable__Redo(PalTable *this) { if ( this->num_redo <= 0 ) return ; #ifdef DEBUG_UNDO mprintf("%6ld Redo:", ftell(this->undo_file)); #endif fseek(this->undo_file, 0, SEEK_CUR); /* to make sure we are in "read" mode */ PalTable__UndoProcess(this, 1); --this->num_redo; } /* - everything else - */ #define STATUS_LEN (4) static void PalTable__DrawStatus(PalTable *this, BOOLEAN stripe_mode) { int color, hunds, tens, ones; int width = 1+(this->csize*16)+1+1; if ( !this->hidden && ( width - (RGBEditor_WIDTH*2+4) >= STATUS_LEN*8 ) ) { int x = this->x + 2 + RGBEditor_WIDTH, y = this->y + PalTable_PALY - 10; color = PalTable__GetCursorColor(this); if (color < 0 || color >= colors) /* hmm, the border returns -1 */ color = 0; Cursor_Hide(); displayc(x+(0*8), y, fg_color, bg_color, (this->auto_select) ? 'A' : 254); displayc(x+(1*8), y, fg_color, bg_color, (this->exclude==1) ? 'X' : (this->exclude==2) ? 'Y' : 254); displayc(x+(2*8), y, fg_color, bg_color, (this->freestyle) ? 'F' : 254); displayc(x+(3*8), y, fg_color, bg_color, (stripe_mode) ? 'T' : 254); y = y - 10; hunds = (int)(color/100); displayc(x+(0*8), y, fg_color, bg_color, (char)(hunds) + '0' ); tens = (int)((color - (hunds * 100)) / 10); displayc(x+(1*8), y, fg_color, bg_color, (char)(tens) + '0' ); ones = (int)(color - (hunds * 100) - (tens * 10)); displayc(x+(2*8), y, fg_color, bg_color, (char)(ones) + '0' ); Cursor_Show(); } } static void PalTable__HlPal(PalTable *this, int pnum, int color) { int x = this->x + PalTable_PALX + (pnum%16)*this->csize, y = this->y + PalTable_PALY + (pnum/16)*this->csize, size = this->csize; if (this->hidden) return ; Cursor_Hide(); if (color < 0) drect(x, y, size+1, size+1); else rect(x, y, size+1, size+1, color); Cursor_Show(); } static void PalTable__Draw(PalTable *this) { int pal; int xoff, yoff; int width; if (this->hidden) return ; Cursor_Hide(); width = 1+(this->csize*16)+1+1; rect(this->x, this->y, width, 2+RGBEditor_DEPTH+2+(this->csize*16)+1+1, fg_color); fillrect(this->x+1, this->y+1, width-2, 2+RGBEditor_DEPTH+2+(this->csize*16)+1+1-2, bg_color); hline(this->x, this->y+PalTable_PALY-1, width, fg_color); if ( width - (RGBEditor_WIDTH*2+4) >= TITLE_LEN*8 ) { int center = (width - TITLE_LEN*8) / 2; displayf(this->x+center, this->y+RGBEditor_DEPTH/2-6, fg_color, bg_color, TITLE); } RGBEditor_Draw(this->rgb[0]); RGBEditor_Draw(this->rgb[1]); for (pal=0; pal<256; pal++) { xoff = PalTable_PALX + (pal%16) * this->csize; yoff = PalTable_PALY + (pal/16) * this->csize; if ( pal >= colors ) { fillrect(this->x + xoff + 1, this->y + yoff + 1, this->csize-1, this->csize-1, bg_color); draw_diamond(this->x + xoff + this->csize/2 - 1, this->y + yoff + this->csize/2 - 1, fg_color); } else if ( is_reserved(pal) ) { int x1 = this->x + xoff + 1, y1 = this->y + yoff + 1, x2 = x1 + this->csize - 2, y2 = y1 + this->csize - 2; fillrect(this->x + xoff + 1, this->y + yoff + 1, this->csize-1, this->csize-1, bg_color); draw_line(x1, y1, x2, y2, fg_color); draw_line(x1, y2, x2, y1, fg_color); } else fillrect(this->x + xoff + 1, this->y + yoff + 1, this->csize-1, this->csize-1, pal); } if (this->active == 0) { PalTable__HlPal(this, this->curr[1], -1); PalTable__HlPal(this, this->curr[0], fg_color); } else { PalTable__HlPal(this, this->curr[0], -1); PalTable__HlPal(this, this->curr[1], fg_color); } PalTable__DrawStatus(this, FALSE); Cursor_Show(); } static BOOLEAN PalTable__SetCurr(PalTable *this, int which, int curr) { BOOLEAN redraw = (BOOLEAN)((which < 0) ? TRUE : FALSE); if ( redraw ) { which = this->active; curr = this->curr[which]; } else if ( curr == this->curr[which] || curr < 0 ) return (FALSE); Cursor_Hide(); PalTable__HlPal(this, this->curr[0], bg_color); PalTable__HlPal(this, this->curr[1], bg_color); PalTable__HlPal(this, this->top, bg_color); PalTable__HlPal(this, this->bottom, bg_color); if ( this->freestyle ) { this->curr[which] = curr; PalTable__CalcTopBottom(this); PalTable__HlPal(this, this->top, -1); PalTable__HlPal(this, this->bottom, -1); PalTable__HlPal(this, this->curr[this->active], fg_color); RGBEditor_SetRGB(this->rgb[which], this->curr[which], &this->fs_color); RGBEditor_Update(this->rgb[which]); PalTable__UpdateDAC(this); Cursor_Show(); return (TRUE); } this->curr[which] = curr; if (this->curr[0] != this->curr[1]) PalTable__HlPal(this, this->curr[this->active==0?1:0], -1); PalTable__HlPal(this, this->curr[this->active], fg_color); RGBEditor_SetRGB(this->rgb[which], this->curr[which], &(this->pal[this->curr[which]])); if (redraw) { int other = (which==0) ? 1 : 0; RGBEditor_SetRGB(this->rgb[other], this->curr[other], &(this->pal[this->curr[other]])); RGBEditor_Update(this->rgb[0]); RGBEditor_Update(this->rgb[1]); } else RGBEditor_Update(this->rgb[which]); if (this->exclude) PalTable__UpdateDAC(this); Cursor_Show(); this->curr_changed = FALSE; return(TRUE); } static BOOLEAN PalTable__MemoryAlloc(PalTable *this, long size) { char far *temp; if (debugflag == 420) { this->stored_at = NOWHERE; return (FALSE); /* can't do it */ } temp = farmemalloc(FAR_RESERVE); /* minimum free space */ if (temp == NULL) { this->stored_at = NOWHERE; return (FALSE); /* can't do it */ } this->memory = farmemalloc( size ); farmemfree(temp); if ( this->memory == NULL ) { this->stored_at = NOWHERE; return (FALSE); } else { this->stored_at = MEMORY; return (TRUE); } } static void PalTable__SaveRect(PalTable *this) { char buff[MAX_WIDTH]; int width = PalTable_PALX + this->csize*16 + 1 + 1, depth = PalTable_PALY + this->csize*16 + 1 + 1; int yoff; /* first, do any de-allocationg */ switch( this->stored_at ) { case NOWHERE: break; case DISK: break; case MEMORY: if (this->memory != NULL) farmemfree(this->memory); this->memory = NULL; break; } ; /* allocate space and store the rect */ if ( PalTable__MemoryAlloc(this, (long)width*depth) ) { char far *ptr = this->memory; char far *bufptr = buff; /* MSC needs this indirection to get it right */ Cursor_Hide(); for (yoff=0; yoffx, this->y+yoff, width, buff); hline (this->x, this->y+yoff, width, bg_color); movedata(FP_SEG(bufptr), FP_OFF(bufptr), FP_SEG(ptr), FP_OFF(ptr), width); ptr = (char far *)normalize(ptr+width); } Cursor_Show(); } else /* to disk */ { this->stored_at = DISK; if ( this->file == NULL ) { this->file = dir_fopen(tempdir,scrnfile, "w+b"); if (this->file == NULL) { this->stored_at = NOWHERE; buzzer(3); return ; } } rewind(this->file); Cursor_Hide(); for (yoff=0; yoffx, this->y+yoff, width, buff); hline (this->x, this->y+yoff, width, bg_color); if ( fwrite(buff, width, 1, this->file) != 1 ) { buzzer(3); break; } } Cursor_Show(); } } static void PalTable__RestoreRect(PalTable *this) { char buff[MAX_WIDTH]; int width = PalTable_PALX + this->csize*16 + 1 + 1, depth = PalTable_PALY + this->csize*16 + 1 + 1; int yoff; if (this->hidden) return; switch ( this->stored_at ) { case DISK: rewind(this->file); Cursor_Hide(); for (yoff=0; yofffile) != 1 ) { buzzer(3); break; } putrow(this->x, this->y+yoff, width, buff); } Cursor_Show(); break; case MEMORY: { char far *ptr = this->memory; char far *bufptr = buff; /* MSC needs this indirection to get it right */ Cursor_Hide(); for (yoff=0; yoffx, this->y+yoff, width, buff); ptr = (char far *)normalize(ptr+width); } Cursor_Show(); break; } case NOWHERE: break; } /* switch */ } static void PalTable__SetPos(PalTable *this, int x, int y) { int width = PalTable_PALX + this->csize*16 + 1 + 1; this->x = x; this->y = y; RGBEditor_SetPos(this->rgb[0], x+2, y+2); RGBEditor_SetPos(this->rgb[1], x+width-2-RGBEditor_WIDTH, y+2); } static void PalTable__SetCSize(PalTable *this, int csize) { this->csize = csize; PalTable__SetPos(this, this->x, this->y); } static int PalTable__GetCursorColor(PalTable *this) { int x = Cursor_GetX(), y = Cursor_GetY(), size; int color = getcolor(x, y); if ( is_reserved(color) ) { if ( is_in_box(x, y, this->x, this->y, 1+(this->csize*16)+1+1, 2+RGBEditor_DEPTH+2+(this->csize*16)+1+1) ) { /* is the cursor over the editor? */ x -= this->x + PalTable_PALX; y -= this->y + PalTable_PALY; size = this->csize; if (x < 0 || y < 0 || x > size*16 || y > size*16) return (-1); if ( x == size*16 ) --x; if ( y == size*16 ) --y; return ( (y/size)*16 + x/size ); } else return (color); } return (color); } #define CURS_INC 1 static void PalTable__DoCurs(PalTable *this, int key) { BOOLEAN done = FALSE; BOOLEAN first = TRUE; int xoff = 0, yoff = 0; while ( !done ) { switch(key) { case RIGHT_ARROW_2: xoff += CURS_INC*4; break; case RIGHT_ARROW: xoff += CURS_INC; break; case LEFT_ARROW_2: xoff -= CURS_INC*4; break; case LEFT_ARROW: xoff -= CURS_INC; break; case DOWN_ARROW_2: yoff += CURS_INC*4; break; case DOWN_ARROW: yoff += CURS_INC; break; case UP_ARROW_2: yoff -= CURS_INC*4; break; case UP_ARROW: yoff -= CURS_INC; break; default: done = TRUE; } if (!done) { if (!first) getakey(); /* delete key from buffer */ else first = FALSE; key = keypressed(); /* peek at the next one... */ } } Cursor_Move(xoff, yoff); if (this->auto_select) PalTable__SetCurr(this, this->active, PalTable__GetCursorColor(this)); } #ifdef __TURBOC__ # pragma argsused #endif #ifdef __CLINT__ # pragma argsused #endif static void PalTable__change(RGBEditor *rgb, VOIDPTR info) { PalTable *this = (PalTable *)info; int pnum = this->curr[this->active]; if ( this->freestyle ) { this->fs_color = RGBEditor_GetRGB(rgb); PalTable__UpdateDAC(this); return ; } if ( !this->curr_changed ) { PalTable__SaveUndoData(this, pnum, pnum); this->curr_changed = TRUE; } this->pal[pnum] = RGBEditor_GetRGB(rgb); if (this->curr[0] == this->curr[1]) { int other = this->active==0 ? 1 : 0; PALENTRY color; color = RGBEditor_GetRGB(this->rgb[this->active]); RGBEditor_SetRGB(this->rgb[other], this->curr[other], &color); Cursor_Hide(); RGBEditor_Update(this->rgb[other]); Cursor_Show(); } } static void PalTable__UpdateDAC(PalTable *this) { if ( this->exclude ) { memset(dacbox, 0, 256*3); if (this->exclude == 1) { int a = this->curr[this->active]; memmove(dacbox[a], &this->pal[a], 3); } else { int a = this->curr[0], b = this->curr[1]; if (a>b) { int t=a; a=b; b=t; } memmove(dacbox[a], &this->pal[a], 3*(1+(b-a))); } } else { memmove(dacbox[0], this->pal, 3*colors); if ( this->freestyle ) PalTable__PutBand(this, (PALENTRY *)dacbox); /* apply band to dacbox */ } if ( !this->hidden ) { if (inverse) { memset(dacbox[fg_color], 0, 3); /* dacbox[fg] = (0,0,0) */ memset(dacbox[bg_color], 48, 3); /* dacbox[bg] = (48,48,48) */ } else { memset(dacbox[bg_color], 0, 3); /* dacbox[bg] = (0,0,0) */ memset(dacbox[fg_color], 48, 3); /* dacbox[fg] = (48,48,48) */ } } spindac(0,1); } static void PalTable__Rotate(PalTable *this, int dir, int lo, int hi) { rotatepal(this->pal, dir, lo, hi); Cursor_Hide(); /* update the DAC. */ PalTable__UpdateDAC(this); /* update the editors. */ RGBEditor_SetRGB(this->rgb[0], this->curr[0], &(this->pal[this->curr[0]])); RGBEditor_SetRGB(this->rgb[1], this->curr[1], &(this->pal[this->curr[1]])); RGBEditor_Update(this->rgb[0]); RGBEditor_Update(this->rgb[1]); Cursor_Show(); } static void PalTable__other_key(int key, RGBEditor *rgb, VOIDPTR info) { PalTable *this = (PalTable *)info; switch(key) { case '\\': /* move/resize */ { if (this->hidden) break; /* cannot move a hidden pal */ Cursor_Hide(); PalTable__RestoreRect(this); MoveBox_SetPos(this->movebox, this->x, this->y); MoveBox_SetCSize(this->movebox, this->csize); if ( MoveBox_Process(this->movebox) ) { if ( MoveBox_ShouldHide(this->movebox) ) PalTable_SetHidden(this, TRUE); else if ( MoveBox_Moved(this->movebox) ) { PalTable__SetPos(this, MoveBox_X(this->movebox), MoveBox_Y(this->movebox)); PalTable__SetCSize(this, MoveBox_CSize(this->movebox)); PalTable__SaveRect(this); } } PalTable__Draw(this); Cursor_Show(); RGBEditor_SetDone(this->rgb[this->active], TRUE); if (this->auto_select) PalTable__SetCurr(this, this->active, PalTable__GetCursorColor(this)); break; } case 'Y': /* exclude range */ case 'y': if ( this->exclude==2 ) this->exclude = 0; else this->exclude = 2; PalTable__UpdateDAC(this); break; case 'X': case 'x': /* exclude current entry */ if ( this->exclude==1 ) this->exclude = 0; else this->exclude = 1; PalTable__UpdateDAC(this); break; case RIGHT_ARROW: case LEFT_ARROW: case UP_ARROW: case DOWN_ARROW: case RIGHT_ARROW_2: case LEFT_ARROW_2: case UP_ARROW_2: case DOWN_ARROW_2: PalTable__DoCurs(this, key); break; case ESC: this->done = TRUE; RGBEditor_SetDone(rgb, TRUE); break; case ' ': /* select the other palette register */ this->active = (this->active==0) ? 1 : 0; if (this->auto_select) PalTable__SetCurr(this, this->active, PalTable__GetCursorColor(this)); else PalTable__SetCurr(this, -1, 0); if (this->exclude || this->freestyle) PalTable__UpdateDAC(this); RGBEditor_SetDone(rgb, TRUE); break; case ENTER: /* set register to color under cursor. useful when not */ case ENTER_2: /* in auto_select mode */ if ( this->freestyle ) { PalTable__SaveUndoData(this, this->bottom, this->top); PalTable__PutBand(this, this->pal); } PalTable__SetCurr(this, this->active, PalTable__GetCursorColor(this)); if (this->exclude || this->freestyle ) PalTable__UpdateDAC(this); RGBEditor_SetDone(rgb, TRUE); break; case 'D': /* copy (Duplicate?) color in inactive to color in active */ case 'd': { int a = this->active, b = (a==0) ? 1 : 0; PALENTRY t; t = RGBEditor_GetRGB(this->rgb[b]); Cursor_Hide(); RGBEditor_SetRGB(this->rgb[a], this->curr[a], &t); RGBEditor_Update(this->rgb[a]); PalTable__change(this->rgb[a], this); PalTable__UpdateDAC(this); Cursor_Show(); break; } case '=': /* create a shade range between the two entries */ { int a = this->curr[0], b = this->curr[1]; if (a > b) { int t = a; a = b; b = t; } PalTable__SaveUndoData(this, a, b); if (a != b) { mkpalrange(&this->pal[a], &this->pal[b], &this->pal[a], b-a, 1); PalTable__UpdateDAC(this); } break; } case '!': /* swap r<->g */ { int a = this->curr[0], b = this->curr[1]; if (a > b) { int t = a; a = b; b = t; } PalTable__SaveUndoData(this, a, b); if (a != b) { rotcolrg(&this->pal[a], b-a); PalTable__UpdateDAC(this); } break; } case '@': /* swap g<->b */ case '"': /* for Europeans! AMC */ case 151: /* for French keyboards */ { int a = this->curr[0], b = this->curr[1]; if (a > b) { int t = a; a = b; b = t; } PalTable__SaveUndoData(this, a, b); if (a != b) { rotcolgb(&this->pal[a], b-a); PalTable__UpdateDAC(this); } break; } case '#': /* swap r<->b */ case 156: /* AMC: This seems to work instead of the pound sign */ case '$': /* AMC: If all else fails! (I'd rather not use this) */ { int a = this->curr[0], b = this->curr[1]; if (a > b) { int t = a; a = b; b = t; } PalTable__SaveUndoData(this, a, b); if (a != b) { rotcolbr(&this->pal[a], b-a); PalTable__UpdateDAC(this); } break; } case 'T': case 't': /* s(T)ripe mode */ { int key; Cursor_Hide(); PalTable__DrawStatus(this, TRUE); key = getakeynohelp(); Cursor_Show(); if (key >= '1' && key <= '9') { int a = this->curr[0], b = this->curr[1]; if (a > b) { int t = a; a = b; b = t; } PalTable__SaveUndoData(this, a, b); if (a != b) { mkpalrange(&this->pal[a], &this->pal[b], &this->pal[a], b-a, key-'0'); PalTable__UpdateDAC(this); } } break; } case 'M': /* set gamma */ case 'm': { static FCODE o_msg[] = {"Enter gamma value"}; char msg[sizeof(o_msg)]; int i; char buf[20]; far_strcpy(msg,o_msg); sprintf(buf,"%.3f",1./gamma_val); stackscreen(); i = field_prompt(0,msg,NULL,buf,20,NULL); unstackscreen(); if (i != -1) { sscanf(buf,"%f",&gamma_val); if (gamma_val==0) { gamma_val = (float)0.0000000001; } gamma_val = (float)(1./gamma_val); } } break; case 'A': /* toggle auto-select mode */ case 'a': this->auto_select = (BOOLEAN)((this->auto_select) ? FALSE : TRUE); if (this->auto_select) { PalTable__SetCurr(this, this->active, PalTable__GetCursorColor(this)); if (this->exclude) PalTable__UpdateDAC(this); } break; case 'H': case 'h': /* toggle hide/display of palette editor */ Cursor_Hide(); PalTable_Hide(this, rgb, (BOOLEAN)((this->hidden) ? FALSE : TRUE)); Cursor_Show(); break; case '.': /* rotate once */ case ',': { int dir = (key=='.') ? 1 : -1; PalTable__SaveUndoRotate(this, dir, rotate_lo, rotate_hi); PalTable__Rotate(this, dir, rotate_lo, rotate_hi); break; } case '>': /* continuous rotation (until a key is pressed) */ case '<': { int dir; long tick; int diff = 0; Cursor_Hide(); if ( !this->hidden ) { RGBEditor_BlankSampleBox(this->rgb[0]); RGBEditor_BlankSampleBox(this->rgb[1]); RGBEditor_SetHidden(this->rgb[0], TRUE); RGBEditor_SetHidden(this->rgb[1], TRUE); } do { dir = (key=='>') ? 1 : -1; while ( !keypressed() ) { tick = readticker(); PalTable__Rotate(this, dir, rotate_lo, rotate_hi); diff += dir; while (readticker() == tick) ; /* wait until a tick passes */ } key = getakey(); } while (key=='<' || key=='>'); if ( !this->hidden ) { RGBEditor_SetHidden(this->rgb[0], FALSE); RGBEditor_SetHidden(this->rgb[1], FALSE); RGBEditor_Update(this->rgb[0]); RGBEditor_Update(this->rgb[1]); } if ( diff != 0 ) PalTable__SaveUndoRotate(this, diff, rotate_lo, rotate_hi); Cursor_Show(); break; } case 'I': /* invert the fg & bg colors */ case 'i': inverse = (BOOLEAN)!inverse; PalTable__UpdateDAC(this); break; case 'V': case 'v': /* set the reserved colors to the editor colors */ if ( this->curr[0] >= colors || this->curr[1] >= colors || this->curr[0] == this->curr[1] ) { buzzer(2); break; } fg_color = (BYTE)this->curr[0]; bg_color = (BYTE)this->curr[1]; if ( !this->hidden ) { Cursor_Hide(); PalTable__UpdateDAC(this); PalTable__Draw(this); Cursor_Show(); } RGBEditor_SetDone(this->rgb[this->active], TRUE); break; case 'O': /* set rotate_lo and rotate_hi to editors */ case 'o': if (this->curr[0] > this->curr[1]) { rotate_lo = this->curr[1]; rotate_hi = this->curr[0]; } else { rotate_lo = this->curr[0]; rotate_hi = this->curr[1]; } break; case F2: /* restore a palette */ case F3: case F4: case F5: case F6: case F7: case F8: case F9: { int which = key - F2; if ( this->save_pal[which] != NULL ) { struct SREGS seg; Cursor_Hide(); PalTable__SaveUndoData(this, 0, 255); segread(&seg); movedata(FP_SEG(this->save_pal[which]), FP_OFF(this->save_pal[which]), seg.ds, (USEGTYPE)(this->pal), 256*3); PalTable__UpdateDAC(this); PalTable__SetCurr(this, -1, 0); Cursor_Show(); RGBEditor_SetDone(this->rgb[this->active], TRUE); } else buzzer(3); /* error buzz */ break; } case SF2: /* save a palette */ case SF3: case SF4: case SF5: case SF6: case SF7: case SF8: case SF9: { int which = key - SF2; if ( this->save_pal[which] != NULL ) { struct SREGS seg; segread(&seg); movedata(seg.ds, (USEGTYPE)(this->pal), FP_SEG(this->save_pal[which]), FP_OFF(this->save_pal[which]), 256*3); } else buzzer(3); /* oops! short on memory! */ break; } case 'L': /* load a .map palette */ case 'l': { PalTable__SaveUndoData(this, 0, 255); load_palette(); #ifndef XFRACT getpalrange(0, colors, this->pal); #else getpalrange(0, 256, this->pal); #endif PalTable__UpdateDAC(this); RGBEditor_SetRGB(this->rgb[0], this->curr[0], &(this->pal[this->curr[0]])); RGBEditor_Update(this->rgb[0]); RGBEditor_SetRGB(this->rgb[1], this->curr[1], &(this->pal[this->curr[1]])); RGBEditor_Update(this->rgb[1]); break; } case 'S': /* save a .map palette */ case 's': { #ifndef XFRACT setpalrange(0, colors, this->pal); #else setpalrange(0, 256, this->pal); #endif save_palette(); PalTable__UpdateDAC(this); break; } case 'C': /* color cycling sub-mode */ case 'c': { BOOLEAN oldhidden = (BOOLEAN)this->hidden; PalTable__SaveUndoData(this, 0, 255); Cursor_Hide(); if ( !oldhidden ) PalTable_Hide(this, rgb, TRUE); setpalrange(0, colors, this->pal); rotate(0); getpalrange(0, colors, this->pal); PalTable__UpdateDAC(this); if ( !oldhidden ) { RGBEditor_SetRGB(this->rgb[0], this->curr[0], &(this->pal[this->curr[0]])); RGBEditor_SetRGB(this->rgb[1], this->curr[1], &(this->pal[this->curr[1]])); PalTable_Hide(this, rgb, FALSE); } Cursor_Show(); break; } case 'F': case 'f': /* toggle freestyle palette edit mode */ this->freestyle= (BOOLEAN)((this->freestyle) ? FALSE :TRUE); PalTable__SetCurr(this, -1, 0); if ( !this->freestyle ) /* if turning off... */ PalTable__UpdateDAC(this); break; case CTL_DEL: /* rt plus down */ if (this->bandwidth >0 ) this->bandwidth --; else this->bandwidth=0; PalTable__SetCurr(this, -1, 0); break; case CTL_INSERT: /* rt plus up */ if (this->bandwidth <255 ) this->bandwidth ++; else this->bandwidth = 255; PalTable__SetCurr(this, -1, 0); break; case 'W': /* convert to greyscale */ case 'w': { switch ( this->exclude ) { case 0: /* normal mode. convert all colors to grey scale */ PalTable__SaveUndoData(this, 0, 255); palrangetogrey(this->pal, 0, 256); break; case 1: /* 'x' mode. convert current color to grey scale. */ PalTable__SaveUndoData(this, this->curr[this->active], this->curr[this->active]); palrangetogrey(this->pal, this->curr[this->active], 1); break; case 2: /* 'y' mode. convert range between editors to grey. */ { int a = this->curr[0], b = this->curr[1]; if (a > b) { int t = a; a = b; b = t; } PalTable__SaveUndoData(this, a, b); palrangetogrey(this->pal, a, 1+(b-a)); break; } } PalTable__UpdateDAC(this); RGBEditor_SetRGB(this->rgb[0], this->curr[0], &(this->pal[this->curr[0]])); RGBEditor_Update(this->rgb[0]); RGBEditor_SetRGB(this->rgb[1], this->curr[1], &(this->pal[this->curr[1]])); RGBEditor_Update(this->rgb[1]); break; } case 'N': /* convert to negative color */ case 'n': { switch ( this->exclude ) { case 0: /* normal mode. convert all colors to grey scale */ PalTable__SaveUndoData(this, 0, 255); palrangetonegative(this->pal, 0, 256); break; case 1: /* 'x' mode. convert current color to grey scale. */ PalTable__SaveUndoData(this, this->curr[this->active], this->curr[this->active]); palrangetonegative(this->pal, this->curr[this->active], 1); break; case 2: /* 'y' mode. convert range between editors to grey. */ { int a = this->curr[0], b = this->curr[1]; if (a > b) { int t = a; a = b; b = t; } PalTable__SaveUndoData(this, a, b); palrangetonegative(this->pal, a, 1+(b-a)); break; } } PalTable__UpdateDAC(this); RGBEditor_SetRGB(this->rgb[0], this->curr[0], &(this->pal[this->curr[0]])); RGBEditor_Update(this->rgb[0]); RGBEditor_SetRGB(this->rgb[1], this->curr[1], &(this->pal[this->curr[1]])); RGBEditor_Update(this->rgb[1]); break; } case 'U': /* Undo */ case 'u': PalTable__Undo(this); break; case 'e': /* Redo */ case 'E': PalTable__Redo(this); break; } /* switch */ PalTable__DrawStatus(this, FALSE); } static void PalTable__MkDefaultPalettes(PalTable *this) /* creates default Fkey palettes */ { PALENTRY black, white; PALENTRY temp[256]; int ctr; struct SREGS seg; black.red = black.green = black.blue = 0; white.red = white.green = white.blue = 63; mkpalrange(&black, &white, temp, 256, 1); /* boring! */ segread(&seg); for (ctr=0; ctr<8; ctr++) /* copy temp into all fkey saves */ movedata(seg.ss, (USEGTYPE)(temp), FP_SEG(this->save_pal[ctr]), FP_OFF(this->save_pal[ctr]), 256*3); } static PalTable *PalTable_Construct(void) { PalTable *this = new(PalTable); int csize; int ctr; PALENTRY far *mem_block; void far *temp; temp = farmemalloc(FAR_RESERVE); if ( temp != NULL ) { mem_block = (PALENTRY far *)farmemalloc(256L*3 * 8); if ( mem_block == NULL ) { for (ctr=0; ctr<8; ctr++) this->save_pal[ctr] = NULL; } else { for (ctr=0; ctr<8; ctr++) this->save_pal[ctr] = mem_block + (256*ctr); PalTable__MkDefaultPalettes(this); } farmemfree(temp); } this->rgb[0] = RGBEditor_Construct(0, 0, PalTable__other_key, PalTable__change, this); this->rgb[1] = RGBEditor_Construct(0, 0, PalTable__other_key, PalTable__change, this); this->movebox = MoveBox_Construct(0,0,0, PalTable_PALX+1, PalTable_PALY+1); this->active = 0; this->curr[0] = 1; this->curr[1] = 1; this->auto_select = TRUE; this->exclude = FALSE; this->hidden = FALSE; this->stored_at = NOWHERE; this->file = NULL; this->memory = NULL; this->fs_color.red = 42; this->fs_color.green = 42; this->fs_color.blue = 42; this->freestyle = FALSE; this->bandwidth = 15; this->top = 255; this->bottom = 0 ; this->undo_file = dir_fopen(tempdir,undofile, "w+b"); this->curr_changed = FALSE; this->num_redo = 0; RGBEditor_SetRGB(this->rgb[0], this->curr[0], &this->pal[this->curr[0]]); RGBEditor_SetRGB(this->rgb[1], this->curr[1], &this->pal[this->curr[0]]); PalTable__SetPos(this, 0, 0); csize = ( (sydots-(PalTable_PALY+1+1)) / 2 ) / 16; if (csizehidden = hidden; RGBEditor_SetHidden(this->rgb[0], hidden); RGBEditor_SetHidden(this->rgb[1], hidden); PalTable__UpdateDAC(this); } static void PalTable_Hide(PalTable *this, RGBEditor *rgb, BOOLEAN hidden) { if (hidden) { PalTable__RestoreRect(this); PalTable_SetHidden(this, TRUE); reserve_colors = FALSE; if (this->auto_select) PalTable__SetCurr(this, this->active, PalTable__GetCursorColor(this)); } else { PalTable_SetHidden(this, FALSE); reserve_colors = TRUE; if (this->stored_at == NOWHERE) /* do we need to save screen? */ PalTable__SaveRect(this); PalTable__Draw(this); if (this->auto_select) PalTable__SetCurr(this, this->active, PalTable__GetCursorColor(this)); RGBEditor_SetDone(rgb, TRUE); } } static void PalTable_Destroy(PalTable *this) { if (this->file != NULL) { fclose(this->file); dir_remove(tempdir,scrnfile); } if (this->undo_file != NULL) { fclose(this->undo_file); dir_remove(tempdir,undofile); } if (this->memory != NULL) farmemfree(this->memory); if (this->save_pal[0] != NULL) farmemfree((BYTE far *)this->save_pal[0]); RGBEditor_Destroy(this->rgb[0]); RGBEditor_Destroy(this->rgb[1]); MoveBox_Destroy(this->movebox); delete(this); } static void PalTable_Process(PalTable *this) { int ctr,i; getpalrange(0, colors, this->pal); /* Make sure all palette entries are 0-63 */ for(ctr=0; ctr<768; ctr++) ((char *)this->pal)[ctr] &= 63; PalTable__UpdateDAC(this); RGBEditor_SetRGB(this->rgb[0], this->curr[0], &this->pal[this->curr[0]]); RGBEditor_SetRGB(this->rgb[1], this->curr[1], &this->pal[this->curr[0]]); if (!this->hidden) { MoveBox_SetPos(this->movebox, this->x, this->y); MoveBox_SetCSize(this->movebox, this->csize); if ( !MoveBox_Process(this->movebox) ) { setpalrange(0, colors, this->pal); return ; } PalTable__SetPos(this, MoveBox_X(this->movebox), MoveBox_Y(this->movebox)); PalTable__SetCSize(this, MoveBox_CSize(this->movebox)); if ( MoveBox_ShouldHide(this->movebox) ) { PalTable_SetHidden(this, TRUE); reserve_colors = FALSE; /* */ } else { reserve_colors = TRUE; /* */ PalTable__SaveRect(this); PalTable__Draw(this); } } PalTable__SetCurr(this, this->active, PalTable__GetCursorColor(this)); PalTable__SetCurr(this, (this->active==1)?0:1, PalTable__GetCursorColor(this)); Cursor_Show(); /* Store original palette in slots (AMC) */ for(i=0;i<8;i++) { if ( this->save_pal[i] != NULL ) { struct SREGS seg; segread(&seg); movedata(seg.ds, (USEGTYPE)(this->pal), FP_SEG(this->save_pal[i]), FP_OFF(this->save_pal[i]), 256*3); } else buzzer(3); /* Short on memory! */ } /* End of AMC's new section */ this->done = FALSE; while ( !this->done ) RGBEditor_Edit(this->rgb[this->active]); Cursor_Hide(); PalTable__RestoreRect(this); setpalrange(0, colors, this->pal); } /* * interface to FRACTINT */ void EditPalette(void) /* called by fractint */ { int oldlookatmouse = lookatmouse; int oldsxoffs = sxoffs; int oldsyoffs = syoffs; PalTable *pt; mem_init(strlocn, 10*1024); if ( (font8x8 = findfont(0)) == NULL ) return ; plot = putcolor; line_buff = newx(max(sxdots,sydots)); lookatmouse = 3; sxoffs = syoffs = 0; reserve_colors = TRUE; inverse = FALSE; fg_color = (BYTE)(255%colors); bg_color = (BYTE)(fg_color-1); Cursor_Construct(); pt = PalTable_Construct(); PalTable_Process(pt); PalTable_Destroy(pt); Cursor_Destroy(); lookatmouse = oldlookatmouse; sxoffs = oldsxoffs; syoffs = oldsyoffs; delete(line_buff); }