1 /* Copyright (C) 1992-1998 The Geometry Center
2  * Copyright (C) 1998-2000 Stuart Levy, Tamara Munzner, Mark Phillips
3  *
4  * This file is part of Geomview.
5  *
6  * Geomview is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published
8  * by the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * Geomview is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with Geomview; see the file COPYING.  If not, write
18  * to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
19  * USA, or visit http://www.gnu.org.
20  */
21 
22 #if HAVE_CONFIG_H
23 # include "config.h"
24 #endif
25 
26 #if 0
27 static char copyright[] = "Copyright (C) 1992-1998 The Geometry Center\n\
28 Copyright (C) 1998-2000 Stuart Levy, Tamara Munzner, Mark Phillips";
29 #endif
30 
31 
32 /* Authors: Charlie Gunn, Stuart Levy, Tamara Munzner, Mark Phillips */
33 
34 #include "discgrpP.h"
35 #include "mgP.h"
36 #include "math.h"
37 
38 /* this method is called before drawing, to set up a standard data
39  * structure containing a description of the camera; the user can
40  * replace it with his/her own routine that gets this information
41  * from somewhere else.
42  */
43 void
DiscGrpStandardPreDraw(DiscGrp * discgrp)44 DiscGrpStandardPreDraw(DiscGrp *discgrp)
45 {
46 	float halfy, aspect, halfx;
47 	static float magic_scale = 1.2;
48 
49     /* we're about to mess around with the camera matrix; before doing so,
50     get the current one (it's already been set for this frame) to use in
51     culling later on */
52     if (discgrp->flag  & (DG_DRAWCAM | DG_ZCULL | DG_CENTERCAM))	{
53         /* get the pieces of the model to viewing transform */
54 	CamGet(_mgc->cam, CAM_W2C, discgrp->viewinfo.w2c);
55 	TmInvert(discgrp->viewinfo.w2c, discgrp->viewinfo.c2w);
56         /* concatenate the model to world coordinate transform */
57         mg_gettransform(discgrp->viewinfo.m2w);
58 	TmInvert(discgrp->viewinfo.m2w, discgrp->viewinfo.w2m);
59         TmConcat(discgrp->viewinfo.m2w, discgrp->viewinfo.w2c, discgrp->viewinfo.m2c);
60 	TmInvert(discgrp->viewinfo.m2c, discgrp->viewinfo.c2m);
61 	CamGet(_mgc->cam, CAM_HALFYFIELD, &halfy);
62 	CamGet(_mgc->cam, CAM_ASPECT, &aspect);
63 	halfy = halfy * magic_scale;
64 	halfx = aspect * halfy;
65 
66 	/* Hack to get culling to work -Celeste */
67 	halfx = (halfx > halfy) ? halfx : halfy;
68 	halfy = halfx;
69 	/* the frustrum planes evaluate positive on cull-able points */
70 #define INITPT(ptr,xx,yy,zz,ww) { ((ptr)->x) = (xx);	\
71 			((ptr)->y) = (yy);		\
72 			((ptr)->z) = (zz);		\
73 			((ptr)->w) = (ww); }
74 	INITPT(&discgrp->viewinfo.frustrum[0], -1, 0, halfx, 0)
75 	INITPT(&discgrp->viewinfo.frustrum[1], 1, 0, halfx, 0)
76 	INITPT(&discgrp->viewinfo.frustrum[2], 0, -1, halfy, 0)
77 	INITPT(&discgrp->viewinfo.frustrum[3], 0, 1, halfy, 0)
78 	}
79 
80 }
81 
82     static float visd1 = 2.0;	/* for debugging */
83 DiscGrp *
DiscGrpDraw(DiscGrp * discgrp)84 DiscGrpDraw(DiscGrp *discgrp)
85 {
86 	static HPoint3 origin = {0,0,0,1}, cpos;
87 	Transform c2wprime;
88 	DiscGrpEl *nhbr;
89 	int metric;
90 
91     /* set up the viewing system dependent matrices, etc */
92     if (discgrp->predraw)    (*discgrp->predraw)(discgrp);
93     else		DiscGrpStandardPreDraw(discgrp);
94 
95     metric = discgrp->attributes & DG_METRIC_BITS;
96     /*  make sure we have some geometry to display; the control code
97      *	is a bit suspiciously topheavy  */
98     if (discgrp->geom == NULL || discgrp->flag & DG_NEWDIRDOM ||
99 	(discgrp->flag & DG_DRAWDIRDOM && discgrp->ddgeom == NULL)) {
100 
101       	discgrp->ddgeom = DiscGrpDirDom(discgrp);
102 	if (discgrp->geom == NULL ) discgrp->geom = discgrp->ddgeom;
103         /* turn off the alarm */
104 	discgrp->flag &= ~DG_NEWDIRDOM;
105 	if (!discgrp->ddgeom)	{
106 	    OOGLError(1,"DiscGrpDraw: Unable to create dirichlet domain\n");
107 	}
108     }
109 
110     /* be sure we have some group elements */
111     if (discgrp->big_list == NULL ) {
112       if (discgrp->nhbr_list != NULL) {
113 	discgrp->big_list = discgrp->nhbr_list;
114       } else { return(discgrp); }
115     }
116 
117     /*
118      * the main idea here is to find out the position of the current camera
119      * and use it to make sure the group elements used are centered at the
120      * camera.  We do this by looking at the orbit of the origin and seeing
121      * if the camera is closer to
122      */
123     if (discgrp->flag & DG_CENTERCAM )	{
124 	Transform cinv, hprime, h;
125 	/* use it to derive the model coordinates of the camera */
126 	HPt3Transform(discgrp->viewinfo.c2m, &origin, &cpos);
127 
128 	/* compute the group element which is 'closest' to the camera */
129 	nhbr = DiscGrpClosestGroupEl(discgrp, &cpos);
130 
131 	/* apply the inverse of this transform to the camera */
132   	TmInvert(nhbr->tform, h);
133 	/* this requires conjugating cinv by the w2m transform:
134 	 *
135          *  C  --- c2w --->   W   ---- w2m ---->   M
136 	 *   \                |                    |
137 	 *    \  	      h'                 h = nhbr->tform inverse
138 	 *     c2w'	      |                    |
139 	 *	\--------->   W   <--- m2w -----   M
140 	 *
141 	 * In the above diagram we want c2w' = c2w h'
142   	 */
143 	TmConcat(h, discgrp->viewinfo.m2w, cinv);
144 	TmConcat(discgrp->viewinfo.w2m, cinv, hprime);
145 	TmConcat(discgrp->viewinfo.c2w, hprime, c2wprime);
146 	if (discgrp->attributes & DG_HYPERBOLIC && needstuneup(c2wprime)) {
147 	    tuneup(c2wprime, metric);
148 	    if (needstuneup(c2wprime))
149 	        OOGLError(1,"DiscGrpDraw: tuneup failed\n");
150 	    }
151 	CamSet(_mgc->cam, CAM_C2W, c2wprime, CAM_END);
152 	}
153 
154     {
155     int viscnt = 0;
156     /*float ratio = 1.0;*/
157     HPoint3 image;
158     int vis;
159     float d;
160     Transform tile2c;
161 #ifdef UNNECESSARY
162     extern Geom *large_dd, *small_dd;	/*very ugly but appearances
163 		don't work correctly when pushed down into a list */
164 #endif
165     Transform Tnew;
166     GeomIter *it;
167 
168     it = GeomIterate( (Geom *)discgrp, DEEP );
169     /* loop through them */
170     while(NextTransform(it, Tnew) > 0) {
171 	vis = 1;
172 	if (discgrp->flag  & DG_ZCULL)	{
173             TmConcat(Tnew, discgrp->viewinfo.m2c, tile2c);
174             HPt3Transform(tile2c, &discgrp->cpoint, &image);
175 	    d = HPt3SpaceDistance(&image, &discgrp->cpoint, metric);
176 	    /* discard images that are too far away */
177 	    if (d > discgrp->drawdist) vis = 0;
178 	    /* some close copies are guaranteed to be drawn... */
179 	    else if (d > visd1 ) {	/* only discard far-away tiles */
180 	      /* first discard the ones behind the eye, if that makes sense */
181 	      if (metric != DG_SPHERICAL && image.z*image.w > 0.0) vis = 0;
182 	      else {	/* then test outside the camera frustrum */
183 		  { int i;
184 		  for (i=0; i<4; ++i)		{
185 		    d = HPt3R40Dot(&image, &discgrp->viewinfo.frustrum[i]);
186 		    if ( d > 0)	{
187 			vis = 0;
188 			break;
189 		 	}
190 		    }
191 		  }
192 		}
193 	      }
194 	    }
195 
196 	/* if the tile has passed the visibility tests... */
197 	if (vis)	{
198 	  viscnt++;
199           mgpushtransform();
200     	  mgtransform( Tnew );
201 
202 	  /* while the appearance stuff doesn't work correctly, we have to
203 	   * commit some pretty terrible crimes...we'd like to be able to
204 	   * just say GeomDraw(discgrp->geom)...but we can't as long as
205 	   * appearances don't work as advertised */
206 
207     	  if (discgrp->ddgeom && discgrp->flag & DG_DRAWDIRDOM)    {
208 	   if (discgrp->flag & DG_DDBEAM)	GeomDraw(discgrp->ddgeom);
209 	   else {
210 	    GeomDraw(discgrp->ddgeom);
211 #ifdef UNNECESSARY
212             mgpushappearance();
213             mgctxset(MG_ApSet, AP_DONT, APF_FACEDRAW, AP_DO, APF_EDGEDRAW, AP_END, MG_END);
214             GeomDraw(large_dd);
215             mgpopappearance();
216 
217     	    mgpushappearance();
218             mgctxset(MG_ApSet, AP_DO, APF_FACEDRAW, AP_END, MG_END);
219             GeomDraw(small_dd);
220             mgpopappearance();
221 #endif /*UNNECESSARY*/
222             }
223 	   }
224           if (discgrp->flag & DG_DRAWGEOM && discgrp->geom && discgrp->geom != discgrp->ddgeom)
225 		GeomDraw( discgrp->geom );
226 
227 	  if ((discgrp->flag & DG_DRAWCAM) && (discgrp->camgeom)) {
228 	    mgpushtransform();
229 	    mgtransform( discgrp->viewinfo.c2m );
230 	    GeomDraw(discgrp->camgeom);
231 	    mgpoptransform();
232 	    }
233 
234           mgpoptransform();
235 	  }
236         }
237     /* for debugging to see how culling works */
238     /*ratio = viscnt / ((double) discgrp->big_list->num_el);*/
239     }
240 
241     return(discgrp);
242 }
243 
244 
245 #ifdef REASONABLE
246  	TmScale( scaler, discgrp->scale, discgrp->scale, discgrp->scale);
247 	large = DiscGrpDirDom(discgrp, &discgrp->cpoint);
248 	large->ap = ApCreate(AP_DO, APF_EDGEDRAW, AP_DONT, APF_FACEDRAW, AP_END);
249 	ap = ApCreate(AP_DONT, APF_EDGEDRAW, AP_DO, APF_FACEDRAW, AP_END);
250 	small = GeomCreate("inst", CR_GEOM, large, CR_AXIS, scaler, CR_APPEAR, ap, CR_END);
251 	smlist = GeomCreate("list", CR_GEOM, small, CR_END);
252 	mylist = GeomCreate("list", CR_GEOM, large, CR_CDR, smlist, CR_END);
253 	discgrp->ddgeom = mylist;
254  	TmScale( scaler, discgrp->scale, discgrp->scale, discgrp->scale);
255 	Tm3SpaceTranslateOrigin(tlate, &discgrp->cpoint, metric);
256 	/* perform translation so cpoint is at origin */
257 	TmInvert(tlate, invtlate);
258 	/* apply scaling transform centered at cpoint */
259 	TmConcat(invtlate, scaler, tmp);
260 	/* and move cpoint back to where it started */
261 	TmConcat(tmp, tlate, tmp);
262 
263 	    d = HPt3SpaceDistance( &discgrp->cpoint, &image, metric);
264 #else
265 #endif
266