/* this is an example of an asynchronous tool.
   use it as a template for your tools that require interactive
   participation by the user.

   suggested uses:
   real time data base manipulators, like this scale

   NOTE that this source code handles splines and flares
   also note that this source code shows how to honor point mode if
   it is active

   NOTE that the radial option has been disabled in this example file
*/

/* some general includes. We tried to get all you would normally need
   change to fit your tool if needed.
*/
#include "exec/types.h"

/* these two statements allow more efficient allocmems, see
   SC readme for 6.0
   DON'T call pragmas/exec_pragmas.h
*/

#define __USE_SYSBASE
#include <proto/exec.h>

#include "stdio.h"
#include "string.h"
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/libraries.h>
#include <intuition/intuition.h>
#include <graphics/text.h>
#include <proto/graphics.h>
#include <proto/intuition.h>
#include "exec/io.h"
#include "exec/memory.h"
#include "dos.h"
#include "libraries/dosextens.h"
#include "libraries/dos.h"
#include "libraries/filehandler.h"
#include "devices/inputevent.h"
#include "graphics/gfxmacros.h"

#include <graphics/gfx.h>
#include <hardware/blit.h>
#include <graphics/copper.h>
#include <graphics/view.h>
#include <graphics/rastport.h>
#include <graphics/gels.h>
#include <graphics/regions.h>
#include <graphics/clip.h>
#include <exec/exec.h>
#include <graphics/gfxbase.h>
#include <m68881.h>

#include "math.h"
#include "float.h"
#include "limits.h"
#include "proto/dos.h"
#include "stdlib.h"
#include "workbench/workbench.h"
#include "workbench/startup.h"
#include "proto/icon.h"
#include "time.h"

/* for our run time libraries */
#include "alad_pragmas.h"
#include "alad_protos.h"

#include "defines.h"
#include "externs.h"

static void getdefaults(int);

int CXBRK(void) { return(0); }  /* Disable Lattice CTRL/C handling */
void chkabort __ARGS((void)) { return; }  /* really */
void Chk_Abort __ARGS((void)) { return; } /* really */

void scalelines(void);
void doendscalelines(double,double,double);
void doscalelines(double,double,double);
void doendscalelinespmode(double,double,double);
void doscalelinespmode(double,double,double);

/* library pointers */
struct Library *AladBase;
struct IntuitionBase *IntuitionBase;

/* our semaphore pointer */
struct SignalSemaphore *polysema;

/* pointer to current attach point */
LONG *atpoint;

/* some variables user can control from user window */
double scalex=1.0,scaley=1.0,scalez=1.0;
int radial,scalefrom,deforms;

/* variables to set bounding rectangles for selected polys */
/* filled out in sethighlow() */
int low[3],high[3],center[3];

int getscdef(void);
static void sethighlow(void);
int main(int,char **);

int main(argc,argv)
int argc;
char **argv;
{
 int t;

 /* open libraries we need */
 IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",33);
 if(IntuitionBase == NULL) return(-1);
 AladBase = OpenLibrary("Aladdin4D:support/alad.library",0);
 if(AladBase == NULL) {
  CloseLibrary((struct Library *)IntuitionBase);
  return(-1);
 }
 /* retrieve last values in use */
 getdefaults(0);
 /* Part of what Aladdin has stored in the hardware key
    is the user request
    use readHSLdevice() to get it
    if it returns a 1, user clicked the tool with a LMB
    if it returns a 2, user clicked the tool with a RMB
 */
 t = readHSLdevice();
 if(t == 1) { /* LMB */
  /* if user used a left mouse button, just do the work */
  /* this is interactive mode */
  scalelines();
 } else if(t == 2) { /* RMB */
  /* if user used a right mouse button, open the defaults window
     and if he hits the perform gadget, do the work based on
     the values in the gadgets
     note that it is not possible to go into interactive mode
     here since all tools called with a RMB are entered
     in a synchronous mode
  */
  if(getscdef()) {
   /* since called synchronously, ok to modify without the semaphore
      but sethighlow does, so get it
   */
   Forbid();
   polysema = FindSemaphore("Aladdin4DSemaphore");
   Permit();
   if(polysema) { /* only if we found the semaphore */
    /* atpoint points either to our calculated center, or the
       current attach point in the library
    */
    atpoint = scalefrom ? getatpoint() : center;
    if(radial || (!scalefrom)) sethighlow();
    /* if multiplepoint() returns true, we are in point mode */
    if(multiplepoint()) doendscalelinespmode(scalex,scaley,scalez);
    else                doendscalelines(scalex,scaley,scalez);
   } else {
    letemknow("Can't find semaphore");
   }
  }
  /* save the new defaults for next time tool used */
  getdefaults(1);
 }
 /* with ALL asynchronous tools, ALWAYS call these two functions */
 settoolfinished(1);
 wakealaddin();
 /* finally clean up */
 CloseLibrary((struct Library *)IntuitionBase);
 CloseLibrary(AladBase);
 return(0); /* always return 0 when finished */
}

