sl@0
|
1 |
/*
|
sl@0
|
2 |
* Copyright (c) 2003 Nokia Corporation and/or its subsidiary(-ies).
|
sl@0
|
3 |
* All rights reserved.
|
sl@0
|
4 |
* This component and the accompanying materials are made available
|
sl@0
|
5 |
* under the terms of the License "Eclipse Public License v1.0"
|
sl@0
|
6 |
* which accompanies this distribution, and is available
|
sl@0
|
7 |
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
|
sl@0
|
8 |
*
|
sl@0
|
9 |
* Initial Contributors:
|
sl@0
|
10 |
* Nokia Corporation - initial contribution.
|
sl@0
|
11 |
*
|
sl@0
|
12 |
* Contributors:
|
sl@0
|
13 |
*
|
sl@0
|
14 |
* Description: Camera implementation
|
sl@0
|
15 |
*
|
sl@0
|
16 |
*/
|
sl@0
|
17 |
|
sl@0
|
18 |
|
sl@0
|
19 |
/*!
|
sl@0
|
20 |
* \internal
|
sl@0
|
21 |
* \file
|
sl@0
|
22 |
* \brief Camera implementation
|
sl@0
|
23 |
*/
|
sl@0
|
24 |
|
sl@0
|
25 |
#ifndef M3G_CORE_INCLUDE
|
sl@0
|
26 |
# error included by m3g_core.c; do not compile separately.
|
sl@0
|
27 |
#endif
|
sl@0
|
28 |
|
sl@0
|
29 |
#include "m3g_camera.h"
|
sl@0
|
30 |
|
sl@0
|
31 |
/* Internal frustum plane enumeration (and testing order!) */
|
sl@0
|
32 |
|
sl@0
|
33 |
#define NEAR_PLANE 0
|
sl@0
|
34 |
#define FAR_PLANE 1
|
sl@0
|
35 |
#define LEFT_PLANE 2
|
sl@0
|
36 |
#define RIGHT_PLANE 3
|
sl@0
|
37 |
#define BOTTOM_PLANE 4
|
sl@0
|
38 |
#define TOP_PLANE 5
|
sl@0
|
39 |
|
sl@0
|
40 |
/*----------------------------------------------------------------------
|
sl@0
|
41 |
* Private functions
|
sl@0
|
42 |
*--------------------------------------------------------------------*/
|
sl@0
|
43 |
|
sl@0
|
44 |
/*!
|
sl@0
|
45 |
* \internal
|
sl@0
|
46 |
* \brief Makes sure that the internal projection matrix is up-to-date
|
sl@0
|
47 |
* and checks if the camera has a zero view volume.
|
sl@0
|
48 |
*/
|
sl@0
|
49 |
static void m3gValidateProjectionMatrix(Camera *camera)
|
sl@0
|
50 |
{
|
sl@0
|
51 |
M3Gint projType = camera->projType;
|
sl@0
|
52 |
|
sl@0
|
53 |
/* The generic matrix is always valid, but for perspective and
|
sl@0
|
54 |
* parallel we must regenerate the matrix */
|
sl@0
|
55 |
|
sl@0
|
56 |
if (projType != M3G_GENERIC) {
|
sl@0
|
57 |
M3Gfloat m[16];
|
sl@0
|
58 |
|
sl@0
|
59 |
M3Gfloat clipNear = camera->clipNear;
|
sl@0
|
60 |
M3Gfloat clipFar = camera->clipFar;
|
sl@0
|
61 |
|
sl@0
|
62 |
if (projType == M3G_PERSPECTIVE) {
|
sl@0
|
63 |
|
sl@0
|
64 |
M3Gfloat height = m3gTan(m3gMul(M3G_DEG2RAD * 0.5f,
|
sl@0
|
65 |
camera->heightFov));
|
sl@0
|
66 |
|
sl@0
|
67 |
m[0] = m3gRcp(m3gMul(camera->aspect, height));
|
sl@0
|
68 |
m[1] = m[2] = m[3] = 0.f;
|
sl@0
|
69 |
|
sl@0
|
70 |
m[4] = 0.f;
|
sl@0
|
71 |
m[5] = m3gRcp(height);
|
sl@0
|
72 |
m[6] = m[7] = 0.f;
|
sl@0
|
73 |
|
sl@0
|
74 |
m[8] = m[9] = 0.f;
|
sl@0
|
75 |
m[10] = m3gDiv(-m3gAdd(clipFar, clipNear),
|
sl@0
|
76 |
m3gSub(clipFar, clipNear));
|
sl@0
|
77 |
m[11] = -1.f;
|
sl@0
|
78 |
|
sl@0
|
79 |
m[12] = m[13] = 0.f;
|
sl@0
|
80 |
m[14] = m3gDiv(m3gMul(m3gMul(-2.f, clipFar), clipNear),
|
sl@0
|
81 |
m3gSub(clipFar, clipNear));
|
sl@0
|
82 |
m[15] = 0.f;
|
sl@0
|
83 |
}
|
sl@0
|
84 |
else if (projType == M3G_PARALLEL) {
|
sl@0
|
85 |
|
sl@0
|
86 |
M3Gfloat height = camera->heightFov;
|
sl@0
|
87 |
|
sl@0
|
88 |
m[0] = m3gDiv(2.f, m3gMul(camera->aspect, height));
|
sl@0
|
89 |
m[1] = m[2] = m[3] = 0.f;
|
sl@0
|
90 |
|
sl@0
|
91 |
m[4] = 0.f;
|
sl@0
|
92 |
m[5] = m3gDiv(2.f, height);
|
sl@0
|
93 |
m[6] = m[7] = 0;
|
sl@0
|
94 |
|
sl@0
|
95 |
m[8] = m[9] = 0;
|
sl@0
|
96 |
m[10] = m3gDiv(-2.f, m3gSub(clipFar, clipNear));
|
sl@0
|
97 |
m[11] = 0.f;
|
sl@0
|
98 |
|
sl@0
|
99 |
m[12] = m[13] = 0.f;
|
sl@0
|
100 |
m[14] = m3gDiv(-m3gAdd(clipFar, clipNear),
|
sl@0
|
101 |
m3gSub(clipFar, clipNear));
|
sl@0
|
102 |
m[15] = 1.f;
|
sl@0
|
103 |
}
|
sl@0
|
104 |
else {
|
sl@0
|
105 |
M3G_ASSERT(M3G_FALSE); /* unknown projection type! */
|
sl@0
|
106 |
}
|
sl@0
|
107 |
m3gSetMatrixColumns(&camera->projMatrix, m);
|
sl@0
|
108 |
}
|
sl@0
|
109 |
|
sl@0
|
110 |
{
|
sl@0
|
111 |
M3GMatrix im;
|
sl@0
|
112 |
if (!m3gMatrixInverse(&im, &camera->projMatrix)) {
|
sl@0
|
113 |
camera->zeroViewVolume = M3G_TRUE;
|
sl@0
|
114 |
}
|
sl@0
|
115 |
else {
|
sl@0
|
116 |
camera->zeroViewVolume = M3G_FALSE;
|
sl@0
|
117 |
}
|
sl@0
|
118 |
}
|
sl@0
|
119 |
|
sl@0
|
120 |
camera->frustumPlanesValid = M3G_FALSE;
|
sl@0
|
121 |
}
|
sl@0
|
122 |
|
sl@0
|
123 |
/*!
|
sl@0
|
124 |
* \internal
|
sl@0
|
125 |
* \brief Validates the cached view frustum planes
|
sl@0
|
126 |
*/
|
sl@0
|
127 |
static void m3gValidateFrustumPlanes(Camera *camera)
|
sl@0
|
128 |
{
|
sl@0
|
129 |
if (!camera->frustumPlanesValid) {
|
sl@0
|
130 |
Vec4 *plane;
|
sl@0
|
131 |
Vec4 rows[4];
|
sl@0
|
132 |
|
sl@0
|
133 |
m3gGetMatrixRows(&camera->projMatrix, (M3Gfloat*) rows);
|
sl@0
|
134 |
|
sl@0
|
135 |
plane = &camera->frustumPlanes[LEFT_PLANE];
|
sl@0
|
136 |
*plane = rows[3];
|
sl@0
|
137 |
m3gAddVec4(plane, &rows[0]);
|
sl@0
|
138 |
|
sl@0
|
139 |
plane = &camera->frustumPlanes[RIGHT_PLANE];
|
sl@0
|
140 |
*plane = rows[3];
|
sl@0
|
141 |
m3gSubVec4(plane, &rows[0]);
|
sl@0
|
142 |
|
sl@0
|
143 |
plane = &camera->frustumPlanes[BOTTOM_PLANE];
|
sl@0
|
144 |
*plane = rows[3];
|
sl@0
|
145 |
m3gAddVec4(plane, &rows[1]);
|
sl@0
|
146 |
|
sl@0
|
147 |
plane = &camera->frustumPlanes[TOP_PLANE];
|
sl@0
|
148 |
*plane = rows[3];
|
sl@0
|
149 |
m3gSubVec4(plane, &rows[1]);
|
sl@0
|
150 |
|
sl@0
|
151 |
plane = &camera->frustumPlanes[NEAR_PLANE];
|
sl@0
|
152 |
*plane = rows[3];
|
sl@0
|
153 |
m3gAddVec4(plane, &rows[2]);
|
sl@0
|
154 |
|
sl@0
|
155 |
plane = &camera->frustumPlanes[FAR_PLANE];
|
sl@0
|
156 |
*plane = rows[3];
|
sl@0
|
157 |
m3gSubVec4(plane, &rows[2]);
|
sl@0
|
158 |
|
sl@0
|
159 |
camera->frustumPlanesValid = M3G_TRUE;
|
sl@0
|
160 |
}
|
sl@0
|
161 |
}
|
sl@0
|
162 |
|
sl@0
|
163 |
#undef NEAR_PLANE
|
sl@0
|
164 |
#undef FAR_PLANE
|
sl@0
|
165 |
#undef LEFT_PLANE
|
sl@0
|
166 |
#undef RIGHT_PLANE
|
sl@0
|
167 |
#undef BOTTOM_PLANE
|
sl@0
|
168 |
#undef TOP_PLANE
|
sl@0
|
169 |
|
sl@0
|
170 |
/*----------------------------------------------------------------------
|
sl@0
|
171 |
* Internal functions
|
sl@0
|
172 |
*--------------------------------------------------------------------*/
|
sl@0
|
173 |
|
sl@0
|
174 |
/*!
|
sl@0
|
175 |
* \internal
|
sl@0
|
176 |
* \brief Overloaded Object3D method.
|
sl@0
|
177 |
*
|
sl@0
|
178 |
* \param property animation property
|
sl@0
|
179 |
* \retval M3G_TRUE property supported
|
sl@0
|
180 |
* \retval M3G_FALSE property not supported
|
sl@0
|
181 |
*/
|
sl@0
|
182 |
static M3Gbool m3gCameraIsCompatible(M3Gint property)
|
sl@0
|
183 |
{
|
sl@0
|
184 |
switch (property) {
|
sl@0
|
185 |
case M3G_ANIM_FAR_DISTANCE:
|
sl@0
|
186 |
case M3G_ANIM_FIELD_OF_VIEW:
|
sl@0
|
187 |
case M3G_ANIM_NEAR_DISTANCE:
|
sl@0
|
188 |
return M3G_TRUE;
|
sl@0
|
189 |
default:
|
sl@0
|
190 |
return m3gNodeIsCompatible(property);
|
sl@0
|
191 |
}
|
sl@0
|
192 |
}
|
sl@0
|
193 |
|
sl@0
|
194 |
/*!
|
sl@0
|
195 |
* \internal
|
sl@0
|
196 |
* \brief Overloaded Object3D method.
|
sl@0
|
197 |
*
|
sl@0
|
198 |
* \param obj Camera object
|
sl@0
|
199 |
* \param property animation property
|
sl@0
|
200 |
* \param valueSize size of value array
|
sl@0
|
201 |
* \param value value array
|
sl@0
|
202 |
*/
|
sl@0
|
203 |
static void m3gCameraUpdateProperty(Object *obj,
|
sl@0
|
204 |
M3Gint property,
|
sl@0
|
205 |
M3Gint valueSize,
|
sl@0
|
206 |
const M3Gfloat *value)
|
sl@0
|
207 |
{
|
sl@0
|
208 |
Camera *camera = (Camera *) obj;
|
sl@0
|
209 |
M3G_VALIDATE_OBJECT(camera);
|
sl@0
|
210 |
M3G_ASSERT_PTR(value);
|
sl@0
|
211 |
|
sl@0
|
212 |
switch (property) {
|
sl@0
|
213 |
case M3G_ANIM_FAR_DISTANCE:
|
sl@0
|
214 |
M3G_ASSERT(valueSize >= 1);
|
sl@0
|
215 |
camera->clipFar = (camera->projType == M3G_PERSPECTIVE)
|
sl@0
|
216 |
? m3gClampFloatPositive(value[0])
|
sl@0
|
217 |
: value[0];
|
sl@0
|
218 |
break;
|
sl@0
|
219 |
case M3G_ANIM_FIELD_OF_VIEW:
|
sl@0
|
220 |
M3G_ASSERT(valueSize >= 1);
|
sl@0
|
221 |
camera->heightFov = (camera->projType == M3G_PERSPECTIVE)
|
sl@0
|
222 |
? m3gClampFloat(value[0], 0.f, 180.f)
|
sl@0
|
223 |
: m3gClampFloatPositive(value[0]);
|
sl@0
|
224 |
break;
|
sl@0
|
225 |
case M3G_ANIM_NEAR_DISTANCE:
|
sl@0
|
226 |
M3G_ASSERT(valueSize >= 1);
|
sl@0
|
227 |
camera->clipNear = (camera->projType == M3G_PERSPECTIVE)
|
sl@0
|
228 |
? m3gClampFloatPositive(value[0])
|
sl@0
|
229 |
: value[0];
|
sl@0
|
230 |
break;
|
sl@0
|
231 |
default:
|
sl@0
|
232 |
m3gNodeUpdateProperty(obj, property, valueSize, value);
|
sl@0
|
233 |
return; /* don't invalidate the matrix */
|
sl@0
|
234 |
}
|
sl@0
|
235 |
|
sl@0
|
236 |
/* Validate the projection matrix if we changed any of the
|
sl@0
|
237 |
* camera parameters */
|
sl@0
|
238 |
|
sl@0
|
239 |
m3gValidateProjectionMatrix(camera);
|
sl@0
|
240 |
}
|
sl@0
|
241 |
|
sl@0
|
242 |
/*!
|
sl@0
|
243 |
* \internal
|
sl@0
|
244 |
* \brief Overloaded Node method.
|
sl@0
|
245 |
*
|
sl@0
|
246 |
* Start render setup scene traversal.
|
sl@0
|
247 |
*
|
sl@0
|
248 |
* \param node Camera object
|
sl@0
|
249 |
* \param toCamera transform to camera
|
sl@0
|
250 |
* \param alphaFactor total alpha factor
|
sl@0
|
251 |
* \param caller caller node
|
sl@0
|
252 |
* \param renderQueue RenderQueue
|
sl@0
|
253 |
*
|
sl@0
|
254 |
* \retval M3G_TRUE continue render setup
|
sl@0
|
255 |
* \retval M3G_FALSE abort render setup
|
sl@0
|
256 |
*/
|
sl@0
|
257 |
static M3Gbool m3gCameraSetupRender(Node *self,
|
sl@0
|
258 |
const Node *caller,
|
sl@0
|
259 |
SetupRenderState *s,
|
sl@0
|
260 |
RenderQueue *renderQueue)
|
sl@0
|
261 |
{
|
sl@0
|
262 |
Node *parent;
|
sl@0
|
263 |
M3Gbool success = M3G_TRUE;
|
sl@0
|
264 |
|
sl@0
|
265 |
/* Just do the parent node. Note that we won't be needing the old
|
sl@0
|
266 |
* state back after going up the tree, so we can overwrite it. */
|
sl@0
|
267 |
|
sl@0
|
268 |
parent = self->parent;
|
sl@0
|
269 |
|
sl@0
|
270 |
if (caller != parent && parent != NULL) {
|
sl@0
|
271 |
Matrix t;
|
sl@0
|
272 |
|
sl@0
|
273 |
M3G_BEGIN_PROFILE(M3G_INTERFACE(self), M3G_PROFILE_SETUP_TRANSFORMS);
|
sl@0
|
274 |
if (!m3gGetInverseNodeTransform(self, &t)) {
|
sl@0
|
275 |
return M3G_FALSE;
|
sl@0
|
276 |
}
|
sl@0
|
277 |
m3gMulMatrix(&s->toCamera, &t);
|
sl@0
|
278 |
M3G_END_PROFILE(M3G_INTERFACE(self), M3G_PROFILE_SETUP_TRANSFORMS);
|
sl@0
|
279 |
|
sl@0
|
280 |
/* The parent node will update the alpha factor and culling
|
sl@0
|
281 |
* mask if necessary, so we need not touch those */
|
sl@0
|
282 |
|
sl@0
|
283 |
success = M3G_VFUNC(Node, parent, setupRender)(parent,
|
sl@0
|
284 |
self, s, renderQueue);
|
sl@0
|
285 |
}
|
sl@0
|
286 |
|
sl@0
|
287 |
return success;
|
sl@0
|
288 |
}
|
sl@0
|
289 |
|
sl@0
|
290 |
/*!
|
sl@0
|
291 |
* \internal
|
sl@0
|
292 |
* \brief Overloaded Object3D method.
|
sl@0
|
293 |
*
|
sl@0
|
294 |
* \param originalObj original Camera object
|
sl@0
|
295 |
* \param cloneObj pointer to cloned Camera object
|
sl@0
|
296 |
* \param pairs array for all object-duplicate pairs
|
sl@0
|
297 |
* \param numPairs number of pairs
|
sl@0
|
298 |
*/
|
sl@0
|
299 |
static M3Gbool m3gCameraDuplicate(const Object *originalObj,
|
sl@0
|
300 |
Object **cloneObj,
|
sl@0
|
301 |
Object **pairs,
|
sl@0
|
302 |
M3Gint *numPairs)
|
sl@0
|
303 |
{
|
sl@0
|
304 |
Camera *original = (Camera *)originalObj;
|
sl@0
|
305 |
Camera *clone = (Camera *)m3gCreateCamera(originalObj->interface);
|
sl@0
|
306 |
*cloneObj = (Object *)clone;
|
sl@0
|
307 |
if (*cloneObj == NULL) {
|
sl@0
|
308 |
return M3G_FALSE;
|
sl@0
|
309 |
}
|
sl@0
|
310 |
|
sl@0
|
311 |
if (m3gNodeDuplicate(originalObj, cloneObj, pairs, numPairs)) {
|
sl@0
|
312 |
clone->projType = original->projType;
|
sl@0
|
313 |
clone->projMatrix = original->projMatrix;
|
sl@0
|
314 |
clone->heightFov = original->heightFov;
|
sl@0
|
315 |
clone->aspect = original->aspect;
|
sl@0
|
316 |
clone->clipNear = original->clipNear;
|
sl@0
|
317 |
clone->clipFar = original->clipFar;
|
sl@0
|
318 |
clone->zeroViewVolume = original->zeroViewVolume;
|
sl@0
|
319 |
return M3G_TRUE;
|
sl@0
|
320 |
}
|
sl@0
|
321 |
else {
|
sl@0
|
322 |
return M3G_FALSE;
|
sl@0
|
323 |
}
|
sl@0
|
324 |
}
|
sl@0
|
325 |
|
sl@0
|
326 |
/*!
|
sl@0
|
327 |
* \internal
|
sl@0
|
328 |
* \brief Initializes a Camera object. See specification
|
sl@0
|
329 |
* for default values.
|
sl@0
|
330 |
*
|
sl@0
|
331 |
* \param m3g M3G interface
|
sl@0
|
332 |
* \param camera Camera object
|
sl@0
|
333 |
*/
|
sl@0
|
334 |
static void m3gInitCamera(Interface *m3g, Camera *camera)
|
sl@0
|
335 |
{
|
sl@0
|
336 |
M3GMatrix m;
|
sl@0
|
337 |
|
sl@0
|
338 |
/* Camera is derived from node */
|
sl@0
|
339 |
m3gInitNode(m3g, &camera->node, M3G_CLASS_CAMERA);
|
sl@0
|
340 |
|
sl@0
|
341 |
/* GENERIC, Identity */
|
sl@0
|
342 |
m3gIdentityMatrix(&m);
|
sl@0
|
343 |
m3gSetProjectionMatrix(camera, (const M3GMatrix *)&m);
|
sl@0
|
344 |
}
|
sl@0
|
345 |
|
sl@0
|
346 |
/*!
|
sl@0
|
347 |
* \internal
|
sl@0
|
348 |
* \brief Sets camera matrix to OpenGL
|
sl@0
|
349 |
* projection matrix.
|
sl@0
|
350 |
*
|
sl@0
|
351 |
* \param camera Camera object
|
sl@0
|
352 |
*/
|
sl@0
|
353 |
static void m3gApplyProjection(const Camera *camera)
|
sl@0
|
354 |
{
|
sl@0
|
355 |
M3Gfloat t[16];
|
sl@0
|
356 |
|
sl@0
|
357 |
m3gGetMatrixColumns(&camera->projMatrix, t);
|
sl@0
|
358 |
|
sl@0
|
359 |
glMatrixMode(GL_PROJECTION);
|
sl@0
|
360 |
glLoadMatrixf(t);
|
sl@0
|
361 |
glMatrixMode(GL_MODELVIEW);
|
sl@0
|
362 |
}
|
sl@0
|
363 |
|
sl@0
|
364 |
/*!
|
sl@0
|
365 |
* \internal
|
sl@0
|
366 |
* \brief Returns a pointer to the camera projection matrix
|
sl@0
|
367 |
*
|
sl@0
|
368 |
* The matrix <em>must not</em> be accessed directly, as only this
|
sl@0
|
369 |
* function will ensure that the returned matrix has valid values in
|
sl@0
|
370 |
* it.
|
sl@0
|
371 |
*
|
sl@0
|
372 |
* \param camera Camera object
|
sl@0
|
373 |
* \return a pointer to the projection matrix
|
sl@0
|
374 |
*/
|
sl@0
|
375 |
static const Matrix *m3gProjectionMatrix(const Camera *camera)
|
sl@0
|
376 |
{
|
sl@0
|
377 |
M3G_VALIDATE_OBJECT(camera);
|
sl@0
|
378 |
|
sl@0
|
379 |
return &camera->projMatrix;
|
sl@0
|
380 |
}
|
sl@0
|
381 |
|
sl@0
|
382 |
/*!
|
sl@0
|
383 |
* \internal
|
sl@0
|
384 |
* \brief Retrieves a pointer to the six camera space view frustum planes
|
sl@0
|
385 |
*/
|
sl@0
|
386 |
static const Vec4 *m3gFrustumPlanes(const Camera *camera)
|
sl@0
|
387 |
{
|
sl@0
|
388 |
M3G_VALIDATE_OBJECT(camera);
|
sl@0
|
389 |
m3gValidateFrustumPlanes((Camera*) camera);
|
sl@0
|
390 |
return camera->frustumPlanes;
|
sl@0
|
391 |
}
|
sl@0
|
392 |
|
sl@0
|
393 |
/*----------------------------------------------------------------------
|
sl@0
|
394 |
* Virtual function table
|
sl@0
|
395 |
*--------------------------------------------------------------------*/
|
sl@0
|
396 |
|
sl@0
|
397 |
static const NodeVFTable m3gvf_Camera = {
|
sl@0
|
398 |
{
|
sl@0
|
399 |
{
|
sl@0
|
400 |
m3gObjectApplyAnimation,
|
sl@0
|
401 |
m3gCameraIsCompatible,
|
sl@0
|
402 |
m3gCameraUpdateProperty,
|
sl@0
|
403 |
m3gObjectDoGetReferences,
|
sl@0
|
404 |
m3gObjectFindID,
|
sl@0
|
405 |
m3gCameraDuplicate,
|
sl@0
|
406 |
m3gDestroyNode /* no extra clean-up for Camera */
|
sl@0
|
407 |
}
|
sl@0
|
408 |
},
|
sl@0
|
409 |
m3gNodeAlign,
|
sl@0
|
410 |
NULL, /* pure virtual DoRender */
|
sl@0
|
411 |
m3gNodeGetBBox,
|
sl@0
|
412 |
m3gNodeRayIntersect,
|
sl@0
|
413 |
m3gCameraSetupRender,
|
sl@0
|
414 |
m3gNodeUpdateDuplicateReferences,
|
sl@0
|
415 |
m3gNodeValidate
|
sl@0
|
416 |
};
|
sl@0
|
417 |
|
sl@0
|
418 |
|
sl@0
|
419 |
/*----------------------------------------------------------------------
|
sl@0
|
420 |
* Public API functions
|
sl@0
|
421 |
*--------------------------------------------------------------------*/
|
sl@0
|
422 |
|
sl@0
|
423 |
/*!
|
sl@0
|
424 |
* \brief Creates a Camera object.
|
sl@0
|
425 |
*
|
sl@0
|
426 |
* \param interface M3G interface
|
sl@0
|
427 |
* \retval Camera new Camera object
|
sl@0
|
428 |
* \retval NULL Camera creating failed
|
sl@0
|
429 |
*/
|
sl@0
|
430 |
M3G_API M3GCamera m3gCreateCamera(M3GInterface interface)
|
sl@0
|
431 |
{
|
sl@0
|
432 |
Interface *m3g = (Interface *) interface;
|
sl@0
|
433 |
M3G_VALIDATE_INTERFACE(m3g);
|
sl@0
|
434 |
|
sl@0
|
435 |
{
|
sl@0
|
436 |
Camera *camera = m3gAllocZ(m3g, sizeof(Camera));
|
sl@0
|
437 |
|
sl@0
|
438 |
if (camera != NULL) {
|
sl@0
|
439 |
m3gInitCamera(m3g, camera);
|
sl@0
|
440 |
}
|
sl@0
|
441 |
|
sl@0
|
442 |
return (M3GCamera) camera;
|
sl@0
|
443 |
}
|
sl@0
|
444 |
}
|
sl@0
|
445 |
|
sl@0
|
446 |
/*!
|
sl@0
|
447 |
* \brief Sets a parallel projection.
|
sl@0
|
448 |
*
|
sl@0
|
449 |
* \param handle Camera object
|
sl@0
|
450 |
* \param height height (=fovy)
|
sl@0
|
451 |
* \param aspectRatio viewport aspect ratio
|
sl@0
|
452 |
* \param clipNear near clipping plane
|
sl@0
|
453 |
* \param clipFar far clipping plane
|
sl@0
|
454 |
*/
|
sl@0
|
455 |
M3G_API void m3gSetParallel(M3GCamera handle,
|
sl@0
|
456 |
M3Gfloat height,
|
sl@0
|
457 |
M3Gfloat aspectRatio,
|
sl@0
|
458 |
M3Gfloat clipNear, M3Gfloat clipFar)
|
sl@0
|
459 |
{
|
sl@0
|
460 |
Camera *camera = (Camera *) handle;
|
sl@0
|
461 |
M3G_VALIDATE_OBJECT(camera);
|
sl@0
|
462 |
|
sl@0
|
463 |
if (height <= 0 || aspectRatio <= 0.0f) {
|
sl@0
|
464 |
m3gRaiseError(M3G_INTERFACE(camera), M3G_INVALID_VALUE);
|
sl@0
|
465 |
return;
|
sl@0
|
466 |
}
|
sl@0
|
467 |
|
sl@0
|
468 |
camera->projType = M3G_PARALLEL;
|
sl@0
|
469 |
camera->heightFov = height;
|
sl@0
|
470 |
camera->aspect = aspectRatio;
|
sl@0
|
471 |
camera->clipNear = clipNear;
|
sl@0
|
472 |
camera->clipFar = clipFar;
|
sl@0
|
473 |
|
sl@0
|
474 |
m3gValidateProjectionMatrix(camera);
|
sl@0
|
475 |
}
|
sl@0
|
476 |
|
sl@0
|
477 |
/*!
|
sl@0
|
478 |
* \brief Sets a perspective projection.
|
sl@0
|
479 |
*
|
sl@0
|
480 |
* \param handle Camera object
|
sl@0
|
481 |
* \param fovy fovy
|
sl@0
|
482 |
* \param aspectRatio viewport aspect ratio
|
sl@0
|
483 |
* \param clipNear near clipping plane
|
sl@0
|
484 |
* \param clipFar far clipping plane
|
sl@0
|
485 |
*/
|
sl@0
|
486 |
M3G_API void m3gSetPerspective(M3GCamera handle,
|
sl@0
|
487 |
M3Gfloat fovy,
|
sl@0
|
488 |
M3Gfloat aspectRatio,
|
sl@0
|
489 |
M3Gfloat clipNear, M3Gfloat clipFar)
|
sl@0
|
490 |
{
|
sl@0
|
491 |
Camera *camera = (Camera *) handle;
|
sl@0
|
492 |
M3G_VALIDATE_OBJECT(camera);
|
sl@0
|
493 |
|
sl@0
|
494 |
if (fovy <= 0.0f || fovy >= 180.f
|
sl@0
|
495 |
|| aspectRatio <= 0.0f
|
sl@0
|
496 |
|| clipNear <= 0.0f || clipFar <= 0.0f) {
|
sl@0
|
497 |
m3gRaiseError(M3G_INTERFACE(camera), M3G_INVALID_VALUE);
|
sl@0
|
498 |
return;
|
sl@0
|
499 |
}
|
sl@0
|
500 |
|
sl@0
|
501 |
camera->projType = M3G_PERSPECTIVE;
|
sl@0
|
502 |
camera->heightFov = fovy;
|
sl@0
|
503 |
camera->aspect = aspectRatio;
|
sl@0
|
504 |
camera->clipNear = clipNear;
|
sl@0
|
505 |
camera->clipFar = clipFar;
|
sl@0
|
506 |
|
sl@0
|
507 |
m3gValidateProjectionMatrix(camera);
|
sl@0
|
508 |
}
|
sl@0
|
509 |
|
sl@0
|
510 |
/*!
|
sl@0
|
511 |
* \brief Sets a generic projection.
|
sl@0
|
512 |
*
|
sl@0
|
513 |
* \param handle Camera object
|
sl@0
|
514 |
* \param transform projection matrix
|
sl@0
|
515 |
*/
|
sl@0
|
516 |
M3G_API void m3gSetProjectionMatrix(M3GCamera handle,
|
sl@0
|
517 |
const M3GMatrix *transform)
|
sl@0
|
518 |
{
|
sl@0
|
519 |
Camera *camera = (Camera *) handle;
|
sl@0
|
520 |
M3G_VALIDATE_OBJECT(camera);
|
sl@0
|
521 |
|
sl@0
|
522 |
if (transform == NULL) {
|
sl@0
|
523 |
m3gRaiseError(M3G_INTERFACE(camera), M3G_NULL_POINTER);
|
sl@0
|
524 |
return;
|
sl@0
|
525 |
}
|
sl@0
|
526 |
|
sl@0
|
527 |
camera->projType = M3G_GENERIC;
|
sl@0
|
528 |
m3gCopyMatrix(&camera->projMatrix, transform);
|
sl@0
|
529 |
|
sl@0
|
530 |
m3gValidateProjectionMatrix(camera);
|
sl@0
|
531 |
}
|
sl@0
|
532 |
|
sl@0
|
533 |
/*!
|
sl@0
|
534 |
* \brief Gets camera matrix.
|
sl@0
|
535 |
*
|
sl@0
|
536 |
* \param handle Camera object
|
sl@0
|
537 |
* \param transform projection matrix to fill in
|
sl@0
|
538 |
* \return projection type
|
sl@0
|
539 |
*/
|
sl@0
|
540 |
M3G_API M3Gint m3gGetProjectionAsMatrix(M3GCamera handle,
|
sl@0
|
541 |
M3GMatrix *transform)
|
sl@0
|
542 |
{
|
sl@0
|
543 |
Camera *camera = (Camera *) handle;
|
sl@0
|
544 |
M3G_VALIDATE_OBJECT(camera);
|
sl@0
|
545 |
|
sl@0
|
546 |
if (transform != NULL) {
|
sl@0
|
547 |
/* Check for impossible projection matrix */
|
sl@0
|
548 |
if (camera->projType != M3G_GENERIC &&
|
sl@0
|
549 |
camera->clipFar == camera->clipNear) {
|
sl@0
|
550 |
m3gRaiseError(M3G_INTERFACE(camera), M3G_ARITHMETIC_ERROR);
|
sl@0
|
551 |
return 0;
|
sl@0
|
552 |
}
|
sl@0
|
553 |
|
sl@0
|
554 |
m3gCopyMatrix(transform, m3gProjectionMatrix(camera));
|
sl@0
|
555 |
}
|
sl@0
|
556 |
|
sl@0
|
557 |
return camera->projType;
|
sl@0
|
558 |
}
|
sl@0
|
559 |
|
sl@0
|
560 |
/*!
|
sl@0
|
561 |
* \brief Gets camera parameters.
|
sl@0
|
562 |
*
|
sl@0
|
563 |
* \param handle Camera object
|
sl@0
|
564 |
* \param params camera parameters to fill in
|
sl@0
|
565 |
* \return projection type
|
sl@0
|
566 |
*/
|
sl@0
|
567 |
M3G_API M3Gint m3gGetProjectionAsParams(M3GCamera handle, M3Gfloat *params)
|
sl@0
|
568 |
{
|
sl@0
|
569 |
Camera *camera = (Camera *) handle;
|
sl@0
|
570 |
M3G_VALIDATE_OBJECT(camera);
|
sl@0
|
571 |
|
sl@0
|
572 |
if (params != NULL && camera->projType != M3G_GENERIC) {
|
sl@0
|
573 |
params[0] = camera->heightFov;
|
sl@0
|
574 |
params[1] = camera->aspect;
|
sl@0
|
575 |
params[2] = camera->clipNear;
|
sl@0
|
576 |
params[3] = camera->clipFar;
|
sl@0
|
577 |
}
|
sl@0
|
578 |
|
sl@0
|
579 |
return camera->projType;
|
sl@0
|
580 |
}
|
sl@0
|
581 |
|