1 |
|
|
/* |
2 |
|
|
Teem: Tools to process and visualize scientific data and images . |
3 |
|
|
Copyright (C) 2013, 2012, 2011, 2010, 2009 University of Chicago |
4 |
|
|
Copyright (C) 2008, 2007, 2006, 2005 Gordon Kindlmann |
5 |
|
|
Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998 University of Utah |
6 |
|
|
|
7 |
|
|
This library is free software; you can redistribute it and/or |
8 |
|
|
modify it under the terms of the GNU Lesser General Public License |
9 |
|
|
(LGPL) as published by the Free Software Foundation; either |
10 |
|
|
version 2.1 of the License, or (at your option) any later version. |
11 |
|
|
The terms of redistributing and/or modifying this software also |
12 |
|
|
include exceptions to the LGPL that facilitate static linking. |
13 |
|
|
|
14 |
|
|
This library is distributed in the hope that it will be useful, |
15 |
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 |
|
|
Lesser General Public License for more details. |
18 |
|
|
|
19 |
|
|
You should have received a copy of the GNU Lesser General Public License |
20 |
|
|
along with this library; if not, write to Free Software Foundation, Inc., |
21 |
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
22 |
|
|
*/ |
23 |
|
|
|
24 |
|
|
|
25 |
|
|
#include "limn.h" |
26 |
|
|
|
27 |
|
|
/* |
28 |
|
|
******** limnCameraUpdate() |
29 |
|
|
** |
30 |
|
|
** sets in cam: W2V, V2W, U, V, N, vspNeer, vspFaar, vspDist |
31 |
|
|
** and, if fov and aspect are set, this also sets uRange and vRange |
32 |
|
|
** |
33 |
|
|
** This does use biff to describe problems with camera settings |
34 |
|
|
*/ |
35 |
|
|
int |
36 |
|
|
limnCameraUpdate(limnCamera *cam) { |
37 |
|
|
static const char me[] = "limnCameraUpdate"; |
38 |
|
|
double len, bb[4], uu[4], vv[4], nn[4], TT[16], RR[16]; |
39 |
|
|
|
40 |
|
|
if (!cam) { |
41 |
|
|
biffAddf(LIMN, "%s: got NULL pointer", me); |
42 |
|
|
return 1; |
43 |
|
|
} |
44 |
|
|
|
45 |
|
|
ELL_4V_SET(uu, 0, 0, 0, 0); |
46 |
|
|
ELL_4V_SET(vv, 0, 0, 0, 0); |
47 |
|
|
ELL_4V_SET(nn, 0, 0, 0, 0); |
48 |
|
|
ELL_4V_SET(bb, 0, 0, 0, 1); |
49 |
|
|
ELL_3V_SUB(nn, cam->at, cam->from); |
50 |
|
|
len = ELL_3V_LEN(nn); |
51 |
|
|
if (!len) { |
52 |
|
|
biffAddf(LIMN, "%s: cam->at (%g,%g,%g) == cam->from", me, |
53 |
|
|
cam->at[0], cam->at[1], cam->at[2]); |
54 |
|
|
return 1; |
55 |
|
|
} |
56 |
|
|
if (cam->atRelative) { |
57 |
|
|
/* ctx->cam->{neer,dist} are "at" relative */ |
58 |
|
|
cam->vspNeer = cam->neer + len; |
59 |
|
|
cam->vspFaar = cam->faar + len; |
60 |
|
|
cam->vspDist = cam->dist + len; |
61 |
|
|
} |
62 |
|
|
else { |
63 |
|
|
/* ctx->cam->{neer,dist} are eye relative */ |
64 |
|
|
cam->vspNeer = cam->neer; |
65 |
|
|
cam->vspFaar = cam->faar; |
66 |
|
|
cam->vspDist = cam->dist; |
67 |
|
|
} |
68 |
|
|
if (!(cam->vspNeer > 0 && cam->vspDist > 0 && cam->vspFaar > 0)) { |
69 |
|
|
biffAddf(LIMN, "%s: eye-relative near (%g), dist (%g), or far (%g) <= 0", |
70 |
|
|
me, cam->vspNeer, cam->vspDist, cam->vspFaar); |
71 |
|
|
return 1; |
72 |
|
|
} |
73 |
|
|
if (!(cam->vspNeer <= cam->vspFaar)) { |
74 |
|
|
biffAddf(LIMN, "%s: eye-relative near (%g) further than far (%g)", |
75 |
|
|
me, cam->vspNeer, cam->vspFaar); |
76 |
|
|
return 1 ; |
77 |
|
|
} |
78 |
|
|
if (AIR_EXISTS(cam->fov)) { |
79 |
|
|
if (!( AIR_IN_OP(0.0, cam->fov, 180.0) )) { |
80 |
|
|
biffAddf(LIMN, "%s: cam->fov (%g) not in valid range between 0 and 180", |
81 |
|
|
me, cam->fov); |
82 |
|
|
return 1 ; |
83 |
|
|
} |
84 |
|
|
if (!AIR_EXISTS(cam->aspect)) { |
85 |
|
|
biffAddf(LIMN, "%s: cam->fov set, but cam->aspect isn't", me); |
86 |
|
|
return 1; |
87 |
|
|
} |
88 |
|
|
/* "fov" is half vertical angle */ |
89 |
|
|
cam->vRange[0] = -tan(cam->fov*AIR_PI/360)*(cam->vspDist); |
90 |
|
|
cam->vRange[1] = -cam->vRange[0]; |
91 |
|
|
cam->uRange[0] = cam->vRange[0]*(cam->aspect); |
92 |
|
|
cam->uRange[1] = -cam->uRange[0]; |
93 |
|
|
} |
94 |
|
|
/* else cam->fov isn't set, but we're not going to complain if |
95 |
|
|
uRange and vRange aren't both set ... */ |
96 |
|
|
|
97 |
|
|
ELL_3V_SCALE(nn, 1.0/len, nn); |
98 |
|
|
ELL_3V_CROSS(uu, nn, cam->up); |
99 |
|
|
len = ELL_3V_LEN(uu); |
100 |
|
|
if (!len) { |
101 |
|
|
biffAddf(LIMN, "%s: cam->up is co-linear with view direction", me); |
102 |
|
|
return 1 ; |
103 |
|
|
} |
104 |
|
|
ELL_3V_SCALE(uu, 1.0/len, uu); |
105 |
|
|
|
106 |
|
|
if (cam->rightHanded) { |
107 |
|
|
ELL_3V_CROSS(vv, nn, uu); |
108 |
|
|
} |
109 |
|
|
else { |
110 |
|
|
ELL_3V_CROSS(vv, uu, nn); |
111 |
|
|
} |
112 |
|
|
|
113 |
|
|
ELL_4V_COPY(cam->U, uu); |
114 |
|
|
ELL_4V_COPY(cam->V, vv); |
115 |
|
|
ELL_4V_COPY(cam->N, nn); |
116 |
|
|
ELL_4M_TRANSLATE_SET(TT, -cam->from[0], -cam->from[1], -cam->from[2]); |
117 |
|
|
ELL_4M_ROWS_SET(RR, uu, vv, nn, bb); |
118 |
|
|
ELL_4M_MUL(cam->W2V, RR, TT); |
119 |
|
|
ell_4m_inv_d(cam->V2W, cam->W2V); |
120 |
|
|
|
121 |
|
|
return 0; |
122 |
|
|
} |
123 |
|
|
|
124 |
|
|
/* |
125 |
|
|
******** limnCameraAspectSet |
126 |
|
|
** |
127 |
|
|
** simply sets the "aspect" field of the cam. Note that calling this |
128 |
|
|
** does *not* automatically mean that the uRange and vRange in the camera |
129 |
|
|
** will be set according to the "fov"- the "fov" has to actually be set |
130 |
|
|
** (be non-NaN) for that to happen. This allows dumber functions to |
131 |
|
|
** call this whenever they have the information required to do so, even |
132 |
|
|
** if the "aspect" is not going to be needed for a given camera use |
133 |
|
|
*/ |
134 |
|
|
int |
135 |
|
|
limnCameraAspectSet(limnCamera *cam, unsigned int horz, unsigned int vert, |
136 |
|
|
int centering) { |
137 |
|
|
static const char me[] = "limnCameraAspectSet"; |
138 |
|
|
|
139 |
|
|
if (!cam) { |
140 |
|
|
biffAddf(LIMN, "%s: got NULL pointer", me); |
141 |
|
|
return 1; |
142 |
|
|
} |
143 |
|
|
if (!( horz > 0 && vert > 0 )) { |
144 |
|
|
biffAddf(LIMN, "%s: bad image dimensions %ux%u", me, horz, vert); |
145 |
|
|
return 1; |
146 |
|
|
} |
147 |
|
|
if (airEnumValCheck(nrrdCenter, centering)) { |
148 |
|
|
biffAddf(LIMN, "%s: centering %d not valid", me, centering); |
149 |
|
|
return 1; |
150 |
|
|
} |
151 |
|
|
|
152 |
|
|
if (nrrdCenterCell == centering) { |
153 |
|
|
cam->aspect = ((double)horz)/vert; |
154 |
|
|
} else { |
155 |
|
|
cam->aspect = ((double)(horz-1))/(vert-1); |
156 |
|
|
} |
157 |
|
|
|
158 |
|
|
return 0; |
159 |
|
|
} |
160 |
|
|
|
161 |
|
|
/* |
162 |
|
|
******** limnCameraPathMake |
163 |
|
|
** |
164 |
|
|
** uses limnSplines to do camera paths based on key-frames |
165 |
|
|
** |
166 |
|
|
** output: cameras at all "numFrames" frames are set in the |
167 |
|
|
** PRE-ALLOCATED array of output cameras, "cam". |
168 |
|
|
** |
169 |
|
|
** input: |
170 |
|
|
** keycam: array of keyframe cameras |
171 |
|
|
** time: times associated with the key frames |
172 |
|
|
** ---> both of these arrays are length "numKeys" <--- |
173 |
|
|
** trackWhat: takes values from the limnCameraPathTrack* enum |
174 |
|
|
** quatType: spline to control camera orientations. This is needed for |
175 |
|
|
** tracking at or from, but not needed for limnCameraPathTrackBoth. |
176 |
|
|
** This is the only limnSplineTypeSpec* argument that can be NULL. |
177 |
|
|
** posType: spline to control whichever of from, at, and up are needed for |
178 |
|
|
** the given style of tracking. |
179 |
|
|
** distType: spline to control neer, faar, dist: positions of near clipping, |
180 |
|
|
** far clipping, and image plane, as well as the |
181 |
|
|
** distance between from and at (which is used if not doing |
182 |
|
|
** limnCameraPathTrackBoth) |
183 |
|
|
** viewType: spline to control fov (and aspect, if you're crazy) |
184 |
|
|
** |
185 |
|
|
** NOTE: The "atRelative", "orthographic", and "rightHanded" fields |
186 |
|
|
** are copied from keycam[0] into all output cam[i], but you still need |
187 |
|
|
** to correctly set them for all keycam[i] for limnCameraUpdate to work |
188 |
|
|
** as expected. Also, for the sake of simplicity, this function only works |
189 |
|
|
** with fov and aspect, instead of {u,v}Range, and hence both "fov" and |
190 |
|
|
** "aspect" need to set in *all* the keycams, even if neither of them |
191 |
|
|
** ever changes! |
192 |
|
|
*/ |
193 |
|
|
int |
194 |
|
|
limnCameraPathMake(limnCamera *cam, int numFrames, |
195 |
|
|
limnCamera *keycam, double *time, int numKeys, |
196 |
|
|
int trackWhat, |
197 |
|
|
limnSplineTypeSpec *quatType, |
198 |
|
|
limnSplineTypeSpec *posType, |
199 |
|
|
limnSplineTypeSpec *distType, |
200 |
|
|
limnSplineTypeSpec *viewType) { |
201 |
|
|
static const char me[]="limnCameraPathMake"; |
202 |
|
|
char which[AIR_STRLEN_MED]; |
203 |
|
|
airArray *mop; |
204 |
|
|
Nrrd *nquat, *nfrom, *natpt, *nupvc, *ndist, *nfova, *ntime, *nsample; |
205 |
|
|
double fratVec[3], *quat, *from, *atpt, *upvc, *dist, *fova, |
206 |
|
|
W2V[9], N[3], fratDist; |
207 |
|
|
limnSpline *timeSpline, *quatSpline, *fromSpline, *atptSpline, *upvcSpline, |
208 |
|
|
*distSpline, *fovaSpline; |
209 |
|
|
limnSplineTypeSpec *timeType; |
210 |
|
|
int ii, E; |
211 |
|
|
|
212 |
|
|
if (!( cam && keycam && time && posType && distType && viewType )) { |
213 |
|
|
biffAddf(LIMN, "%s: got NULL pointer", me); |
214 |
|
|
return 1; |
215 |
|
|
} |
216 |
|
|
if (!( AIR_IN_OP(limnCameraPathTrackUnknown, trackWhat, |
217 |
|
|
limnCameraPathTrackLast) )) { |
218 |
|
|
biffAddf(LIMN, "%s: trackWhat %d not in valid range [%d,%d]", me, |
219 |
|
|
trackWhat, limnCameraPathTrackUnknown+1, |
220 |
|
|
limnCameraPathTrackLast-1); |
221 |
|
|
return 1; |
222 |
|
|
} |
223 |
|
|
if (limnCameraPathTrackBoth != trackWhat && !quatType) { |
224 |
|
|
biffAddf(LIMN, "%s: need the quaternion limnSplineTypeSpec if not " |
225 |
|
|
"doing trackBoth", me); |
226 |
|
|
return 1; |
227 |
|
|
} |
228 |
|
|
|
229 |
|
|
/* create and allocate nrrds. For the time being, we're allocating |
230 |
|
|
more different nrrds, and filling their contents, than we need |
231 |
|
|
to-- nquat is not needed if we're doing limnCameraPathTrackBoth, |
232 |
|
|
for example. However, we do make an effort to only do the spline |
233 |
|
|
evaluation on the things we actually need to know. */ |
234 |
|
|
mop = airMopNew(); |
235 |
|
|
airMopAdd(mop, nquat = nrrdNew(), (airMopper)nrrdNuke, airMopAlways); |
236 |
|
|
airMopAdd(mop, nfrom = nrrdNew(), (airMopper)nrrdNuke, airMopAlways); |
237 |
|
|
airMopAdd(mop, natpt = nrrdNew(), (airMopper)nrrdNuke, airMopAlways); |
238 |
|
|
airMopAdd(mop, nupvc = nrrdNew(), (airMopper)nrrdNuke, airMopAlways); |
239 |
|
|
airMopAdd(mop, ndist = nrrdNew(), (airMopper)nrrdNuke, airMopAlways); |
240 |
|
|
airMopAdd(mop, nfova = nrrdNew(), (airMopper)nrrdNuke, airMopAlways); |
241 |
|
|
airMopAdd(mop, ntime = nrrdNew(), (airMopper)nrrdNix, airMopAlways); |
242 |
|
|
if (nrrdWrap_va(ntime, time, nrrdTypeDouble, 1, |
243 |
|
|
AIR_CAST(size_t, numKeys))) { |
244 |
|
|
biffMovef(LIMN, NRRD, "%s: trouble wrapping time values", me); |
245 |
|
|
airMopError(mop); return 1; |
246 |
|
|
} |
247 |
|
|
airMopAdd(mop, nsample = nrrdNew(), (airMopper)nrrdNuke, airMopAlways); |
248 |
|
|
timeType = limnSplineTypeSpecNew(limnSplineTypeTimeWarp); |
249 |
|
|
airMopAdd(mop, timeType, (airMopper)limnSplineTypeSpecNix, airMopAlways); |
250 |
|
|
if (nrrdMaybeAlloc_va(nquat, nrrdTypeDouble, 2, |
251 |
|
|
AIR_CAST(size_t, 4), AIR_CAST(size_t, numKeys)) |
252 |
|
|
|| nrrdMaybeAlloc_va(nfrom, nrrdTypeDouble, 2, |
253 |
|
|
AIR_CAST(size_t, 3), AIR_CAST(size_t, numKeys)) |
254 |
|
|
|| nrrdMaybeAlloc_va(natpt, nrrdTypeDouble, 2, |
255 |
|
|
AIR_CAST(size_t, 3), AIR_CAST(size_t, numKeys)) |
256 |
|
|
|| nrrdMaybeAlloc_va(nupvc, nrrdTypeDouble, 2, |
257 |
|
|
AIR_CAST(size_t, 3), AIR_CAST(size_t, numKeys)) |
258 |
|
|
|| nrrdMaybeAlloc_va(ndist, nrrdTypeDouble, 2, |
259 |
|
|
AIR_CAST(size_t, 4), AIR_CAST(size_t, numKeys)) |
260 |
|
|
|| nrrdMaybeAlloc_va(nfova, nrrdTypeDouble, 2, |
261 |
|
|
AIR_CAST(size_t, 2), AIR_CAST(size_t, numKeys))) { |
262 |
|
|
biffMovef(LIMN, NRRD, "%s: couldn't allocate buffer nrrds", me); |
263 |
|
|
airMopError(mop); return 1; |
264 |
|
|
} |
265 |
|
|
quat = (double*)(nquat->data); |
266 |
|
|
from = (double*)(nfrom->data); |
267 |
|
|
atpt = (double*)(natpt->data); |
268 |
|
|
upvc = (double*)(nupvc->data); |
269 |
|
|
dist = (double*)(ndist->data); |
270 |
|
|
fova = (double*)(nfova->data); |
271 |
|
|
|
272 |
|
|
/* check cameras, and put camera information into nrrds */ |
273 |
|
|
for (ii=0; ii<numKeys; ii++) { |
274 |
|
|
if (limnCameraUpdate(keycam + ii)) { |
275 |
|
|
biffAddf(LIMN, "%s: trouble with camera at keyframe %d\n", me, ii); |
276 |
|
|
airMopError(mop); return 1; |
277 |
|
|
} |
278 |
|
|
if (!( AIR_EXISTS(keycam[ii].fov) && AIR_EXISTS(keycam[ii].aspect) )) { |
279 |
|
|
biffAddf(LIMN, "%s: fov, aspect not both defined on keyframe %d", |
280 |
|
|
me, ii); |
281 |
|
|
airMopError(mop); return 1; |
282 |
|
|
} |
283 |
|
|
ell_4m_to_q_d(quat + 4*ii, keycam[ii].W2V); |
284 |
|
|
if (ii) { |
285 |
|
|
if (0 > ELL_4V_DOT(quat + 4*ii, quat + 4*(ii-1))) { |
286 |
|
|
ELL_4V_SCALE(quat + 4*ii, -1, quat + 4*ii); |
287 |
|
|
} |
288 |
|
|
} |
289 |
|
|
ELL_3V_COPY(from + 3*ii, keycam[ii].from); |
290 |
|
|
ELL_3V_COPY(atpt + 3*ii, keycam[ii].at); |
291 |
|
|
ELL_3V_COPY(upvc + 3*ii, keycam[ii].up); |
292 |
|
|
ELL_3V_SUB(fratVec, keycam[ii].from, keycam[ii].at); |
293 |
|
|
fratDist = ELL_3V_LEN(fratVec); |
294 |
|
|
ELL_4V_SET(dist + 4*ii, fratDist, |
295 |
|
|
keycam[ii].neer, keycam[ii].dist, keycam[ii].faar); |
296 |
|
|
ELL_2V_SET(fova + 2*ii, keycam[ii].fov, keycam[ii].aspect); |
297 |
|
|
} |
298 |
|
|
|
299 |
|
|
/* create splines from nrrds */ |
300 |
|
|
if (!( (strcpy(which, "quaternion"), quatSpline = |
301 |
|
|
limnSplineCleverNew(nquat, limnSplineInfoQuaternion, quatType)) |
302 |
|
|
&& (strcpy(which, "from point"), fromSpline = |
303 |
|
|
limnSplineCleverNew(nfrom, limnSplineInfo3Vector, posType)) |
304 |
|
|
&& (strcpy(which, "at point"), atptSpline = |
305 |
|
|
limnSplineCleverNew(natpt, limnSplineInfo3Vector, posType)) |
306 |
|
|
&& (strcpy(which, "up vector"), upvcSpline = |
307 |
|
|
limnSplineCleverNew(nupvc, limnSplineInfo3Vector, posType)) |
308 |
|
|
&& (strcpy(which, "plane distances"), distSpline = |
309 |
|
|
limnSplineCleverNew(ndist, limnSplineInfo4Vector, distType)) |
310 |
|
|
&& (strcpy(which, "field-of-view"), fovaSpline = |
311 |
|
|
limnSplineCleverNew(nfova, limnSplineInfo2Vector, viewType)) |
312 |
|
|
&& (strcpy(which, "time warp"), timeSpline = |
313 |
|
|
limnSplineCleverNew(ntime, limnSplineInfoScalar, timeType)) )) { |
314 |
|
|
biffAddf(LIMN, "%s: trouble creating %s spline", me, which); |
315 |
|
|
airMopError(mop); return 1; |
316 |
|
|
} |
317 |
|
|
airMopAdd(mop, quatSpline, (airMopper)limnSplineNix, airMopAlways); |
318 |
|
|
airMopAdd(mop, fromSpline, (airMopper)limnSplineNix, airMopAlways); |
319 |
|
|
airMopAdd(mop, atptSpline, (airMopper)limnSplineNix, airMopAlways); |
320 |
|
|
airMopAdd(mop, upvcSpline, (airMopper)limnSplineNix, airMopAlways); |
321 |
|
|
airMopAdd(mop, distSpline, (airMopper)limnSplineNix, airMopAlways); |
322 |
|
|
airMopAdd(mop, fovaSpline, (airMopper)limnSplineNix, airMopAlways); |
323 |
|
|
airMopAdd(mop, timeSpline, (airMopper)limnSplineNix, airMopAlways); |
324 |
|
|
|
325 |
|
|
/* evaluate splines */ |
326 |
|
|
E = AIR_FALSE; |
327 |
|
|
if (!E) E |= limnSplineSample(nsample, timeSpline, |
328 |
|
|
limnSplineMinT(timeSpline), numFrames, |
329 |
|
|
limnSplineMaxT(timeSpline)); |
330 |
|
|
quat = NULL; |
331 |
|
|
from = NULL; |
332 |
|
|
atpt = NULL; |
333 |
|
|
upvc = NULL; |
334 |
|
|
switch(trackWhat) { |
335 |
|
|
case limnCameraPathTrackAt: |
336 |
|
|
if (!E) E |= limnSplineNrrdEvaluate(natpt, atptSpline, nsample); |
337 |
|
|
if (!E) atpt = (double*)(natpt->data); |
338 |
|
|
if (!E) E |= limnSplineNrrdEvaluate(nquat, quatSpline, nsample); |
339 |
|
|
if (!E) quat = (double*)(nquat->data); |
340 |
|
|
break; |
341 |
|
|
case limnCameraPathTrackFrom: |
342 |
|
|
if (!E) E |= limnSplineNrrdEvaluate(nfrom, fromSpline, nsample); |
343 |
|
|
if (!E) from = (double*)(nfrom->data); |
344 |
|
|
if (!E) E |= limnSplineNrrdEvaluate(nquat, quatSpline, nsample); |
345 |
|
|
if (!E) quat = (double*)(nquat->data); |
346 |
|
|
break; |
347 |
|
|
case limnCameraPathTrackBoth: |
348 |
|
|
if (!E) E |= limnSplineNrrdEvaluate(nfrom, fromSpline, nsample); |
349 |
|
|
if (!E) from = (double*)(nfrom->data); |
350 |
|
|
if (!E) E |= limnSplineNrrdEvaluate(natpt, atptSpline, nsample); |
351 |
|
|
if (!E) atpt = (double*)(natpt->data); |
352 |
|
|
if (!E) E |= limnSplineNrrdEvaluate(nupvc, upvcSpline, nsample); |
353 |
|
|
if (!E) upvc = (double*)(nupvc->data); |
354 |
|
|
break; |
355 |
|
|
} |
356 |
|
|
dist = NULL; |
357 |
|
|
if (!E) E |= limnSplineNrrdEvaluate(ndist, distSpline, nsample); |
358 |
|
|
if (!E) dist = (double*)(ndist->data); |
359 |
|
|
fova = NULL; |
360 |
|
|
if (!E) E |= limnSplineNrrdEvaluate(nfova, fovaSpline, nsample); |
361 |
|
|
if (!E) fova = (double*)(nfova->data); |
362 |
|
|
if (E) { |
363 |
|
|
biffAddf(LIMN, "%s: trouble evaluating splines", me); |
364 |
|
|
airMopError(mop); return 1; |
365 |
|
|
} |
366 |
|
|
|
367 |
|
|
/* copy information from nrrds back into cameras */ |
368 |
|
|
for (ii=0; ii<numFrames; ii++) { |
369 |
|
|
cam[ii].atRelative = keycam[0].atRelative; |
370 |
|
|
cam[ii].orthographic = keycam[0].orthographic; |
371 |
|
|
cam[ii].rightHanded = keycam[0].rightHanded; |
372 |
|
|
if (limnCameraPathTrackBoth == trackWhat) { |
373 |
|
|
ELL_3V_COPY(cam[ii].from, from + 3*ii); |
374 |
|
|
ELL_3V_COPY(cam[ii].at, atpt + 3*ii); |
375 |
|
|
ELL_3V_COPY(cam[ii].up, upvc + 3*ii); |
376 |
|
|
} else { |
377 |
|
|
fratDist = (dist + 4*ii)[0]; |
378 |
|
|
ell_q_to_3m_d(W2V, quat + 4*ii); |
379 |
|
|
ELL_3MV_ROW1_GET(cam[ii].up, W2V); |
380 |
|
|
if (cam[ii].rightHanded) { |
381 |
|
|
ELL_3V_SCALE(cam[ii].up, -1, cam[ii].up); |
382 |
|
|
} |
383 |
|
|
ELL_3MV_ROW2_GET(N, W2V); |
384 |
|
|
if (limnCameraPathTrackFrom == trackWhat) { |
385 |
|
|
ELL_3V_COPY(cam[ii].from, from + 3*ii); |
386 |
|
|
ELL_3V_SCALE_ADD2(cam[ii].at, 1.0, cam[ii].from, fratDist, N); |
387 |
|
|
} else { |
388 |
|
|
ELL_3V_COPY(cam[ii].at, atpt + 3*ii); |
389 |
|
|
ELL_3V_SCALE_ADD2(cam[ii].from, 1.0, cam[ii].at, -fratDist, N); |
390 |
|
|
} |
391 |
|
|
} |
392 |
|
|
cam[ii].neer = (dist + 4*ii)[1]; |
393 |
|
|
cam[ii].dist = (dist + 4*ii)[2]; |
394 |
|
|
cam[ii].faar = (dist + 4*ii)[3]; |
395 |
|
|
cam[ii].fov = (fova + 2*ii)[0]; |
396 |
|
|
cam[ii].aspect = (fova + 2*ii)[1]; |
397 |
|
|
if (limnCameraUpdate(cam + ii)) { |
398 |
|
|
biffAddf(LIMN, "%s: trouble with output camera %d\n", me, ii); |
399 |
|
|
airMopError(mop); return 1; |
400 |
|
|
} |
401 |
|
|
} |
402 |
|
|
|
403 |
|
|
airMopOkay(mop); |
404 |
|
|
return 0; |
405 |
|
|
} |