static void getdefaults(int sav)
{
 /* establish a defaults file
    if program run before, get them
    if first time, file won't exist, so return
 */
 LONG file;
 double version;
 char *fn = "aladdin4ddef:{ALAD}_scale.def";

 if(sav) {
  file=Open(fn,MODE_NEWFILE);
  if(file==0) { return; }
  version = 3.0; /* change the number for future tool versions */
  Write(file,(BYTE *)&version,sizeof(version));
  Write(file,(BYTE *)&scalex,sizeof(scalex));
  Write(file,(BYTE *)&scaley,sizeof(scaley));
  Write(file,(BYTE *)&scalez,sizeof(scalez));
  Write(file,(BYTE *)&radial,sizeof(radial));
  Write(file,(BYTE *)&scalefrom,sizeof(scalefrom));
  Write(file,(BYTE *)&deforms,sizeof(deforms));
 } else {
  file=Open(fn,MODE_OLDFILE);
  if(file==0) { return; }
  Read(file,(BYTE *)&version,sizeof(version));
  if(version == 3.0) { /* only if version is recognized */
   Read(file,(BYTE *)&scalex,sizeof(scalex));
   Read(file,(BYTE *)&scaley,sizeof(scaley));
   Read(file,(BYTE *)&scalez,sizeof(scalez));
   Read(file,(BYTE *)&radial,sizeof(radial));
   Read(file,(BYTE *)&scalefrom,sizeof(scalefrom));
   Read(file,(BYTE *)&deforms,sizeof(deforms));
  }
 }
 Close(file);
}

/* these are the performance functions that you will replace with
   your own functions.

scalelines() :
   handles the interface with the library,
   measures mouse movement
   prompts user
   calls actual manipulation functions if necessary

doscalelinespmode or doscalelines :
   manipulate the polys for real time

doendscalelinespmode or doendscalelines :
   do final manipulation of the polys, takes care of bounding boxes for
   textures, etc. that doscalelines doesn't do

*/


