1 #include "medit.h"
2 #include "extern.h"
3 #include "sproto.h"
4 
5 extern int refmat,reftype,refitem;
6 int       *pilmat,ipilmat;
7 int        refpick = -1;
8 
9 GLfloat  dazim = 1.0;
10 GLfloat  delev = 1.0;
11 
12 extern void mouseCamera(int button,int state,int x,int y);
13 extern void motionCamera(int x,int y);
14 
15 
usage()16 static void usage() {
17   fprintf(stdout,"\n");
18   fprintf(stdout,"-- Medit: OnLine Help --\n");
19 
20   fprintf(stdout,"** Rendering options (toggle):\n");
21   fprintf(stdout,"f - facets        l - lines          g - const. entities\n");
22   fprintf(stdout,"c - obj. color    e - material       b - back color\n");
23   fprintf(stdout,"A - axis          B - box            G - grid\n");
24   fprintf(stdout,"C - capping       r(R) - hide (show) refs.\n");
25   fprintf(stdout,"n - smooth/flat shading\n");
26 
27   fprintf(stdout,"\n** Controls options:\n");
28   fprintf(stdout,"i - reset view    a - animate        I - interactive\n");
29   fprintf(stdout,"h - online help   q - quit           X - close window\n");
30 
31   fprintf(stdout,"\n** View controls (ALT + key):\n");
32   fprintf(stdout,"c - copy   d - duplicate p - paste  l - link   u - unlink\n");
33   fprintf(stdout,"J - toggle flight        y - change axis\n");
34 
35   fprintf(stdout,"\n** Misc. features\n");
36   fprintf(stdout,"L - load prefs    W - save prefs\n");
37   fprintf(stdout,"H - hardcopy PPM\n");
38   fprintf(stdout,"F - face nums     P - point nums     # - select entity\n");
39   fprintf(stdout,"N - normals       O - oppos. normals ! - select plane\n");
40   fprintf(stdout,"m - data          o - iso-lines      w - tensor/vector\n");
41   fprintf(stdout,"v - streamlines   k - toggle elev.   K - elev. coeff.\n");
42   fprintf(stdout,"j - toggle deco   p - palette        S - play animation\n");
43 
44   fprintf(stdout,"+/- scale object  z/Z scale view\n");
45   fprintf(stdout,"F1,F2,F3 - clipping: On/Off, Edit, Freeze\n");
46 }
47 
48 /* special keys CAMERA mode */
specCamera(pScene sc,int key)49 void specCamera(pScene sc,int key) {
50   pCamera     c;
51   double      dd,azim,elev;
52   GLfloat     axe[3];
53   int         keyact;
54 
55   c  = sc->camera;
56   keyact = glutGetModifiers();
57 
58   axe[0] = c->speed[2];
59   axe[1] = 0.0;
60   axe[2] = -c->speed[0];
61   dd = sqrt(axe[0]*axe[0] + axe[2]*axe[2]);
62   if ( dd != 0.0f ) {
63     axe[0] /= dd;
64     axe[2] /= dd;
65   }
66 
67   switch (key) {
68   case GLUT_KEY_LEFT:
69     if ( keyact & GLUT_ACTIVE_SHIFT ) {
70       c->eye[0] += axe[0]*c->altinc;
71       c->eye[2] += axe[2]*c->altinc;
72       reshapeScene(sc->par.xs,sc->par.ys);
73       glutPostRedisplay();
74       return;
75     }
76     else {
77       azim = Azimuth(c);
78       elev = Elevation(c);
79       azim += dazim;
80     }
81     break;
82   case GLUT_KEY_RIGHT:
83     if ( keyact & GLUT_ACTIVE_SHIFT ) {
84       c->eye[0] -= axe[0]*c->altinc;
85       c->eye[2] -= axe[2]*c->altinc;
86       reshapeScene(sc->par.xs,sc->par.ys);
87       glutPostRedisplay();
88       return;
89     }
90     else {
91       azim = Azimuth(c);
92       elev = Elevation(c);
93       azim -= dazim;
94     }
95     break;
96   case GLUT_KEY_UP:
97     if ( keyact & GLUT_ACTIVE_SHIFT ) {
98       c->eye[1] += c->altinc;
99       reshapeScene(sc->par.xs,sc->par.ys);
100       glutPostRedisplay();
101       return;
102     }
103     else {
104       azim = Azimuth(c);
105       elev = Elevation(c);
106       elev -= delev;
107     }
108     break;
109   case GLUT_KEY_DOWN:
110     if ( keyact & GLUT_ACTIVE_SHIFT ) {
111       c->eye[1] -= c->altinc;
112       reshapeScene(sc->par.xs,sc->par.ys);
113       glutPostRedisplay();
114       return;
115     }
116     else {
117       azim = Azimuth(c);
118       elev = Elevation(c);
119       elev += delev;
120     }
121     break;
122   default:
123     return;
124   }
125 
126   updateCamera(sc,c,azim,elev);
127 
128   /* refresh scene */
129   reshapeScene(sc->par.xs,sc->par.ys);
130   glutPostRedisplay();
131 }
132 
133 
134 /* change center of scene */
changeCenter(pScene sc,pMesh mesh)135 static void changeCenter(pScene sc,pMesh mesh) {
136   pPoint     p0;
137   pTriangle  pt;
138   pQuad      pq;
139   pTetra     ptt;
140   pHexa      ph;
141   float      cx,cy,cz;
142   int        i;
143 
144   if ( !refitem )  return;
145   cx = cy = cz = 0.0;
146   switch(reftype) {
147   case LPoint:
148     p0 = &mesh->point[refitem];
149     cx = p0->c[0];
150     cy = p0->c[1];
151     cz = p0->c[2];
152     break;
153   case LTria:
154     pt = &mesh->tria[refitem];
155     for (i=0; i<3; i++) {
156       p0 = &mesh->point[pt->v[i]];
157       cx += 0.33 * p0->c[0];
158       cy += 0.33 * p0->c[1];
159       cz += 0.33 * p0->c[2];
160     }
161     break;
162   case LQuad:
163     pq = &mesh->quad[refitem];
164     for (i=0; i<4; i++) {
165       p0 = &mesh->point[pq->v[i]];
166       cx += 0.25 * p0->c[0];
167       cy += 0.25 * p0->c[1];
168       cz += 0.25 * p0->c[2];
169     }
170     break;
171   case LTets:
172     ptt = &mesh->tetra[refitem];
173     for (i=0; i<4; i++) {
174       p0 = &mesh->point[ptt->v[i]];
175       cx += 0.25 * p0->c[0];
176       cy += 0.25 * p0->c[1];
177       cz += 0.25 * p0->c[2];
178     }
179     break;
180   case LHexa:
181     ph = &mesh->hexa[refitem];
182     for (i=0; i<8; i++) {
183       p0 = &mesh->point[ph->v[i]];
184       cx += 0.125 * p0->c[0];
185       cy += 0.125 * p0->c[1];
186       cz += 0.125 * p0->c[2];
187     }
188     break;
189   }
190 
191   /* reset translation and move to center */
192   sc->view->panx = sc->view->pany = 0.0;
193   sc->cx = -cx;
194   sc->cy = -cy;
195   sc->cz = -cz;
196 }
197 
198 
199 /* special keys PERSPECTIVE mode */
special(int key,int x,int y)200 void special(int key,int x,int y) {
201   pTransform  view;
202   pScene      sc;
203   pMesh       mesh;
204   pClip       clip;
205   pCube       cube;
206   float       pancoeff = 0.1f;
207   int         keyact,idw = currentScene();
208   ubyte       post = TRUE;
209 
210   /* default */
211   if ( ddebug ) printf("special key  %d\n",key);
212   sc   = cv.scene[idw];
213 
214   /* special mode camera */
215   if ( sc->persp->pmode == CAMERA ) {
216     specCamera(sc,key);
217     return;
218   }
219 
220   view = sc->view;
221   mesh = cv.mesh[sc->idmesh];
222   clip = sc->clip;
223   cube = sc->cube;
224   keyact = glutGetModifiers();
225   if ( keyact & GLUT_ACTIVE_SHIFT )
226     pancoeff = 0.01;
227 
228   switch(key) {
229   case GLUT_KEY_F1:  /* toggle clipping plane */
230     if ( mesh->dim == 3 ) {
231       if ( cube->active & C_ON)
232     keyCube('C',0,0);
233       else
234     keyClip('C',0,0);
235     }
236     post = FALSE;
237     break;
238   case GLUT_KEY_F2:  /* edit clipping plane */
239     if ( mesh->dim == 3 ) {
240       if ( cube->active & C_ON)
241         keyCube('E',0,0);
242       else if ( clip->active & C_ON )
243     keyClip('E',0,0);
244     }
245     post = FALSE;
246     break;
247   case GLUT_KEY_F3:  /* freeze clipping plane */
248     if ( cube->active & C_ON )
249       keyCube('F',0,0);
250     else if ( clip->active & C_ON )
251       keyClip('F',0,0);
252     post = FALSE;
253     break;
254   case GLUT_KEY_F4:  /* toggle Vclip */
255     if ( mesh->dim == 3 )  keyClip('Z',0,0);
256     post = FALSE;
257     break;
258   case GLUT_KEY_F5:  /* Toggle Shrink */
259     if ( mesh->ntet+mesh->nhex > 0 )
260       keyFeature('V',0,0);
261     else
262       keyFeature('S',0,0);
263     break;
264   case GLUT_KEY_F6:  /* Increase Shrink */
265     keyFeature('I',0,0);
266     break;
267   case GLUT_KEY_F7:  /* Decrease Shrink */
268     keyFeature('i',0,0);
269     break;
270 
271   case GLUT_KEY_LEFT:  /* translate eyes or object */
272     if ( clip->active & C_EDIT ) {
273       clip->cliptr->panx -= 0.02 * sc->dmax;
274       clip->cliptr->angle = 0.0;
275       clip->active |= C_UPDATE + C_REDO;
276     }
277     else if ( keyact & GLUT_ACTIVE_CTRL ) {
278       sc->par.eyesep *= 0.9;
279       printf("eyesep %f\n",sc->par.eyesep);
280     }
281     else
282       view->panx -= pancoeff * sc->dmax;
283     break;
284   case GLUT_KEY_RIGHT:
285     if ( clip->active & C_EDIT ) {
286       clip->cliptr->panx += 0.02 * sc->dmax;
287       clip->cliptr->angle = 0.0;
288       clip->active |= C_UPDATE + C_REDO;
289     }
290     else if ( keyact & GLUT_ACTIVE_CTRL ) {
291       sc->par.eyesep *= 1.1;
292       printf("eyesep %f\n",sc->par.eyesep);
293     }
294     else
295       view->panx += pancoeff * sc->dmax;
296     break;
297   case GLUT_KEY_UP:
298     if ( clip->active & C_EDIT ) {
299       clip->cliptr->pany += 0.02 * sc->dmax;
300       clip->cliptr->angle = 0.0;
301       clip->active |= C_UPDATE + C_REDO;
302     }
303     else
304       view->pany += pancoeff * sc->dmax;
305     break;
306   case GLUT_KEY_DOWN:
307     if ( clip->active & C_EDIT ) {
308       clip->cliptr->pany -= 0.02 * sc->dmax;
309       clip->cliptr->angle = 0.0;
310       clip->active |= C_UPDATE + C_REDO;
311     }
312     else
313       view->pany -= pancoeff * sc->dmax;
314     break;
315   default:
316     return;
317   }
318   if ( post )  glutPostRedisplay();
319 }
320 
321 
keyScene(unsigned char key,int x,int y)322 void keyScene(unsigned char key,int x,int y) {
323   pMaterial   pm;
324   pTetra      ptt;
325   pHexa       ph;
326   pTriangle   pt;
327   pQuad       pq;
328   pScene      sc,sc1;
329   pMesh       mesh;
330   pClip       clip;
331   pCube       cube;
332   pPersp      p;
333   pCamera     cam;
334   double      dd;
335   float       a,b,c,d;
336   int         k,keyact,numit,idw = currentScene();
337   ubyte       post = FALSE,dolist = FALSE;
338 
339   if ( idw < 0 ) exit(0);
340 
341   /* ESC = end medit */
342   if ( key == 'q' || key == 27 )
343     exit(0);
344   else if ( key == 'h' || key == '?' )
345     usage();
346 
347   /* default */
348   sc   = cv.scene[idw];
349   mesh = cv.mesh[sc->idmesh];
350   clip = sc->clip;
351   cube = sc->cube;
352   p    = sc->persp;
353 
354   keyact = glutGetModifiers();
355   if ( key == ' ' ) {
356     if ( option == MORPHING )
357       morphMesh(sc,mesh);
358     else if ( sc->isotyp & S_PARTICLE ) {
359       glutIdleFunc(0);
360     }
361     else {
362       cam = sc->camera;
363       cam->eye[0] += cam->spmod*cam->speed[0];
364       cam->eye[1] += cam->spmod*cam->speed[1];
365       cam->eye[2] += cam->spmod*cam->speed[2];
366       reshapeScene(sc->par.xs,sc->par.ys);
367     }
368     post = TRUE;
369   }
370 
371   else if ( islower(key) ) {
372     switch(key) {
373     case 'a':  /* toggle animate */
374       keyAnim('A',0,0);
375       break;
376     case 'b':  /* backcolor */
377       keyColor('b',0,0);
378       break;
379     case 'c':
380       if ( keyact & GLUT_ACTIVE_ALT )
381     keyView('C',0,0);
382       else {
383     sc->mode ^= S_COLOR;
384     post = TRUE;
385       }
386       break;
387     case 'd':
388       if ( keyact & GLUT_ACTIVE_ALT ) keyView('D',0,0);
389       break;
390     case 'e':
391       keyColor('e',0,0);
392       break;
393     case 'f':
394       sc->mode ^= S_FILL;
395       post=TRUE;
396       break;
397     case 'g':
398       keyItem('g',0,0);
399       break;
400     case 'h':
401       usage();
402       break;
403     case 'i':
404       keyView('R',0,0);
405       if ( clip->active & C_ON )  resetClip(sc,clip,mesh);
406       if ( cube->active & C_ON )  resetCube(sc,cube,mesh);
407       sc1 = sc;
408       while ( sc1->slave > -1 ) {
409         sc1 = cv.scene[sc1->slave];
410         glutSetWindow(sc1->idwin);
411         keyScene('i',0,0);
412       }
413       glutSetWindow(sc->idwin);
414       break;
415     case 'j':
416       sc->type ^= S_DECO;
417       post = TRUE;
418       break;
419     case 'k':
420       keyMetric('k',0,0);
421       break;
422     case 'l':
423       if ( keyact & GLUT_ACTIVE_ALT )
424         keyView('L',0,0);
425       else
426         sc->mode ^= S_BDRY;
427       post = TRUE;
428       break;
429     case 'm':  /* toggle metric */
430       if ( mesh->nbb )  keyMetric('m',0,0);
431       keyMode('n',0,0);
432       break;
433     case 'n':
434 		  if ( mesh->nvn )  keyMode('n',0,0);
435 		  break;
436     case 'o': /* iso-lines */
437       if ( mesh->nbb ) keyMetric('l',0,0);
438       break;
439     case 'p':
440       if ( keyact & GLUT_ACTIVE_ALT )
441         keyView('P',0,0);
442       else
443         keyMetric('p',0,0);
444       break;
445     case 'r':
446       if ( refmat<0 || ipilmat == sc->par.nbmat ) return;
447       pilmat[++ipilmat] = refmat;
448       pm = &sc->material[refmat];
449       pm->flag = 1;
450       updatePoints(sc,mesh,refmat);
451       if ( sc->picklist ) glDeleteLists(sc->picklist,1);
452       sc->picklist = 0;
453       refmat = -1;
454       dolist = TRUE;
455       post   = TRUE;
456       break;
457     case 's':
458       if ( !refitem ) return;
459       switch(reftype) {
460       case LTria:
461         pt = &mesh->tria[refitem];
462         pt->v[0] = 0;
463         break;
464       case LQuad:
465         pq = &mesh->quad[refitem];
466         pq->v[0] = 0;
467         break;
468       case LTets:
469         ptt = &mesh->tetra[refitem];
470         ptt->v[0] = 0;
471         break;
472       case LHexa:
473         ph = &mesh->hexa[refitem];
474         ph->v[0] = 0;
475         break;
476       }
477       sc->picklist = 0;
478       dolist = TRUE;
479       post   = TRUE;
480       break;
481     case 't':  /* toggle texture */
482       /*keyColor('t',0,0);*/
483       break;
484     case 'u':
485       if ( keyact & GLUT_ACTIVE_ALT )
486     keyView('U',0,0);
487       break;
488     case 'v':
489       keyMetric('v',0,0);
490       break;
491     case 'w':
492       keyMetric('w',0,0);
493       break;
494     case 'x':
495       if ( cube->active & C_EDIT ) {
496         cube->cma[0] += 0.1*sc->dmax;
497         post = TRUE;
498         break;
499       }
500     case 'y':
501       if ( cube->active & C_EDIT ) {
502         cube->cma[1] += 0.1*sc->dmax;
503         post = TRUE;
504         break;
505       }
506       if ( p->pmode & CAMERA ) {
507         cam = sc->camera;
508         cam->vecup = (cam->vecup+1) % 3;
509         switch(cam->vecup) {
510           case X_AXIS: cam->altinc = (mesh->xmax-mesh->xmin); break;
511           case Y_AXIS: cam->altinc = (mesh->ymax-mesh->ymin); break;
512           case Z_AXIS: cam->altinc = (mesh->zmax-mesh->zmin); break;
513         }
514         cam->altinc *= 0.005f;
515         sc->type |= S_RESET;
516         reshapeScene(sc->par.xs,sc->par.ys);
517       }
518       /* tilt cut plane */
519       else if ( clip->active & C_EDIT )
520         tiltClip(sc,clip);
521       else return;
522       post = TRUE;
523       break;
524 
525     case 'z':  /* zoom in */
526       if ( cube->active & C_EDIT ) {
527         cube->cma[2] += 0.1*sc->dmax;
528         post = TRUE;
529         break;
530       }
531       else {
532     if ( p->rubber == 2 )
533       setPersp(sc,p,1);
534         else
535           p->fovy = max(0.9*p->fovy,1e-05);
536         farclip(1);
537       }
538       post = TRUE;
539 
540       /* get linked view */
541       sc1 = sc;
542       while ( sc1->slave > -1 ) {
543         sc1 = cv.scene[sc1->slave];
544         memcpy(sc1->view,sc->view,sizeof(struct transform));
545         memcpy(sc1->persp,sc->persp,sizeof(struct sperspective));
546         glutSetWindow(sc1->idwin);
547         reshapeScene(sc1->par.xs,sc1->par.ys);
548       }
549       glutSetWindow(sc->idwin);
550       break;
551     }
552   }
553 
554   else if ( isupper(key) ) {
555     switch(key) {
556     case 'A':  /* toggle axis */
557       keyItem('A',0,0);
558       break;
559     case 'B':  /* toggle box */
560       keyItem('B',0,0);
561       break;
562     case 'C':  /* toggle capping */
563       keyClip('K',0,0);
564       break;
565     case 'D':  /* selection cube */
566       if (mesh->dim == 3 )  keyItem('D',0,0);
567         break;
568     case 'E':
569       keyColor('E',0,0);
570       glutSetWindow(sc->idwin);
571       break;
572     case 'F': /* toggle face nums */
573       keyItem('F',0,0);
574       break;
575     case 'G':  /* toggle grid */
576       keyItem('G',0,0);
577       break;
578     case 'H': /* hardcopy PPM */
579       keyFile('H',0,0);
580       break;
581     case 'I':  /* follows mouse */
582       sc->type ^= S_FOLLOW;
583       sc1 = sc;
584       while ( sc1->slave > -1 ) {
585         sc1 = cv.scene[sc1->slave];
586         sc1->type = sc->type;
587       }
588       break;
589     case 'J':
590       if ( mesh->dim == 2 && !(sc->mode & S_ALTITUDE) )  break;
591       if ( p->pmode == PERSPECTIVE ) {
592         p->pmode = CAMERA;
593         glutMouseFunc(mouseCamera);
594         glutMotionFunc(motionCamera);
595       }
596       else {
597         p->pmode = PERSPECTIVE;
598         glutMouseFunc(mouse);
599         glutMotionFunc(motion);
600       }
601       sc->type = S_RESET;
602       reshapeScene(sc->par.xs,sc->par.ys);
603       post = TRUE;
604       break;
605     case 'K':
606       keyMetric('K',0,0);
607       break;
608     case 'L':
609       keyFile('L',0,0);
610       break;
611     case 'M':
612       morphing = 1-morphing;
613       post = TRUE;
614       break;
615     case 'N':  /* draw normals */
616     case 'O':
617       if ( mesh->nvn )
618         keyItem(key,0,0);
619       break;
620     case 'P': /* toggle point nums */
621       keyItem('P',0,0);
622       break;
623     case 'Q':
624       /*keyMetric('q',0,0);*/
625       break;
626     case 'R':
627       if ( ipilmat < 1 ) return;
628       refmat = pilmat[ipilmat--];
629       pm = &sc->material[refmat];
630       pm->flag = 0;
631       updatePoints(sc,mesh,refmat);
632       dolist = TRUE;
633       post   = TRUE;
634       break;
635     case 'S':  /* softcopy */
636       /*keyFile('S',0,0);*/
637       keyAnim('S',0,0);
638       break;
639     case 'V':  /* change center of scene */
640       if ( !refitem )  return;
641       changeCenter(sc,mesh);
642       reshapeScene(sc->par.xs,sc->par.ys);
643       post = TRUE;
644       /* linked view */
645       sc1 = sc;
646       while ( sc1->slave > -1 ) {
647         sc1 = cv.scene[sc1->slave];
648         sc1->cx = sc->cx;
649         sc1->cy = sc->cy;
650         sc1->cz = sc->cz;
651         memcpy(sc1->view,sc->view,sizeof(struct transform));
652         memcpy(sc1->persp,sc->persp,sizeof(struct sperspective));
653         glutSetWindow(sc1->idwin);
654         reshapeScene(sc1->par.xs,sc1->par.ys);
655       }
656       glutSetWindow(sc->idwin);
657       break;
658     case 'W':
659       keyFile('W',0,0);
660       break;
661     case 'X':  /* close window */
662       if ( cube->active & C_EDIT ) {
663         cube->cma[0] -= 0.1*sc->dmax;
664         post = TRUE;
665         break;
666       }
667       if ( idw != cv.nbs ) {
668         deleteScene(sc);
669         for (k=idw+1; k<cv.nbs; k++)
670           cv.scene[k-1] = cv.scene[k];
671         cv.scene[cv.nbs-1] = 0;
672       }
673       glutHideWindow();
674       if ( --cv.nbs == 0 ) exit(0);
675       break;
676 
677     case 'Y':  /* close window */
678       if ( cube->active & C_EDIT ) {
679         cube->cma[1] -= 0.1*sc->dmax;
680         post = TRUE;
681         break;
682       }
683     case 'Z':  /* zoom out */
684       if ( cube->active & C_EDIT ) {
685         cube->cma[2] -= 0.1*sc->dmax;
686         post = TRUE;
687         break;
688       }
689       else {
690         if ( p->rubber == 2 )
691           setPersp(sc,p,0);
692         else
693           p->fovy = min(1.1*p->fovy,179.0);
694         farclip(1);
695       }
696       post = TRUE;
697 
698       /* get linked view */
699       sc1 = sc;
700       while ( sc1->slave > -1 ) {
701         sc1 = cv.scene[sc1->slave];
702         memcpy(sc1->view,sc->view,sizeof(struct transform));
703         memcpy(sc1->persp,sc->persp,sizeof(struct sperspective));
704         glutSetWindow(sc1->idwin);
705         reshapeScene(sc1->par.xs,sc1->par.ys);
706       }
707       glutSetWindow(sc->idwin);
708       break;
709     }
710   }
711 
712   else {
713     switch (key) {
714     case '-':
715       if (keyact & GLUT_ACTIVE_ALT ) {
716         keyAnim('p',0,0);
717         break;
718       }
719       if ( cube->active & C_EDIT ) {
720         cube->cma[0] *= 0.95;
721         cube->cma[1] *= 0.95;
722         cube->cma[2] *= 0.95;
723         post = TRUE;
724         break;
725       }
726       if ( sc->persp->pmode == CAMERA ) {
727         cam = sc->camera;
728         cam->spmod -= 1.e-04 * sc->dmax;
729         post = TRUE;
730         break;
731       }
732       if ( p->depth < -20.0*sc->dmax )  break;
733       p->depth -= 0.1*sc->dmax;
734       farclip(1);
735       post = TRUE;
736 
737       /*
738       if ( p->rubber == 2 )
739         setPersp(sc,p,0);
740       else
741         p->fovy = min(1.1*p->fovy,179.0);
742       farclip(1);
743       post = TRUE;
744       */
745       /* get linked view */
746       sc1 = sc;
747       while ( sc1->slave > -1 ) {
748         sc1 = cv.scene[sc1->slave];
749         memcpy(sc1->view,sc->view,sizeof(struct transform));
750         memcpy(sc1->persp,sc->persp,sizeof(struct sperspective));
751         glutSetWindow(sc1->idwin);
752         reshapeScene(sc1->par.xs,sc1->par.ys);
753       }
754       glutSetWindow(sc->idwin);
755       break;
756 
757     case '+':
758       if (keyact & GLUT_ACTIVE_ALT ) {
759         keyAnim('n',0,0);
760         break;
761       }
762       if ( cube->active & C_EDIT ) {
763     cube->cma[0] *= 1.05;
764     cube->cma[1] *= 1.05;
765     cube->cma[2] *= 1.05;
766         post = TRUE;
767         break;
768       }
769       if ( sc->persp->pmode == CAMERA ) {
770         cam = sc->camera;
771         cam->spmod += 1.e-04 * sc->dmax;
772         post = TRUE;
773         break;
774       }
775       if ( p->depth > 0.0 )  break;
776       p->depth += 0.1*sc->dmax;
777       farclip(1);
778       post = TRUE;
779 
780 /*
781       if ( p->rubber == 2 )
782     setPersp(sc,p,1);
783       else
784       p->fovy = max(0.9*p->fovy,1e-05);
785       farclip(1);
786       post = TRUE;
787 */
788       /* update linked view */
789       sc1 = sc;
790       while ( sc1->slave > -1 ) {
791         sc1 = cv.scene[sc1->slave];
792         memcpy(sc1->view,sc->view,sizeof(struct transform));
793         memcpy(sc1->camera,sc->camera,sizeof(struct camera));
794         memcpy(sc1->persp,sc->persp,sizeof(struct sperspective));
795         glutSetWindow(sc1->idwin);
796         reshapeScene(sc1->par.xs,sc1->par.ys);
797       }
798       glutSetWindow(sc->idwin);
799       break;
800 
801     case '#':  /* select entity */
802       fprintf(stdout,"ENTITY NUMBER: "); fflush(stdout);
803       fflush(stdin);  fscanf(stdin,"%d",&numit);
804       if ( sc->picklist )  glDeleteLists(sc->picklist,1);
805       if ( numit > 0 )
806     sc->picklist = pickItem(mesh,sc,numit);
807       post = TRUE;
808       break;
809     case '!':  /* clip plane */
810       if ( !(clip->active & C_ON) )  return;
811       dd = clip->eqn[3]-clip->eqn[0]*mesh->xtra \
812          - clip->eqn[1]*mesh->ytra-clip->eqn[2]*mesh->ztra;
813       fprintf(stdout,"\nCurrent plane: %gx %+gy %+gz %+g = 0\n",
814               clip->eqn[0],clip->eqn[1],clip->eqn[2],dd);
815       fprintf(stdout,"Plane coeffs : "); fflush(stdout);
816       fflush(stdin);  fscanf(stdin,"%f %f %f %f",&a,&b,&c,&d);
817       resetClip(sc,clip,mesh);
818       clip->eqn[0] = a;
819       clip->eqn[1] = b;
820       clip->eqn[2] = c;
821       clip->eqn[3] = d;
822 
823       fprintf(stdout,"New plane eq.: ");
824       if ( clip->eqn[0] )
825         fprintf(stdout,"%+gx",clip->eqn[0]);
826       if ( clip->eqn[1] )
827         fprintf(stdout," %+gy",clip->eqn[1]);
828       if ( clip->eqn[2] )
829         fprintf(stdout," %+gz",clip->eqn[2]);
830       if ( clip->eqn[3] )
831         fprintf(stdout," %+g",clip->eqn[3]);
832       fprintf(stdout," = 0\n");
833       clip->eqn[3] += (a*mesh->xtra+b*mesh->ytra+c*mesh->ztra);
834       post   = TRUE;
835       dolist = TRUE;
836       break;
837 
838     case '@': /* add trajectoire point */
839       if ( p->pmode == CAMERA )
840         pathAdd(sc,x,y);
841       break;
842 
843     case '%':
844       fprintf(stdout,"reference (%d): ",refpick); fflush(stdout);
845       fflush(stdin);
846       fscanf(stdin,"%d",&refpick);
847       break;
848 
849     case '&':
850       puts("ADJUST");
851       parEdit(sc);
852       break;
853     }
854   }
855 
856   if ( dolist ) {
857     doLists(sc,mesh);
858     doMapLists(sc,mesh,1);
859     doIsoLists(sc,mesh,1);
860   }
861   if ( post )   glutPostRedisplay();
862 }
863 
864