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);
}