void scalelines()
{
 int xscale,yscale,zscale;
 int moux,mouy;
 int dmx,dmy;
 SHORT mouse[2];
 int notdone;
 ULONG com;
 char buf[80];

 #define USERUNDO (com&POLY_UNDOCOM)
 #define STOPLOOPING com&(POLY_SETCOM|POLY_UNDOCOM)

 /* get the semaphore for set up */
 Forbid();
 polysema = FindSemaphore("Aladdin4DSemaphore");
 Permit();
 if(polysema == NULL) return; /* if no key, just get out */
 /* clearusersetcom to remove any old set command */
 clearusersetcom();
 /* undocom clears any old undo command */
 undocom();
 /* atpoint points either to our calculated center, or the
    current attach point in the library
 */
 atpoint = scalefrom ? getatpoint() : center;
 /* initialize some variables */
 dmx = dmy = 100;
 xscale = yscale = zscale = 100;
 /* getlastmousexy for entry */
 getlastmousexy(mouse);
 moux=mouse[0]; mouy = mouse[1]; /* save mouse x,y at entry */
 notdone = 1;
 if(radial || (!scalefrom)) sethighlow();
 while(notdone) { /* continue looping until told to stop */
  com = getusercommands(); /* get current user input from library */
  if(STOPLOOPING) { /* undo or set */
   notdone = 0;     /* so we stop looping and exit */
  } else {          /* still running */
   /* get the semaphore */
   /* at this point, if the semaphore is not available, we are sleeping */
   ObtainSemaphore(polysema); /* waits for aladdin to OK our run */
   getlastmousexy(mouse); /* get current mouse position */
   if((moux != mouse[0]) || (mouy != mouse[1])) {
    if(mousechange()) { /* not here unless LB */
     moux = mouse[0];  mouy = mouse[1];
    } else {
     dmx += moux - mouse[0];
     dmy += mouy - mouse[1];
     moux = mouse[0]; mouy = mouse[1];
     if(com&POLY_SHIFTCOM) { /* if user is holding down the shift key */
      xscale = yscale = zscale = (dmx + dmy)>>1;
     } else {
      switch(edaxis()) { /* the active axis gadget selected */
       case 0:                 /* drawing in y-z plane, z is mouse y */
         yscale = (com&POLY_ALTCOM) ? (dmx + dmy)>>1 : dmx;
         zscale = (com&POLY_ALTCOM) ? yscale : dmy;
         xscale = 100;  break;
       case 1:                 /* drawing in x-z plane, z is mouse y */
         xscale = (com&POLY_ALTCOM) ? (dmx + dmy)>>1 : dmx;
         zscale = (com&POLY_ALTCOM) ? xscale : dmy;
         yscale = 100;  break;
       case 2:                 /* drawing in x-y plane, y is mouse y */
         xscale = (com&POLY_ALTCOM) ? (dmx + dmy)>>1 : dmx;
         yscale = (com&POLY_ALTCOM) ? xscale : dmy;
         zscale = 100;  break;
      }
     }
     if(!USERUNDO) { /* don't call undocom here, or will unset it */
      /* multiplepoint returns true if in point mode */
      if(multiplepoint()) doscalelinespmode((double)(xscale/100.0),(double)(yscale/100.0),(double)(zscale/100.0));
      else                doscalelines((double)(xscale/100.0),(double)(yscale/100.0),(double)(zscale/100.0));
     }
    }
   }
   /* were going to let the user know using promptem what the current
      values are, so sprintf them along with message to buf, then
      call promptem with buf
   */
   sprintf(buf,"scale x y z: %f %f %f",xscale/100.0,yscale/100.0,zscale/100.0);
   promptem(buf); /* NEVER promptem unless have semaphore */
                  /* promptem is only semi-legal, Aladdin must be asleep */
   ReleaseSemaphore(polysema);
  }
 }
 /* only way we broke out of loop is if user gave set or undo command */
 if(!(undocom())) { /* always ask before last operation, clears the undo if set */
  if((xscale != 100)||(yscale != 100)||(zscale != 100)) {
   ObtainSemaphore(polysema); /* wait on Aladdin to OK our run */
   if(multiplepoint()) doendscalelinespmode((double)(xscale/100.0),(double)(yscale/100.0),(double)(zscale/100.0));
   else                doendscalelines((double)(xscale/100.0),(double)(yscale/100.0),(double)(zscale/100.0));
   ReleaseSemaphore(polysema);
  }
 }
}

