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