crunch@well.UUCP (John Draper) (12/03/86)
/***************************** Imagfunc.c ************************************ * * Image editor functions for the Gadget Editor. * * This module by * Ray R. Larson This version: Sept. 28, 1986 * * This module contains the source for the routines that support the * the main routine Image_Ed. ****************************************************************************/ extern char kprintstr[200]; /* work string for debugging output */ /* because kprintf doesn't work for me */ /* The usual header files */ #include <intuition/intuition.h> #include <libraries/dosextens.h> #include <graphics/gfxbase.h> #include <graphics/gfx.h> #include <graphics/display.h> #include <exec/memory.h> #include <workbench/workbench.h> #include <workbench/startup.h> #include <devices/narrator.h> #include <devices/audio.h> #include <libraries/translator.h> /*------------ Graphics Macros ------------------*/ #include <graphics/gfxmacros.h> /*------------ External function declarations ------------*/ extern struct ViewPort *ViewPortAddress(); extern struct Window *OpenWindow(); extern struct IntuiMessage *GetMsg(); extern void *AllocRaster(); extern struct ColorMap *GetColorMap(); extern struct Preferences *GetPrefs(); extern APTR AllocRemember(); extern struct Remember *rememberBase; extern struct TmpRas *InitTmpRas(); /*------------------- global variables -------------------*/ extern struct GfxBase *GfxBase; extern struct IntuitionBase *IntuitionBase; /*------------------- work rasters and bitmaps -----------*/ extern struct RastPort smallraster; /* these are in imagdcl.c */ extern struct BitMap smallbitmap; struct TmpRas smalltmpras; BYTE *tmprasbuf; /*------------------- macro definitions ------------------*/ #define inrange(n,nl,nh) ((n >= nl) && (n <= nh) ?1:0) #define inbox(x,y,xt,yt,xb,yb) ((inrange(x,xt,xb) && inrange(y,yt,yb)) ?1:0) #define MIN(a,b) ((a < b) ? a:b) #define MAX(a,b) ((a > b) ? a:b) #define ABS(a) ((a > 0) ? a:(a * -1)) /*------------------- color table definitions ------------------*/ extern UWORD defaultCT[32], CTable[32]; extern struct ColorMap *cmap; /************************************************************************** * Definitions and declarations for all them gadgets ***************************************************************************/ /* image editor window dimensions */ #define WINDWIDTH 640 #define WINDHEIGHT 200 /* size of the image editing area */ #define FRAMETOP 11 #define FRAMELEFT 3 #define FRAMEBOT 173 #define FRAMERIGHT 401 #define FRAMEHEIGHT FRAMEBOT-FRAMETOP #define FRAMEWIDTH FRAMERIGHT-FRAMELEFT #define PALETTEG 1 #define MAGMINUSG 2 #define MAGPLUSG 3 #define UPDOWNG 4 #define LEFTRIGHTG 5 #define BIGEDG 6 #define RESETG 7 /* no longer used put in menu */ #define BLUECTLG 8 #define GREENCTLG 9 #define REDCTLG 10 /* menu items - menu declarations are in imagmen.c */ #define PROJMEN 0 #define EDITMEN 1 #define OPTMEN 2 #define RETURNM 0 #define CANCELM 1 #define CLREDWIN 0 #define CLREDALL 1 #define RESETIMAG 2 #define RESETCOLOR 3 #define SHOWSMALL 0 #define HIDESMALL 1 extern struct Gadget UpDownGadg, L_R_Gadg, paletteGadg; extern struct PropInfo UpDownProp, L_R_Prop; /* The following routine allocates work bitmaps and raster ports for */ /* the image editor */ initrasters(width,height,depth) LONG width, height, depth; { SHORT i; InitRastPort(&smallraster); InitBitMap(&smallbitmap,depth,width,height); for (i=0 ; i < depth; i++) smallbitmap.Planes[i] = (PLANEPTR)AllocRaster(width+24L,height+24L); for (i=0 ; i < depth; i++) if(smallbitmap.Planes[i] == NULL) return(FALSE); tmprasbuf = AllocRaster(width+24L,height+24L); if (tmprasbuf == NULL) return(FALSE); smallraster.TmpRas = InitTmpRas(&smalltmpras,tmprasbuf,RASSIZE(width+24L,height+24L)); smallraster.BitMap = &smallbitmap; return(TRUE); } /* To erase the temporary rasters... */ FreeEdRas (width,height,depth) LONG width, height, depth; { SHORT i; for (i = 0 ; i < depth; i++) FreeRaster(smallbitmap.Planes[i], width+24L,height+24L); FreeRaster(tmprasbuf,width+24L,height+24L); } /* output 'pixels' to the image editing area on the editor screen */ bigpixel(rp,mousex,mousey,magnif, max_x, max_y) struct RastPort *rp; short mousex, mousey, magnif, max_x, max_y; { LONG x,y,tx,ty,bx,by, magval; magval = (1L << magnif); /* clip it */ if(inbox(mousex,mousey,FRAMELEFT,FRAMETOP, MIN(max_x,FRAMERIGHT-1), MIN(max_y,FRAMEBOT-1)) == 0) return; if (magnif) { x = ((LONG)(mousex - FRAMELEFT)) / magval; y = ((LONG)(mousey - FRAMETOP)) / magval; tx = (x * magval) + FRAMELEFT; ty = (y * magval) + FRAMETOP; bx = tx + (magval-1) ; by = ty + (magval-1) ; bx = MIN(bx,MIN(max_x+magval,FRAMERIGHT)); by = MIN(by,MIN(max_y+magval,FRAMEBOT)); RectFill(rp,tx,ty,bx,by); } else WritePixel(rp,(LONG)mousex,(LONG)mousey); } /* The following routine writes pixels in the 'real-size' raster */ /* for the image that is off-screen. */ smallpixel(rp,mousex,mousey,magnif,max_x,max_y,offset_x,offset_y) struct RastPort *rp; short mousex, mousey, magnif,max_x, max_y, offset_x, offset_y; { LONG x,y,magval; magval = (1L << magnif); x = ((LONG)(mousex - FRAMELEFT)) / magval; y = ((LONG)(mousey - FRAMETOP)) / magval; if(inbox(x,y,0,0,max_x,max_y) == 0) return; else WritePixel(rp,x+(LONG)offset_x, y+(LONG)offset_y); } /* The following routine renders lines draw with the line tool into the */ /* small image */ smalline(rp,basex,basey,mousex,mousey,magnif,max_x,max_y,offset_x,offset_y,pen) struct RastPort *rp; SHORT basex,basey,mousex, mousey, magnif,max_x, max_y, offset_x, offset_y; LONG pen; { SHORT x1,y1, x2, y2, magval; magval = 1 << magnif; x1 = ((basex - FRAMELEFT) / magval)+offset_x; y1 = ((basey - FRAMETOP) / magval)+offset_y; x2 = ((mousex - FRAMELEFT) / magval)+offset_x; y2 = ((mousey - FRAMETOP) / magval)+offset_y; if(inbox(x2,y2,0,0,max_x,max_y) == 0) return; im_draw_line(rp,x1,y1,x2,y2,pen,0); } /* The following routine renders boxes draw with the box tool into the */ /* small image */ smallbox(rp,basex,basey,width,height,magnif,max_x,max_y,offset_x,offset_y,pen) struct RastPort *rp; SHORT basex,basey,width,height, magnif,max_x, max_y, offset_x, offset_y; LONG pen; { SHORT x,y, w, h, magval; magval = 1 << magnif; x = ((basex - FRAMELEFT) / magval)+offset_x; y = ((basey - FRAMETOP) / magval)+offset_y; w = width / magval; h = height / magval; if(inbox(x+w,y+h,0,0,max_x,max_y) == 0) return; im_draw_box(rp,x,y,w,h,pen,0); } /* The following routine renders filled boxes drawn with the filledbox */ /* tool into the small raster image */ smallrect(rp,x1,y1,x2,y2,magnif,max_x,max_y,offset_x,offset_y,pen) struct RastPort *rp; SHORT x1,y1,x2,y2,magnif,max_x, max_y, offset_x, offset_y; LONG pen; { SHORT x,y,topx,topy,botx,boty, magval; topx = MIN(x1,x2); topy = MIN(y1,y2); botx = MAX(x1,x2); boty = MAX(y1,y2); magval = 1 << magnif; topx = ((topx - FRAMELEFT) / magval)+offset_x; topy = ((topy - FRAMETOP) / magval)+offset_y; botx = ((botx - FRAMELEFT) / magval)+offset_x; boty = ((boty - FRAMETOP) / magval)+offset_y; if(inbox(topx,topy,0,0,max_x,max_y) == 0) return; if(inbox(botx,boty,0,0,max_x,max_y) == 0) return; RectFill(rp,(LONG)topx,(LONG)topy,(LONG)botx,(LONG)boty); } /* The following routine renders circles draw with the circle tool into the */ /* small image */ smallcirc(rp,centerx,centery,radius,aspect,magnif,max_x,max_y,offset_x,offset_y, pen) struct RastPort *rp; SHORT centerx,centery,radius,aspect, magnif,max_x, max_y, offset_x, offset_ y; LONG pen; { SHORT x, y, r, a, magval; magval = 1 << magnif; x = ((centerx - FRAMELEFT) / magval)+offset_x; y = ((centery - FRAMETOP) / magval)+offset_y; r = radius / magval; a = aspect / magval; if((inrange(x+r,0,max_x) == 0)|| (inrange(x-r,0,max_x) == 0)|| (inrange(y+a,0,max_y) == 0)|| (inrange(y-a,0,max_y) == 0)) return; im_draw_circ(rp,x,y,r,a,pen,0); } /* The following routine flood fills areas in the small raster with the */ /* given pen color */ smallfill(rp,mousex,mousey,magnif,offset_x,offset_y) struct RastPort *rp; SHORT mousex,mousey,magnif, offset_x, offset_y; { SHORT magval; LONG x, y; magval = 1 << magnif; x = (LONG)((mousex - FRAMELEFT) / magval)+offset_x; y = (LONG)((mousey - FRAMETOP) / magval)+offset_y; SetDrMd(&smallraster,JAM2); Flood(&smallraster,1L,x,y); } /* The following routine redraws the image in the editing window */ /* from the off-screen raster. It is used whenever the magnification */ /* is changed or when the editing area is moved. */ redrawim (src_rp, dest_rp, src_x, src_y, maxsrc_x, maxsrc_y, dest_width, dest_height, magnif,clear) struct RastPort *src_rp, *dest_rp; SHORT src_x,src_y,maxsrc_x,maxsrc_y,dest_width,dest_height,magnif; SHORT clear; { register LONG pen; register SHORT x, y, pixoutx, pixouty, magval; SHORT out_width, out_height, mousex, mousey, src_width, src_height; SHORT n_pixwide, n_pixhigh; SHORT tx,ty,bx,by; /* clear the image drawing area */ if (clear) {SetAPen(dest_rp,0L); RectFill(dest_rp,((LONG)FRAMELEFT),((LONG)FRAMETOP), ((LONG)FRAMERIGHT),((LONG)FRAMEBOT)); } /* set the output frame width and height*/ src_width = (maxsrc_x - src_x)+1; src_height = (maxsrc_y - src_y)+1; if (src_width > dest_width) out_width = dest_width; else out_width = src_width; if (src_height > dest_height) out_height = dest_height; else out_height = src_height; magval = 1<<magnif; if (magnif) /* when the image is magnified redraw as in bigpixel */ { n_pixwide = dest_width/magval; n_pixhigh = dest_height/magval; pixouty = 0; for( y = src_y; y <= maxsrc_y && pixouty <= n_pixhigh; y++, pixout y++) { pixoutx = 0; for( x = src_x; x <= maxsrc_x && pixoutx <= n_pixwide; x++, pixo utx++) { /* first, get the color for the pixel from the */ /* source (small) raster and use it to set the */ /* pen color for the editing pen */ /* (the pen will be left in the last color) */ pen = ReadPixel(src_rp,(LONG)x,(LONG)y); if(pen != 0) { SetAPen(dest_rp,pen); /* write it into the editing frame at the right */ /* magnification, making each pixel in the small*/ /* image into a rectangle in the editor area */ tx = ((x-src_x) * magval) + FRAMELEFT; ty = ((y-src_y) * magval) + FRAMETOP; bx = tx + (magval-1) ; by = ty + (magval-1) ; if( inbox(tx,ty,FRAMELEFT,FRAMETOP, FRAMERIGHT-2,FRAMEBOT-2) == 0) continue; bx = MIN(bx,FRAMERIGHT-1); by = MIN(by,FRAMEBOT-1); RectFill(dest_rp,(LONG)tx,(LONG)ty,(LONG)bx,(LONG)by); } } } } else /* no magnification so simply blit the image over */ { if (out_width == 0) out_width = 1; if (out_height == 0) out_height = 1; ClipBlit (src_rp,(LONG)src_x,(LONG)src_y, dest_rp,(LONG)FRAMELEFT,(LONG)FRAMETOP, (LONG)out_width, (LONG)out_height, (LONG)0xc0 /* copy all planes */); } } /* this routine sets the variables used for clipping the editor image */ setclip(rp,max_right,max_bot,magnif,imagewidth,imageheight) struct RastPort *rp; SHORT *max_right, *max_bot, magnif, imagewidth, imageheight; { SHORT mag_width, mag_height; BOOL drawright, drawbot; drawright = drawbot = FALSE; mag_width = imagewidth << magnif; mag_height = imageheight << magnif; if (mag_width >= (FRAMEWIDTH)) *max_right = FRAMERIGHT; else { *max_right = mag_width + FRAMELEFT -1; drawright = TRUE; } if (mag_height >= (FRAMEHEIGHT)) *max_bot = FRAMEBOT; else { *max_bot = mag_height + FRAMETOP -1; drawbot = TRUE; } if(drawright)/* put a complement 'frame' on the right side */ { SetDrMd(rp,COMPLEMENT | JAM1); Move(rp,(LONG)*max_right+1,(LONG)FRAMETOP); Draw(rp,(LONG)*max_right+1,(LONG)MIN(*max_bot+1,FRAMEBOT)); } if(drawbot) /* put a complement 'frame' at the bottom */ { SetDrMd(rp,COMPLEMENT | JAM1); Move(rp,(LONG)FRAMELEFT,(LONG)*max_bot+1); Draw(rp,(LONG)MIN(*max_right+1,FRAMERIGHT),(LONG)*max_bot+1); } SetDrMd(rp,JAM1); } /* The following routine sets the image movement proportional gadget sizes */ setprops(w,magnif,imagewidth,imageheight) struct Window *w; SHORT magnif, imagewidth, imageheight; { SHORT mag_width, mag_height; USHORT vdiv, vertbod, hdiv, horizbod; mag_width = imagewidth << magnif; mag_height = imageheight << magnif; vdiv = (mag_height / (FRAMEHEIGHT))+ 1;/* round up to next highest*/ hdiv = (mag_width / (FRAMEWIDTH))+ 1; vertbod = 0xFFFF / vdiv ; horizbod = 0xFFFF / hdiv; if(vertbod == 0xFFFF) vertbod -= 0x1000; if(horizbod == 0xFFFF) horizbod -= 0x1000; UpDownProp.VertBody = vertbod; /* calc from height */ L_R_Prop.HorizBody = horizbod; /* calc from width */ RefreshGadgets(&L_R_Gadg,w,NULL); } /* initialize palette - this will set up a pallette for any depth of */ /* screen. */ initpalette(rp,depth) struct RastPort *rp; SHORT depth; { SHORT i, j, c_rows, n_colors, c_per_row; LONG x, y, bx, by, boxw, boxh, pen; n_colors = 1 << depth; if (n_colors > 8) c_rows = 2; else c_rows = 1; c_per_row = n_colors / c_rows; boxw = (LONG)paletteGadg.Width/c_per_row; boxh = (LONG)paletteGadg.Height/c_rows; pen = 0L; for (j = 0; j < c_rows; j++) { for (i=0; i < c_per_row; i++, pen++) { SetAPen(rp,pen); x = ((LONG)i * boxw) + (LONG)paletteGadg.LeftEdge ; y = ((LONG)j * boxh) + (LONG)paletteGadg.TopEdge ; bx = x + boxw -1L; by = y + boxh -1L; RectFill(rp,x,y,bx,by); /* fill in color box */ } } } /* The following routine converts the image from the UBYTE planes of */ /* the small raster bitmap to a USHORT array for the image structure */ struct Image *bitmapTOimage(bitmap,width,height,depth) struct BitMap *bitmap; SHORT width, height, depth; { struct Image *imptr; SHORT n_words, tot_words, i, temp; SHORT n_rows, bytes_per_row, byte, burnbytes, row; USHORT *dest; UBYTE *src; /* allocate a new image structure */ imptr = (struct Image *)AllocRemember( rememberBase,(LONG)sizeof(struct Image), MEMF_CHIP | MEMF_CLEAR); if (imptr == NULL) return(NULL); /* initialize it */ imptr->LeftEdge = 0; imptr->TopEdge = 0; imptr->Width = width; imptr->Height = height; imptr->Depth = depth; imptr->PlanePick = 0xFF; imptr->PlaneOnOff = 0; imptr->NextImage = NULL; /* how many words are needed for the image? */ n_words = width/16; if (n_words % 16 != 0) n_words += 1; tot_words = n_words * (height * depth); /* allocate the word array */ imptr->ImageData = (USHORT *)AllocRemember ( rememberBase,(LONG)(sizeof(USHORT) * tot_words), MEMF_CHIP | MEMF_CLEAR); if(imptr->ImageData == NULL) { kputs("No room for image data - no image returned!"); return(NULL); } /* OK, so we should have the memory for the image, so now */ /* we scan the bitmap and move it to the ImageData area */ if (bitmap->Rows > height) n_rows = height; else n_rows = bitmap->Rows; if (bitmap->BytesPerRow > (n_words * 2)) { bytes_per_row = n_words * 2; burnbytes = bitmap->BytesPerRow - bytes_per_row; } else { bytes_per_row = bitmap->BytesPerRow; burnbytes = 0; } dest = imptr->ImageData; for (i = 0; i < depth; i ++) { src = (UBYTE *)bitmap->Planes[i]; for (row = 0; row < n_rows; row++) { for (byte=0; byte < bytes_per_row; byte+=2) { /* put pairs of bytes into single words */ temp = (USHORT) *src++; temp = temp << 8; temp |= (USHORT)*src++; *dest++ = temp; } /* skip any 'dangling' bytes that aren't part of the */ /* image definition. */ src += burnbytes; } } #ifdef DEBUG kputs("got to the end - returning bitmap pointer"); #endif return(imptr); } /* The following routine frees the memory allocated for an image */ /* Note - this is not called in the gadget editor. RRL */ FreeImage(imptr) struct Image *imptr; { SHORT n_words, tot_words; if (imptr == NULL) return; n_words = imptr->Width/16; if (n_words % 16 != 0) n_words += 1; tot_words = n_words * (imptr->Height * imptr->Depth); FreeMem(imptr->ImageData,(LONG)(sizeof(USHORT) * tot_words)); FreeMem(imptr,(LONG)sizeof(struct Image)); } /*======================================================================== im_draw_box - Draws a box, given Left, Top, Width, Height, and a RastPort -- slightly modified from the draw_box in gt.c for the image editor -rrl ========================================================================*/ im_draw_box(rport, left, top, width, height, pen, tempbox) struct RastPort *rport; SHORT left, top, width, height; BOOL tempbox; LONG pen; { long lf = (long)left; long tp = (long)top; long wd = (long)width; long hg = (long)height; if(tempbox) { SetDrMd(rport, COMPLEMENT); SetAPen(rport, 1L); SetBPen(rport, 0L); } else { SetDrMd(rport, JAM1); SetAPen(rport, pen); } Move(rport, lf, tp); Draw(rport, lf+wd, tp); Draw(rport, lf+wd, tp+hg); Draw(rport, lf, tp+hg); Draw(rport, lf, tp); } /*======================================================================== im_draw_line - Draws a line, given a pair of xy coords and a RastPort ========================================================================*/ im_draw_line(rport, x1, y1, x2, y2, pen, templine) struct RastPort *rport; SHORT x1, y1, x2, y2; LONG pen; BOOL templine; { if(templine) { SetDrMd(rport, COMPLEMENT); SetAPen(rport, 1L); SetBPen(rport, 0L); } else { SetDrMd(rport, JAM1); SetAPen(rport, pen); } Move(rport, (LONG)x1,(LONG)y1); Draw(rport, (LONG)x2, (LONG)y2); } /*======================================================================== im_draw_circ - Draws a circle, given a center xy coord the radius and a RastPort. -- based on Bresenham's algorithm, and redone from pascal to c using the version in the Turbo Pascal Graphics Library. Thanks Borland. ========================================================================*/ /* some constants for the circle algorithm */ SHORT circ[14]= {0,121,239,355,465,568,663,749,823,885,935,971,993,1000}; im_draw_circ(rp, x_c, y_c, radius, aspect, pen, templine) struct RastPort *rp; SHORT x_c, y_c, radius, aspect; LONG pen; BOOL templine; { SHORT i,xk1,xk2,yk1,yk2; register SHORT xp1,yp1,xp2,yp2, x_center, y_center; register FLOAT xfact, yfact; FLOAT aspectfactor=0.45, aspectfl; if(radius == 0) return; x_center = x_c; y_center = y_c; if(templine) { SetDrMd(rp, COMPLEMENT); SetAPen(rp, 1L); SetBPen(rp, 0L); } else { SetDrMd(rp, JAM1); SetAPen(rp, pen); } aspectfl = ((FLOAT)aspect*2.1) / (FLOAT)radius; aspectfl = ABS(aspectfl) * aspectfactor; xfact = ABS(0.001 * (FLOAT)radius); yfact = xfact * aspectfl; if (xfact > 0.0) { xk1 = (SHORT)(circ[0] * xfact+0.5); yk1 = (SHORT)(circ[13] * yfact+0.5); for(i=1; i<14; i++) { xk2 = (SHORT)(circ[i]*xfact+0.5); yk2 = (SHORT)(circ[13 - i+1]*yfact+0.5); xp1 = x_center-xk1; yp1 = y_center+yk1; xp2 = x_center-xk2; yp2 = y_center+yk2; Move(rp, (LONG)xp1,(LONG)yp1); Draw(rp, (LONG)xp2, (LONG)yp2); xp1 = x_center+xk1; xp2 = x_center+xk2; Move(rp, (LONG)xp1,(LONG)yp1); Draw(rp, (LONG)xp2, (LONG)yp2); yp1 = y_center-yk1; yp2 = y_center-yk2; Move(rp, (LONG)xp1,(LONG)yp1+1); Draw(rp, (LONG)xp2, (LONG)yp2+1); xp1 = x_center-xk1; xp2 = x_center-xk2; Move(rp, (LONG)xp1,(LONG)yp1+1); Draw(rp, (LONG)xp2, (LONG)yp2+1); xk1 = xk2; yk1 = yk2; } } else WritePixel(rp,x_center,y_center); }