void doscalelines(scax,scay,scaz)
double scax,scay,scaz;
{
 struct procobject *ob;
 struct splineobject *spo;
 struct flareobject *fla;
 struct PolygonInfo *top;
 struct PointInfo *pnt;
 double sx,sy,sz;

 if(radial) {
  ; /* removed */
 }
 sx = scax - 1.0; sy = scay - 1.0; sz = scaz - 1.0;
 /* firstpoly is the first poly of the current space */
 for(top = firstpoly(); top; top = top->next) { /* look at all polys */
  if(ISSELECTED(top)) { /* if it is selected */
   for(pnt = top->firstpoint; pnt; pnt = pnt->next) { /* look at all points in this poly */
    if(radial) {
     ; /* removed */
    } else {    /* manipulate the points */
     pnt->x = pnt->oldx + (sx*(pnt->oldx - atpoint[0]));
     pnt->y = pnt->oldy + (sy*(pnt->oldy - atpoint[1]));
     pnt->z = pnt->oldz + (sz*(pnt->oldz - atpoint[2]));
    }
   }
  }
 }
 /* firstprocobject is the first procedural object in the space */
 for(ob = firstprocobject(); ob; ob = ob->next) { /* look at all proc objects */
  if(ISSELECTED(ob)) { /* if it is selected */
   if(ob->in == PROB_ISSPLINE) { /* spline object */
    spo = (struct splineobject *)ob->special; /* the spline object structure */
    for(pnt = spo->firstpoint; pnt; pnt = pnt->next) { /* the main points */
     if(radial) {
      ; /* removed */
     } else {
      pnt->x = pnt->oldx + (sx*(pnt->oldx - atpoint[0]));
      pnt->y = pnt->oldy + (sy*(pnt->oldy - atpoint[1]));
      pnt->z = pnt->oldz + (sz*(pnt->oldz - atpoint[2]));
     }
    }
    for(pnt = spo->controlpnt; pnt; pnt = pnt->next) { /* the control points */
     if(radial) {
      ; /* removed */
     } else {
      pnt->x = pnt->oldx + (sx*(pnt->oldx - atpoint[0]));
      pnt->y = pnt->oldy + (sy*(pnt->oldy - atpoint[1]));
      pnt->z = pnt->oldz + (sz*(pnt->oldz - atpoint[2]));
     }
    }
   } else if(ob->in == PROB_ISFLARE) { /* a flare object */
    fla = (struct flareobject *)ob->special; /* the flare structure */
    top = fla->po; /* the flare's polygon */
    for(pnt = top->firstpoint; pnt; pnt = pnt->next) { /* flare poly's points */
     if(radial) {
      ; /* removed */
     } else {
      pnt->x = pnt->oldx + (sx*(pnt->oldx - atpoint[0]));
      pnt->y = pnt->oldy + (sy*(pnt->oldy - atpoint[1]));
      pnt->z = pnt->oldz + (sz*(pnt->oldz - atpoint[2]));
     }
    }
   }
  }
 }
}


