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