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 <math.h>
35 #include "handleP.h"
36 #include "cameraP.h"
37 #include "transobj.h"
38
39 HandleOps CamOps = {
40 "cam",
41 (int ((*)()))CamStreamIn,
42 (int ((*)()))CamStreamOut,
43 (void ((*)()))CamDelete,
44 NULL, /* Resync */
45 NULL /* close pool */
46 };
47
48
49 /*
50 * Load Camera from file.
51 * Syntax:
52 * [camera] < "filename_containing_camera" [or]
53 * [camera] { keyword value keyword value ... }
54 *
55 */
56 int
CamStreamIn(Pool * p,Handle ** hp,Camera ** camp)57 CamStreamIn(Pool *p, Handle **hp, Camera **camp)
58 {
59 char *w, *raww;
60 IOBFILE *f;
61 Handle *h = NULL;
62 Handle *hname = NULL;
63 Camera *cam = NULL;
64 int credible = 0;
65 int i;
66 int got;
67 float v;
68 int brack = 0;
69 int empty = 1, braces = 0;
70 static struct kw {
71 char *name;
72 char args;
73 int kbit;
74 } kw[] = {
75 { "camtoworld", 0, CAMF_NEWC2W },
76 { "worldtocam", 0, CAMF_W2C },
77 { "flag", 1, CAMF_PERSP|CAMF_STEREO },
78 { "halfyfield", 1, CAMF_FOV },
79 { "frameaspect",1, CAMF_ASPECT },
80 { "focus", 1, CAMF_FOCUS }, /* 5 */
81 { "near", 1, CAMF_NEAR },
82 { "far", 1, CAMF_FAR },
83 { "stereo_sep", 1, CAMF_STEREOGEOM },
84 { "stereo_angle",1, CAMF_STEREOGEOM },
85 { "stereyes", 0, CAMF_STEREOXFORM }, /* 10 */
86 { "whicheye", 1, CAMF_EYE },
87 { "define", 0, 0 },
88 { "camera", 0, 0 },
89 { "perspective",1, CAMF_PERSP },
90 { "stereo", 1, CAMF_STEREO }, /* 15 */
91 { "hyperbolic", 1, 0 /* CAMF_HYPERBOLIC is now obsolete */ },
92 { "fov", 1, CAMF_FOV },
93 { "bgcolor", 0, 0 },
94 { "bgimage", 0, 0 },
95 };
96
97 if ((f = PoolInputFile(p)) == NULL)
98 return 0;
99
100 for(;;) {
101 switch(i = iobfnextc(f, 0)) {
102 case '<':
103 case ':':
104 case '@':
105 iobfgetc(f);
106 w = iobfdelimtok("(){}", f, 0);
107 if (i == '<' && (h = HandleByName(w, &CamOps)) == NULL && w[0] != '\0') {
108 w = findfile(PoolName(p), raww = w);
109 if (w == NULL) {
110 OOGLSyntax(f, "Reading camera from \"%s\": can't find file \"%s\"",
111 PoolName(p), raww);
112 }
113 } else if (h) {
114 /* HandleByName() increases the ref. count s.t. the
115 * caller of HandleByName() owns the returned handle.
116 */
117 HandleDelete(h);
118 }
119
120 if ((h = HandleReferringTo(i, w, &CamOps, hp)) != NULL) {
121 cam = (Camera *)h->object;
122 /* Increment the ref. count. This way we can call
123 * HandleDelete() and CamDelete() independently.
124 */
125 RefIncr((Ref*)cam);
126 }
127 if (!brack) goto done;
128 break;
129
130 case '{': brack++; iobfgetc(f); break;
131 case '}':
132 if (brack > 0) { iobfgetc(f); braces = 1; }
133 if (--brack <= 0) goto done;
134 /* Otherwise, fall through into... */
135 default:
136 empty = 0;
137 w = iobfdelimtok("(){}", f, 0);
138 if (w == NULL)
139 goto done;
140
141 for(i = sizeof(kw)/sizeof(kw[0]); --i >= 0; )
142 if (!strcmp(w, kw[i].name))
143 break;
144
145 if (i < 0) {
146 if (credible)
147 OOGLSyntax(f, "Reading camera from \"%s\": unknown camera keyword \"%s\"",
148 PoolName(p), w);
149 if (cam) CamDelete(cam);
150 return 0;
151 } else if ( (got= iobfgetnf(f, kw[i].args, &v, 0)) != kw[i].args ) {
152 OOGLSyntax(f, "Reading camera from \"%s\": \"%s\" expects %d values, got %d",
153 PoolName(p), w, kw[i].args, got);
154 CamDelete(cam);
155 return false;
156 }
157 if (i != 13 && cam == NULL) {
158 cam = CamCreate(CAM_END);
159 credible = 1;
160 }
161 if (cam) {
162 cam->changed |= kw[i].kbit;
163 }
164 switch (i) {
165 case 0: {
166 TransObj *tobj = NULL;
167 Handle *thandle = NULL;
168 if (TransObjStreamIn(p, &thandle, &tobj)) {
169 CamSet(cam, CAM_C2W, tobj->T, CAM_C2WHANDLE, thandle, CAM_END);
170 HandleDelete(thandle);
171 TransDelete(tobj);
172 }
173 break;
174 }
175 case 1: {
176 TransObj *tobj = NULL;
177 Handle *thandle = NULL;
178 if (TransObjStreamIn(p, &thandle, &tobj)) {
179 CamSet(cam, CAM_W2C, tobj, CAM_W2CHANDLE, thandle, CAM_END);
180 HandleDelete(thandle);
181 TransDelete(tobj);
182 }
183 break;
184 }
185 case 2: cam->flag = (int)v; break;
186 case 3: CamSet(cam, CAM_HALFYFIELD, v, CAM_END); break;
187 case 4: CamSet(cam, CAM_ASPECT, v, CAM_END); break;
188 case 5: CamSet(cam, CAM_FOCUS, v, CAM_END); break;
189 case 6: cam->cnear = v; break;
190 case 7: cam->cfar = v; break;
191 case 8: CamSet(cam, CAM_STEREOSEP, v, CAM_END); break;
192 case 9: CamSet(cam, CAM_STEREOANGLE, v, CAM_END); break;
193 case 10: {
194 TransObj *tobj[2] = { NULL, NULL };
195 Handle *thandle[2] = { NULL, NULL };
196 int i;
197 if (TransObjStreamIn(p, &thandle[0], &tobj[0]) &&
198 TransObjStreamIn(p, &thandle[1], &tobj[1])) {
199 TmCopy(tobj[0]->T, cam->stereyes[0]);
200 TmCopy(tobj[1]->T, cam->stereyes[1]);
201 CamSet(cam, CAM_STEREYES, cam->stereyes,
202 CAM_STERHANDLES, thandle,
203 CAM_END);
204 }
205 for (i = 0; i < 2; i++) {
206 HandleDelete(thandle[i]);
207 TransDelete(tobj[i]);
208 }
209 }
210
211 break;
212 case 11: cam->whicheye = (int)v; break;
213 case 12: /* "define" */
214 hname = HandleCreateGlobal(iobfdelimtok("(){}", f, 0), &CamOps);
215 break;
216 case 13: /* "camera" */ break;
217
218 case 14: /* "perspective" */
219 case 15: /* "stereo" */
220 cam->flag &= ~kw[i].kbit;
221 if (v != 0) cam->flag |= kw[i].kbit;
222 break;
223
224 case 16: /* "hyperbolic" */
225 /* The "hyperbolic" field is obsolete (replaced by the
226 "space" field. Ignore it for now [ Mon Dec 7 14:05:50
227 1992 ]. After a few months [ say in March 1993 ] add a
228 warning message to be printed out at this point in the
229 code, and after a few more months [ say June 1993 ],
230 remove it completely. -- mbp */
231 break;
232
233 case 17: /* "fov" */ CamSet(cam, CAM_FOV, v, CAM_END); break;
234 case 18: /* bgcolor */
235 /* we always expect RGB values in the range 0..1 as floating
236 * point values.
237 */
238 if ((got = iobfgetnf(f, 3, (float *)&cam->bgcolor, 0)) != 3) {
239 OOGLSyntax(f, "Reading camera from \"%s\": \"%s\" expects "
240 "an RGB(A) color specification "
241 "(got only %d values, not 3 or 4)",
242 PoolName(p), "bgcolor", got);
243 CamDelete(cam);
244 return false;
245 }
246 if (got == 3 && iobfgetnf(f, 1, (float *)&cam->bgcolor+3, 0) != 1) {
247 cam->bgcolor.a = 1.0;
248 }
249 break;
250 case 19: /* bgimage */
251 if (!ImgStreamIn(p, &cam->bgimghandle, &cam->bgimage)) {
252 OOGLSyntax(f, "Reading camera from \"%s\": "
253 "unable to read background image",
254 PoolName(p));
255 CamDelete(cam);
256 return false;
257 }
258 break;
259 }
260 }
261 }
262
263 done:
264
265 if (hname) {
266 if (cam) {
267 HandleSetObject(hname, (Ref *)cam);
268 }
269 if (h) {
270 /* HandleReferringTo() has passed the ownership to use, so
271 * delete h because we do not need it anymore.
272 */
273 HandleDelete(h);
274 }
275 h = hname;
276 }
277
278 /* Pass the ownership of h and cam to the caller if requested */
279
280 if (hp != NULL) {
281 /* pass on ownership of the handle h to the caller of this function */
282 if (*hp != NULL) {
283 if (*hp != h) {
284 HandlePDelete(hp);
285 } else {
286 HandleDelete(*hp);
287 }
288 }
289 *hp = h;
290 } else if (h) {
291 /* Otherwise delete h because we are its owner. Note that
292 * HandleReferringTo() has passed the ownership of h to us;
293 * explicitly defined handles (hdefine and define constructs)
294 * will not be deleted by this call.
295 */
296 HandleDelete(h);
297 }
298
299 /* same logic as for hp */
300 if (camp != NULL) {
301 if (*camp) {
302 CamDelete(*camp);
303 }
304 *camp = cam;
305 } else if(cam) {
306 CamDelete(cam);
307 }
308
309 return (cam != NULL || h != NULL || (empty && braces));
310 }
311
312
313 int
CamStreamOut(Pool * p,Handle * h,Camera * cam)314 CamStreamOut(Pool *p, Handle *h, Camera *cam)
315 {
316 float fov;
317 FILE *outf;
318
319 if ((outf = PoolOutputFile(p)) == NULL) {
320 return 0;
321 }
322
323 fprintf(outf, "camera {\n");
324 PoolIncLevel(p, 1);
325
326 if (cam == NULL && h != NULL && h->object != NULL) {
327 cam = (Camera *)h->object;
328 }
329
330 if (PoolStreamOutHandle(p, h, cam != NULL)) {
331 if (cam->w2chandle) {
332 PoolFPrint(p, outf, "worldtocam ");
333 TransStreamOut(p, cam->w2chandle, cam->worldtocam);
334 } else {
335 PoolFPrint(p, outf, "camtoworld ");
336 TransStreamOut(p, cam->c2whandle, cam->camtoworld);
337 }
338 PoolFPrint(p, outf, "perspective %d stereo %d\n",
339 cam->flag & CAMF_PERSP ? 1 : 0,
340 cam->flag & CAMF_STEREO ? 1 : 0);
341 CamGet(cam, CAM_FOV, &fov);
342 PoolFPrint(p, outf, "fov %g\n", fov);
343 PoolFPrint(p, outf, "frameaspect %g\n", cam->frameaspect);
344 PoolFPrint(p, outf, "focus %g\n", cam->focus);
345 PoolFPrint(p, outf, "near %g\n", cam->cnear);
346 PoolFPrint(p, outf, "far %g\n", cam->cfar);
347 if (cam->flag & CAMF_STEREOGEOM) {
348 PoolFPrint(p, outf, "stereo_sep %g\n", cam->stereo_sep);
349 PoolFPrint(p, outf, "stereo_angle %g\n", cam->stereo_angle);
350 }
351 if (cam->flag & CAMF_EYE)
352 PoolFPrint(p, outf, "whicheye %d\n", cam->whicheye);
353 if (cam->flag & CAMF_STEREOXFORM) {
354 PoolFPrint(p, outf, "stereyes\n");
355 TransStreamOut(p, cam->sterhandle[0], cam->stereyes[0]);
356 fputc('\n', outf);
357 TransStreamOut(p, cam->sterhandle[1], cam->stereyes[1]);
358 }
359 PoolFPrint(p, outf, "bgcolor %g %g %g %g\n",
360 cam->bgcolor.r, cam->bgcolor.g, cam->bgcolor.b, cam->bgcolor.a);
361 if (cam->bgimage) {
362 PoolFPrint(p, outf, "bg");
363 ImgStreamOut(p, cam->bgimghandle, cam->bgimage);
364 }
365 }
366 PoolIncLevel(p, -1);
367 PoolFPrint(p, outf, "}\n");
368 return !ferror(outf);
369 }
370
371 void
CamHandleScan(Camera * cam,int (* func)(),void * arg)372 CamHandleScan( Camera *cam, int (*func)(), void *arg )
373 {
374 if (cam) {
375 if (cam->c2whandle)
376 (*func)(&cam->c2whandle, cam, arg);
377 if (cam->w2chandle)
378 (*func)(&cam->w2chandle, cam, arg);
379 }
380 }
381
CamTransUpdate(Handle ** hp,Camera * cam,Transform T)382 void CamTransUpdate(Handle **hp, Camera *cam, Transform T)
383 {
384 TransUpdate(hp, (Ref *)cam, T);
385
386 if (hp == &cam->c2whandle) {
387 TmInvert(cam->camtoworld, cam->worldtocam);
388 } else if (hp == &cam->w2chandle) {
389 TmInvert(cam->worldtocam, cam->camtoworld);
390 }
391 }
392
393 /*
394 * Local Variables: ***
395 * c-basic-offset: 2 ***
396 * End: ***
397 */
398