/* this is identical to doscalelines, but checks for point permission
   for operation in point mode
*/
void doscalelinespmode(scax,scay,scaz)
double scax,scay,scaz;
{
 struct procobject *ob;
 struct splineobject *spo;
 struct flareobject *fla;
 struct PolygonInfo *top;
 struct PointInfo *pnt;
 double sx,sy,sz;

 if(radial) {
  ; /* removed */
 }
 sx = scax - 1.0; sy = scay - 1.0; sz = scaz - 1.0;
 for(top = firstpoly(); top; top = top->next) { /* look at all polys */
  if(ISSELECTED(top)) { /* if it is selected */
   for(pnt = top->firstpoint; pnt; pnt = pnt->next) { /* look at all points */
    if(ISPNTPERMIT(pnt)) { /* does this point have permission to move? */
     if(radial) {
      ; /* removed */
     } else {
      pnt->x = pnt->oldx + (sx*(pnt->oldx - atpoint[0]));
      pnt->y = pnt->oldy + (sy*(pnt->oldy - atpoint[1]));
      pnt->z = pnt->oldz + (sz*(pnt->oldz - atpoint[2]));
     }
    }
   }
  }
 }
 for(ob = firstprocobject(); ob; ob = ob->next) { /* look at all procobjects */
  if(ISSELECTED(ob)) { /* if it is selected */
   if(ob->in == PROB_ISSPLINE) { /* spline object */
    spo = (struct splineobject *)ob->special; /* the spline structure */
    for(pnt = spo->firstpoint; pnt; pnt = pnt->next) { /* main points */
     if(ISPNTPERMIT(pnt)) { /* does this point have permission to move? */
      if(radial) {
       ; /* removed */
      } else {
       pnt->x = pnt->oldx + (sx*(pnt->oldx - atpoint[0]));
       pnt->y = pnt->oldy + (sy*(pnt->oldy - atpoint[1]));
       pnt->z = pnt->oldz + (sz*(pnt->oldz - atpoint[2]));
      }
     }
    }
    for(pnt = spo->controlpnt; pnt; pnt = pnt->next) { /* control points */
     if(ISPNTPERMIT(pnt)) { /* does this point have permission to move? */
      if(radial) {
       ; /* removed */
      } else {
       pnt->x = pnt->oldx + (sx*(pnt->oldx - atpoint[0]));
       pnt->y = pnt->oldy + (sy*(pnt->oldy - atpoint[1]));
       pnt->z = pnt->oldz + (sz*(pnt->oldz - atpoint[2]));
      }
     }
    }
   } else if(ob->in == PROB_ISFLARE) { /* a flare object */
    fla = (struct flareobject *)ob->special; /* the flare structure */
    top = fla->po; /* the flare polygon */
    for(pnt = top->firstpoint; pnt; pnt = pnt->next) { /* flare polys points */
     if(ISPNTPERMIT(pnt)) { /* does this point have permission to move? */
      if(radial) {
       ; /* removed */
      } else {
       pnt->x = pnt->oldx + (sx*(pnt->oldx - atpoint[0]));
       pnt->y = pnt->oldy + (sy*(pnt->oldy - atpoint[1]));
       pnt->z = pnt->oldz + (sz*(pnt->oldz - atpoint[2]));
      }
     }
    }
   }
  }
 }
}

/* doendscal.... are just like doscal... but
   take care of polys that use bounders, like textured or phong shaded
   polys with more than four points.
   also takes care of deforms if desired
*/

