home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
World of A1200
/
World_Of_A1200.iso
/
programs
/
misc
/
bsplines
/
bspline.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-02-27
|
9KB
|
425 lines
/*
* BSPLINE.C
*
* Matthew Dillon.
* Public Domain (no Copyrights whatsoever)
*
* -Assumes AZTEC compilation, +L (32 bit ints), with all AMIGA symbols
* precompiled. Additionally expects certain typedefs and routines
* found in MY.LIB, as well as some MY.LIB #include files.
*
* An experienced programmer can remove the MY.LIB dependancies
* (openlibs() call), and figure out what typedefs have been assumed if
* he wishes to compile the program. You can also simply extract the
* Bezier functions for your own use.
*
* BSPLINE EQUATIONS:
*
* c(t) = T(t)BP
*
* T(t) = (t^3 t^2 t 1) P= ( Pi-1 )
* B = ( -1 3 -3 1 ) ( Pi )
* ( 3 -6 3 0 ) ( Pi+1 )
* ( -3 0 3 0 ) ( Pi+2 )
* ( 1 4 1 0 )
*
* t: range 0 to 1
* C: coordinate matrix 1xD matrix (D = dimensions)
* B: Bspline matrix 4x4
* P: Ctrl. Point matrix 4xD matrix (D = dimensions)
*
* using D = 2. For B-Spline, must loop through all control points
* beginning at Pi+1 and ending at Pend-2
*/
#include <typedefs.h>
#include <xmisc.h>
#define SHIFTS 9
#define ONE (1<<SHIFTS)
#define MAXPTS 256 /* Maximum # of bspline points allowed */
typedef struct PropInfo XPI;
typedef struct Image IM;
extern IMESS *GetMsg();
#define MYGADGETS (WINDOWSIZING|WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE)
NW Nw = {
64, 64, 320, 100,
0, 1,
NEWSIZE|MOUSEBUTTONS|MOUSEMOVE|CLOSEWINDOW|GADGETDOWN|GADGETUP|MENUPICK,
MYGADGETS|REPORTMOUSE|ACTIVATE|NOCAREREFRESH,
0, 0, (UBYTE *)"Bspline, By Matthew Dillon", NULL, NULL,
32, 64, -1, -1, WBENCHSCREEN
};
WIN *Win;
RP *Rp;
short Ux, Uy, Lx, Ly;
short Step = 128;
short Display = 1;
short Pts[MAXPTS+1][2], Npts;
main(ac, av)
char *av[];
{
register IMESS *mess;
short notdone = 1;
short pt = -1;
char mode = 0; /* 0=move pts, 1=add pts, 2=del pts */
short gy, gg = 0;
XPI *po;
init_gadgets(&Nw, &po);
exiterr(!openlibs(INTUITION_LIB|GRAPHICS_LIB), "unable to open libs");
exiterr(!(Win = OpenWindow(&Nw)), "unable to open window");
init_menu(Win);
Rp = Win->RPort;
SetAPen(Rp, 3);
SetDrMd(Rp, COMPLEMENT);
setpoint(Pts, 0, 32, 32);
setpoint(Pts, 1, 40, 40);
setpoint(Pts, 2, 100, 50);
setpoint(Pts, 3, 200, 60);
Npts = 4;
setbounds(Pts, Npts);
while (notdone) {
short mx, my, mm = 0;
WaitPort(Win->UserPort);
while (mess = GetMsg(Win->UserPort)) {
switch(mess->Class) {
case CLOSEWINDOW:
notdone = 0;
break;
case NEWSIZE:
setbounds(Pts, Npts);
break;
case GADGETUP:
case GADGETDOWN:
{
gg = mess->Class;
gy = po->VertPot / 256;
}
break;
case MOUSEBUTTONS:
switch(mess->Code) {
case SELECTDOWN:
pt = getpoint(Pts, Npts, mess->MouseX, mess->MouseY);
switch(mode) {
case 0:
mm = 1;
mx = mess->MouseX;
my = mess->MouseY;
goto break2;
case 1:
if (pt < 0)
pt = 0;
if (Npts != MAXPTS) {
bmov(Pts[pt], Pts[pt+1], (Npts-pt)*sizeof(Pts[0]));
Pts[pt][0] = mess->MouseX;
Pts[pt][1] = mess->MouseY;
++Npts;
}
break;
case 2:
if (pt >= 0 && pt < Npts) {
bmov(Pts[pt+1], Pts[pt], (Npts-pt)*sizeof(Pts[0]));
--Npts;
}
break;
}
clearall();
drawcurve(Pts, Npts);
drawpoints(Pts, 0, Npts);
break;
case SELECTUP:
pt = -1;
break;
}
break2:
break;
case MENUPICK:
switch(MENUNUM(mess->Code)) {
case 0:
mode = ITEMNUM(mess->Code);
break;
case 1:
drawpoints(Pts, 0, Npts);
Display = ITEMNUM(mess->Code); /* 0=cross 1=nums */
drawpoints(Pts, 0, Npts);
}
break;
case MOUSEMOVE:
if (gg == GADGETDOWN) {
gy = po->VertPot / 256;
break;
}
if (mode == 0 || mode == 1) {
mm = 1;
mx = mess->MouseX;
my = mess->MouseY;
}
break;
default:
break;
}
ReplyMsg(mess);
}
if (mm && pt >= 0) {
register int i;
register int n;
i = (pt - 3 < 0) ? 0 : pt - 3;
n = (i + 7 > Npts) ? Npts - i : 7;
drawpoints(Pts, pt, pt+1);
drawcurve(&Pts[i], n);
setpoint(Pts, pt, mx, my);
drawcurve(&Pts[i], n);
drawpoints(Pts, pt, pt+1);
}
if (gg) {
char buf[32];
if (gg == GADGETUP)
gg = 0;
if (gy + 1 >= 0 && gy + 1 != Step) {
Step = gy + 1;
sprintf(buf, "gran: %4ld/%ld", Step, ONE);
clearall();
drawcurve(Pts, Npts);
drawpoints(Pts, 0, Npts);
Move(Rp, Ux + 1, Uy + 16);
Text(Rp, buf, strlen(buf));
}
}
}
exiterr(1, NULL);
}
exiterr(n, str)
char *str;
{
if (n) {
if (str)
puts(str);
if (Win) {
uninit_menu(Win);
CloseWindow(Win);
}
closelibs(-1);
exit(1);
}
}
setbounds(a, na)
register long *a;
{
Ux = Win->BorderLeft;
Uy = Win->BorderTop;
Lx = Win->Width - Win->BorderRight;
Ly = Win->Height- Win->BorderBottom + 1;
clearall();
drawcurve(a, na);
drawpoints(a, 0, na);
}
setpoint(a, pt, x, y)
register short a[4][2];
{
a[pt][0] = x;
a[pt][1] = y;
}
getpoint(a, na, x, y)
register short a[][2];
{
register short i, bi;
register long r, br;
for (i = bi = 0, br = 0x7FFFFFFF; i < na; ++i) {
r = (x-a[i][0])*(x-a[i][0]) + (y-a[i][1])*(y-a[i][1])*3;
if (r < br) {
bi = i;
br = r;
}
}
return(bi);
}
clearall()
{
SetAPen(Rp, 0);
SetDrMd(Rp, JAM2);
RectFill(Rp, Ux, Uy, Lx - 1, Ly - 1);
SetAPen(Rp, 3);
SetDrMd(Rp, COMPLEMENT);
}
#define S10(x) ((x) >> SHIFTS)
#define S20(x) ((x) >> (2*SHIFTS))
/*
* So I can use integer arithmatic, I am defining 512 as 1 (as far
* as the mathematics go), which means that I must divide any power
* multiplication by 512^(n-1). E.G. .5^2 = .25 ... to make 256^2
* equal 128, I must divide by 512^1
*/
static short Array[ONE+4][2]; /* hold points to plot */
drawcurve(a, na)
register short a[][2];
{
long mr[4];
register short n, i, t;
long tt, ttt;
short last;
for (i = 1; i < na - 2; ++i) {
for (t = n = last = 0; t <= ONE; t += Step) {
oncemore:
tt = t * t;
ttt= tt* t;
mr[0] = -S20(ttt/6) + S10(tt/2) - t/2 + ONE/6;
mr[1] = S20(ttt/2) - S10(tt) + ONE*2/3;
mr[2] = -S20(ttt/2) + S10(tt/2) + t/2 + ONE/6;
mr[3] = S20(ttt/6);
Array[n][0] = (mr[0] * a[i-1][0] + mr[1] * a[i][0] + mr[2] * a[i+1][0] + mr[3] * a[i+2][0]) >> SHIFTS;
Array[n][1] = (mr[0] * a[i-1][1] + mr[1] * a[i][1] + mr[2] * a[i+1][1] + mr[3] * a[i+2][1]) >> SHIFTS;
if (++n == ONE + 4) {
--n;
puts("software error: OVERFLOW");
}
}
if (last == 0 && t > ONE) {
t = ONE;
last = 1;
goto oncemore;
}
Move(Rp, Array[0][0], Array[0][1]);
PolyDraw(Rp, n, Array);
}
}
drawpoints(a, is, ie)
register short a[][2];
{
register short i;
for (i = is; i < ie; ++i) {
if (Display) {
char buf[32];
Move(Rp, a[i][0], a[i][1]);
Draw(Rp, a[i][0], a[i][1]);
Move(Rp, a[i][0] - 16, a[i][1] + 4);
sprintf(buf, "%ld", i);
Text(Rp, buf, strlen(buf));
} else {
Move(Rp, a[i][0] - 2, a[i][1]);
Draw(Rp, a[i][0] + 2, a[i][1]);
Move(Rp, a[i][0], a[i][1] - 2);
Draw(Rp, a[i][0], a[i][1] + 2);
}
}
}
/*
* GADGET ROUTINES! ------------------------------------------------
*/
#define NG(nn) &Gadgets[nn+1]
#define G_YGLOB 1
#define G_XGLOB 2
XPI Props[] = {
{ AUTOKNOB|FREEVERT , 0, 0, 0x1FFF, 0x1FFF }
};
IM Images[] = {
{ 0,0,2,1,1, NULL, 1, 0, NULL },
};
GADGET Gadgets[] = {
{
NULL, -15, 11, 15, -19, GADGIMAGE|GADGHCOMP|GRELRIGHT|GRELHEIGHT,
GADGIMMEDIATE|RIGHTBORDER|RELVERIFY,PROPGADGET,
(APTR)&Images[0],NULL,NULL,0,(APTR)&Props[0], G_YGLOB, 0
},
};
GADGET *Gc;
long GUx, GUy;
init_gadgets(nw, ppo)
NW *nw;
XPI **ppo;
{
nw->FirstGadget = &Gadgets[0];
*ppo = &Props[0];
}
/*
* MENU ROUTINES! -----------------------------------------------------
*/
ITEXT Itext[] = {
{ 0,1,JAM2,0,0,NULL,(UBYTE *)" Move", NULL },
{ 0,1,JAM2,0,0,NULL,(UBYTE *)" Add", NULL },
{ 0,1,JAM2,0,0,NULL,(UBYTE *)" Delete",NULL },
{ 0,1,JAM2,0,0,NULL,(UBYTE *)" Cross", NULL },
{ 0,1,JAM2,0,0,NULL,(UBYTE *)" Number",NULL }
};
MENUITEM Item0[] = {
{ &Item0[1], 0, 0, 8*11, 8, CHECKIT|ITEMENABLED|COMMSEQ|HIGHCOMP|ITEMTEXT,
0xFE, (APTR)&Itext[0], NULL, 'M', NULL, NULL
},
{
&Item0[2], 0, 8, 8*11, 8, CHECKIT|ITEMENABLED|COMMSEQ|HIGHCOMP|ITEMTEXT,
0xFD, (APTR)&Itext[1], NULL, 'A', NULL, NULL
},
{
NULL, 0,16, 8*11, 8, CHECKIT|ITEMENABLED|COMMSEQ|HIGHCOMP|ITEMTEXT,
0xFB, (APTR)&Itext[2], NULL, 'D', NULL, NULL
}
};
MENUITEM Item1[] = {
{ &Item1[1], 0, 0, 8*11, 8, CHECKIT|ITEMENABLED|COMMSEQ|HIGHCOMP|ITEMTEXT,
0xFE, (APTR)&Itext[3], NULL, 'C', NULL, NULL
},
{
NULL , 0, 8, 8*11, 8, CHECKIT|ITEMENABLED|COMMSEQ|HIGHCOMP|ITEMTEXT,
0xFD, (APTR)&Itext[4], NULL, 'N', NULL, NULL
}
};
MENU Menu[] = {
{ &Menu[1], 0, 0,8*11, 8, MENUENABLED, "Control", &Item0[0] },
{ NULL , 8*11,0,8*11, 8, MENUENABLED, "Display", &Item1[0] }
};
init_menu(win)
WIN *win;
{
SetMenuStrip(win, &Menu[0]);
}
uninit_menu(win)
WIN *win;
{
ClearMenuStrip(win);
}