void doendscalelines(scax,scay,scaz)
double scax,scay,scaz;
{
 struct procobject *ob;
 struct splineobject *spo;
 struct flareobject *fla;
 struct PolygonInfo *top,*po;
 struct PointInfo *pnt;
 struct PolyBMpoint *pt;
 struct PathInfo *path;
 SHORT i;
 double sx,sy,sz;
 struct defpnt *dpt;

 if(radial) {
  ; /* removed */
 }
 sx = scax - 1.0; sy = scay - 1.0; sz = scaz - 1.0;
 for(top = firstpoly(); top; top = top->next) { /* look at all polys */
  if(ISSELECTED(top)) { /* if it is selected */
   for(pnt = top->firstpoint; pnt; pnt = pnt->next) { /* look at all points for it */
    if(radial) {
     ; /* removed */
    } else {
     pnt->x = pnt->oldx + (sx*(pnt->oldx - atpoint[0]));
     pnt->y = pnt->oldy + (sy*(pnt->oldy - atpoint[1]));
     pnt->z = pnt->oldz + (sz*(pnt->oldz - atpoint[2]));
    }
   }
   if(deforms) { /* user wants to scale deform levels */
    if(path = top->path) { /* if poly is assigned to a path */
     if(path->deform) { /* and the path has deform level(s) */
      for(pnt = top->firstpoint; pnt; pnt = pnt->next) { /* all points for poly */
       for(dpt = pnt->dpt; dpt; dpt = dpt->next) { /* all deform levels */
        if(radial) {
         ; /* removed */
        } else {
         dpt->x += (sx*(dpt->x - atpoint[0]));
         dpt->y += (sy*(dpt->y - atpoint[1]));
         dpt->z += (sz*(dpt->z - atpoint[2]));
        }
       }
      }
     }
    }
   }
   /* if poly is textured or phong shaded and has more than 4 points
      it uses a bounder which must be altered
   */
   if((top->points > 4)&&(ISBMP(top))) { /* move bounding polys */
    pt = top->bmp.pnt; /* where bounder is held */
    for(i=0;i<4;i++) { /* always four points in bounder */
     if(radial) {
      ; /* removed */
     } else {
      pt->x[i] = pt->oldx[i] + (sx*(pt->oldx[i] - atpoint[0]));
      pt->y[i] = pt->oldy[i] + (sy*(pt->oldy[i] - atpoint[1]));
      pt->z[i] = pt->oldz[i] + (sz*(pt->oldz[i] - atpoint[2]));
     }
    }
   }
   if(ISMELD(top)) { /* only need to move the bounding polys for melds */
    for(po = top->special; po; po = po->next) { /* actual polys represented by meld */
     if((po->points > 4)&&(ISBMP(po))) {
      pt = po->bmp.pnt;
      for(i=0;i<4;i++) {
       if(radial) {
        ; /* removed */
       } else {
        pt->x[i] = pt->oldx[i] + (sx*(pt->oldx[i] - atpoint[0]));
        pt->y[i] = pt->oldy[i] + (sy*(pt->oldy[i] - atpoint[1]));
        pt->z[i] = pt->oldz[i] + (sz*(pt->oldz[i] - atpoint[2]));
       }
      }
     }
    }
   }
  }
 }
 /* now the procedural objects for the space */
 for(ob = firstprocobject(); ob; ob = ob->next) { /* look at all procs */
  if(ISSELECTED(ob)) { /* if it is selected */
   if(ob->in == PROB_ISSPLINE) { /* spline object */
    spo = (struct splineobject *)ob->special; /* the spline structure */
    for(pnt = spo->firstpoint; pnt; pnt = pnt->next) { /* main points */
     if(radial) {
      ; /* removed */
     } else {
      pnt->x = pnt->oldx + (sx*(pnt->oldx - atpoint[0]));
      pnt->y = pnt->oldy + (sy*(pnt->oldy - atpoint[1]));
      pnt->z = pnt->oldz + (sz*(pnt->oldz - atpoint[2]));
     }
    }
    for(pnt = spo->controlpnt; pnt; pnt = pnt->next) { /* control points */
     if(radial) {
      ; /* removed */
     } else {
      pnt->x = pnt->oldx + (sx*(pnt->oldx - atpoint[0]));
      pnt->y = pnt->oldy + (sy*(pnt->oldy - atpoint[1]));
      pnt->z = pnt->oldz + (sz*(pnt->oldz - atpoint[2]));
     }
    }
   } else if(ob->in == PROB_ISFLARE) { /* a flare object */
    fla = (struct flareobject *)ob->special; /* the flare structure */
    top = fla->po; /* the flare's poly */
    for(pnt = top->firstpoint; pnt; pnt = pnt->next) { /* flare polys points */
     if(radial) {
      ; /* removed */
     } else {
      pnt->x = pnt->oldx + (sx*(pnt->oldx - atpoint[0]));
      pnt->y = pnt->oldy + (sy*(pnt->oldy - atpoint[1]));
      pnt->z = pnt->oldz + (sz*(pnt->oldz - atpoint[2]));
     }
    }
   }
  }
 }
}

/* doendscalelinespmode is just like
   doendscalelines
   but handles point permission flags if in point mode
*/

void doendscalelinespmode(scax,scay,scaz)
double scax,scay,scaz;
{
 struct procobject *ob;
 struct splineobject *spo;
 struct flareobject *fla;
 struct PolygonInfo *top,*po;
 struct PointInfo *pnt;
 struct PolyBMpoint *pt;
 struct PathInfo *path;
 SHORT i;
 double sx,sy,sz;
 struct defpnt *dpt;

 if(radial) {
  ; /* removed */
 }
 sx = scax - 1.0; sy = scay - 1.0; sz = scaz - 1.0;
 for(top = firstpoly(); top; top = top->next) {
  if(ISSELECTED(top)) {
   for(pnt = top->firstpoint; pnt; pnt = pnt->next) {
    if(ISPNTPERMIT(pnt)) { /* does this point have permission to move? */
     if(radial) {
      ; /* removed */
     } else {
      pnt->x = pnt->oldx + (sx*(pnt->oldx - atpoint[0]));
      pnt->y = pnt->oldy + (sy*(pnt->oldy - atpoint[1]));
      pnt->z = pnt->oldz + (sz*(pnt->oldz - atpoint[2]));
     }
    }
   }
   /* need a flag to know if editing deform, and if so, don't do these */
   if(deforms) {
    if(path = top->path) {
     if(path->deform) {
      for(pnt = top->firstpoint; pnt; pnt = pnt->next) {
       if(ISPNTPERMIT(pnt)) { /* does this point have permission to move? */
        for(dpt = pnt->dpt; dpt; dpt = dpt->next) {
         if(radial) {
          ; /* removed */
         } else {
          dpt->x += (sx*(dpt->x - atpoint[0]));
          dpt->y += (sy*(dpt->y - atpoint[1]));
          dpt->z += (sz*(dpt->z - atpoint[2]));
         }
        }
       }
      }
     }
    }
   }
   /* if poly is textured or phong shaded and has more than 4 points
      it uses a bounder which must be altered
   */
   if((top->points > 4)&&(ISBMP(top))) { /* move bounding polys */
    pt = top->bmp.pnt;
    for(i=0;i<4;i++) {
     if(radial) {
      ; /* removed */
     } else {
      pt->x[i] = pt->oldx[i] + (sx*(pt->oldx[i] - atpoint[0]));
      pt->y[i] = pt->oldy[i] + (sy*(pt->oldy[i] - atpoint[1]));
      pt->z[i] = pt->oldz[i] + (sz*(pt->oldz[i] - atpoint[2]));
     }
    }
   }
   if(ISMELD(top)) { /* only need to move the bounding polys */
    for(po = top->special; po; po = po->next) {
     if((po->points > 4)&&(ISBMP(po))) {
      pt = po->bmp.pnt;
      for(i=0;i<4;i++) {
       if(radial) {
        ; /* removed */
       } else {
        pt->x[i] = pt->oldx[i] + (sx*(pt->oldx[i] - atpoint[0]));
        pt->y[i] = pt->oldy[i] + (sy*(pt->oldy[i] - atpoint[1]));
        pt->z[i] = pt->oldz[i] + (sz*(pt->oldz[i] - atpoint[2]));
       }
      }
     }
    }
   }
  }
 }
 for(ob = firstprocobject(); ob; ob = ob->next) {
  if(ISSELECTED(ob)) {
   if(ob->in == PROB_ISSPLINE) { /* spline object */
    spo = (struct splineobject *)ob->special;
    for(pnt = spo->firstpoint; pnt; pnt = pnt->next) {
     if(ISPNTPERMIT(pnt)) { /* does this point have permission to move? */
      if(radial) {
       ; /* removed */
      } else {
       pnt->x = pnt->oldx + (sx*(pnt->oldx - atpoint[0]));
       pnt->y = pnt->oldy + (sy*(pnt->oldy - atpoint[1]));
       pnt->z = pnt->oldz + (sz*(pnt->oldz - atpoint[2]));
      }
     }
    }
    for(pnt = spo->controlpnt; pnt; pnt = pnt->next) {
     if(ISPNTPERMIT(pnt)) { /* does this point have permission to move? */
      if(radial) {
       ; /* removed */
      } else {
       pnt->x = pnt->oldx + (sx*(pnt->oldx - atpoint[0]));
       pnt->y = pnt->oldy + (sy*(pnt->oldy - atpoint[1]));
       pnt->z = pnt->oldz + (sz*(pnt->oldz - atpoint[2]));
      }
     }
    }
   } else if(ob->in == PROB_ISFLARE) {
    fla = (struct flareobject *)ob->special;
    top = fla->po;
    for(pnt = top->firstpoint; pnt; pnt = pnt->next) {
     if(ISPNTPERMIT(pnt)) { /* does this point have permission to move? */
      if(radial) {
       ; /* removed */
      } else {
       pnt->x = pnt->oldx + (sx*(pnt->oldx - atpoint[0]));
       pnt->y = pnt->oldy + (sy*(pnt->oldy - atpoint[1]));
       pnt->z = pnt->oldz + (sz*(pnt->oldz - atpoint[2]));
      }
     }
    }
   }
  }
 }
}

static void sethighlow()
{
 struct PolygonInfo *top;
 struct PointInfo *pnt;
 struct procobject *ob;
 struct splineobject *spo;
 struct flareobject *fla;

 /* the calling function should deselect paths or lights, etc.
    if they are not to participate. */
 low[0] = low[1] = low[2] = 1000000000;
 high[0] = high[1] = high[2] = -1000000000;
 /* get the semaphore so no one else touches the data */
 ObtainSemaphore(polysema);
 for(top = firstpoly(); top; top = top->next) { /* look at all polys */
  if(ISSELECTED(top)) { /* if selected */
   for(pnt = top->firstpoint; pnt; pnt = pnt->next) { /* look at all points for poly */
    if(pnt->x < low[0]) low[0] = pnt->x;
    if(pnt->x > high[0]) high[0] = pnt->x;
    if(pnt->y < low[1]) low[1] = pnt->y;
    if(pnt->y > high[1]) high[1] = pnt->y;
    if(pnt->z < low[2]) low[2] = pnt->z;
    if(pnt->z > high[2]) high[2] = pnt->z;
   }
  }
 }
 for(ob = firstprocobject();ob;ob=ob->next) { /* all procs */
  if(ISSELECTED(ob)) { /* if selected */
   if(ob->in == PROB_ISSPLINE) { /* spline object */
    spo = (struct splineobject *)ob->special; /* the spline structure */
    for(pnt = spo->firstpoint; pnt; pnt = pnt->next) { /* main points */
     if(pnt->x < low[0]) low[0] = pnt->x;
     if(pnt->x > high[0]) high[0] = pnt->x;
     if(pnt->y < low[1]) low[1] = pnt->y;
     if(pnt->y > high[1]) high[1] = pnt->y;
     if(pnt->z < low[2]) low[2] = pnt->z;
     if(pnt->z > high[2]) high[2] = pnt->z;
    }
    for(pnt = spo->controlpnt; pnt; pnt = pnt->next) { /* control points */
     if(pnt->x < low[0]) low[0] = pnt->x;
     if(pnt->x > high[0]) high[0] = pnt->x;
     if(pnt->y < low[1]) low[1] = pnt->y;
     if(pnt->y > high[1]) high[1] = pnt->y;
     if(pnt->z < low[2]) low[2] = pnt->z;
     if(pnt->z > high[2]) high[2] = pnt->z;
    }
   } else if(ob->in == PROB_ISFLARE) { /* flare object */
    fla = (struct flareobject *)ob->special; /* the flare structure */
    top = fla->po; /* the flare poly */
    for(pnt = top->firstpoint; pnt; pnt = pnt->next) { /* flare polys points */
     if(pnt->x < low[0]) low[0] = pnt->x;
     if(pnt->x > high[0]) high[0] = pnt->x;
     if(pnt->y < low[1]) low[1] = pnt->y;
     if(pnt->y > high[1]) high[1] = pnt->y;
     if(pnt->z < low[2]) low[2] = pnt->z;
     if(pnt->z > high[2]) high[2] = pnt->z;
    }
   }
  }
 }
 /* let go of the semaphore */
 ReleaseSemaphore(polysema);
 /* these are the center point of all selected polys */
 center[0] = (high[0]+low[0])>>1;
 center[1] = (high[1]+low[1])>>1;
 center[2] = (high[2]+low[2])>>1;
}
