1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /* 3DLocation implementation */
18 
19 #include "sles_allinclusive.h"
20 
21 
I3DLocation_SetLocationCartesian(SL3DLocationItf self,const SLVec3D * pLocation)22 static SLresult I3DLocation_SetLocationCartesian(SL3DLocationItf self, const SLVec3D *pLocation)
23 {
24     SL_ENTER_INTERFACE
25 
26     if (NULL == pLocation) {
27         result = SL_RESULT_PARAMETER_INVALID;
28     } else {
29         I3DLocation *thiz = (I3DLocation *) self;
30         SLVec3D locationCartesian = *pLocation;
31         interface_lock_exclusive(thiz);
32         thiz->mLocationCartesian = locationCartesian;
33         thiz->mLocationActive = CARTESIAN_SET_SPHERICAL_UNKNOWN;
34         interface_unlock_exclusive(thiz);
35         result = SL_RESULT_SUCCESS;
36     }
37 
38     SL_LEAVE_INTERFACE
39 }
40 
41 
I3DLocation_SetLocationSpherical(SL3DLocationItf self,SLmillidegree azimuth,SLmillidegree elevation,SLmillimeter distance)42 static SLresult I3DLocation_SetLocationSpherical(SL3DLocationItf self,
43     SLmillidegree azimuth, SLmillidegree elevation, SLmillimeter distance)
44 {
45     SL_ENTER_INTERFACE
46 
47     if (!((-360000 <= azimuth) && (azimuth <= 360000) &&
48         (-90000 <= elevation) && (elevation <= 90000) &&
49         (0 <= distance) && (distance <= SL_MILLIMETER_MAX))) {
50         result = SL_RESULT_PARAMETER_INVALID;
51     } else {
52         I3DLocation *thiz = (I3DLocation *) self;
53         interface_lock_exclusive(thiz);
54         thiz->mLocationSpherical.mAzimuth = azimuth;
55         thiz->mLocationSpherical.mElevation = elevation;
56         thiz->mLocationSpherical.mDistance = distance;
57         thiz->mLocationActive = CARTESIAN_UNKNOWN_SPHERICAL_SET;
58         interface_unlock_exclusive(thiz);
59         result = SL_RESULT_SUCCESS;
60     }
61 
62     SL_LEAVE_INTERFACE
63 }
64 
65 
I3DLocation_Move(SL3DLocationItf self,const SLVec3D * pMovement)66 static SLresult I3DLocation_Move(SL3DLocationItf self, const SLVec3D *pMovement)
67 {
68     SL_ENTER_INTERFACE
69 
70     if (NULL == pMovement) {
71         result = SL_RESULT_PARAMETER_INVALID;
72     } else {
73         I3DLocation *thiz = (I3DLocation *) self;
74         SLVec3D movementCartesian = *pMovement;
75         interface_lock_exclusive(thiz);
76         for (;;) {
77             enum CartesianSphericalActive locationActive = thiz->mLocationActive;
78             switch (locationActive) {
79             case CARTESIAN_COMPUTED_SPHERICAL_SET:
80             case CARTESIAN_SET_SPHERICAL_COMPUTED:  // not in 1.0.1
81             case CARTESIAN_SET_SPHERICAL_REQUESTED: // not in 1.0.1
82             case CARTESIAN_SET_SPHERICAL_UNKNOWN:
83                 thiz->mLocationCartesian.x += movementCartesian.x;
84                 thiz->mLocationCartesian.y += movementCartesian.y;
85                 thiz->mLocationCartesian.z += movementCartesian.z;
86                 thiz->mLocationActive = CARTESIAN_SET_SPHERICAL_UNKNOWN;
87                 break;
88             case CARTESIAN_UNKNOWN_SPHERICAL_SET:
89                 thiz->mLocationActive = CARTESIAN_REQUESTED_SPHERICAL_SET;
90                 // fall through
91             case CARTESIAN_REQUESTED_SPHERICAL_SET:
92                 // matched by cond_broadcast in case multiple requesters
93 #if 0
94                 interface_cond_wait(thiz);
95 #else
96                 thiz->mLocationActive = CARTESIAN_COMPUTED_SPHERICAL_SET;
97 #endif
98                 continue;
99             default:
100                 assert(SL_BOOLEAN_FALSE);
101                 break;
102             }
103             break;
104         }
105         interface_unlock_exclusive(thiz);
106         result = SL_RESULT_SUCCESS;
107     }
108 
109     SL_LEAVE_INTERFACE
110 }
111 
112 
I3DLocation_GetLocationCartesian(SL3DLocationItf self,SLVec3D * pLocation)113 static SLresult I3DLocation_GetLocationCartesian(SL3DLocationItf self, SLVec3D *pLocation)
114 {
115     SL_ENTER_INTERFACE
116 
117     if (NULL == pLocation) {
118         result = SL_RESULT_PARAMETER_INVALID;
119     } else {
120         I3DLocation *thiz = (I3DLocation *) self;
121         interface_lock_exclusive(thiz);
122         for (;;) {
123             enum CartesianSphericalActive locationActive = thiz->mLocationActive;
124             switch (locationActive) {
125             case CARTESIAN_COMPUTED_SPHERICAL_SET:
126             case CARTESIAN_SET_SPHERICAL_COMPUTED:  // not in 1.0.1
127             case CARTESIAN_SET_SPHERICAL_REQUESTED: // not in 1.0.1
128             case CARTESIAN_SET_SPHERICAL_UNKNOWN:
129                 {
130                 SLVec3D locationCartesian = thiz->mLocationCartesian;
131                 interface_unlock_exclusive(thiz);
132                 *pLocation = locationCartesian;
133                 }
134                 break;
135             case CARTESIAN_UNKNOWN_SPHERICAL_SET:
136                 thiz->mLocationActive = CARTESIAN_REQUESTED_SPHERICAL_SET;
137                 // fall through
138             case CARTESIAN_REQUESTED_SPHERICAL_SET:
139                 // matched by cond_broadcast in case multiple requesters
140 #if 0
141                 interface_cond_wait(thiz);
142 #else
143                 thiz->mLocationActive = CARTESIAN_COMPUTED_SPHERICAL_SET;
144 #endif
145                 continue;
146             default:
147                 assert(SL_BOOLEAN_FALSE);
148                 interface_unlock_exclusive(thiz);
149                 pLocation->x = 0;
150                 pLocation->y = 0;
151                 pLocation->z = 0;
152                 break;
153             }
154             break;
155         }
156         result = SL_RESULT_SUCCESS;
157     }
158 
159     SL_LEAVE_INTERFACE
160 }
161 
162 
I3DLocation_SetOrientationVectors(SL3DLocationItf self,const SLVec3D * pFront,const SLVec3D * pAbove)163 static SLresult I3DLocation_SetOrientationVectors(SL3DLocationItf self,
164     const SLVec3D *pFront, const SLVec3D *pAbove)
165 {
166     SL_ENTER_INTERFACE
167 
168     if (NULL == pFront || NULL == pAbove) {
169         result = SL_RESULT_PARAMETER_INVALID;
170     } else {
171         SLVec3D front = *pFront;
172         SLVec3D above = *pAbove;
173         // NTH Check for vectors close to zero or close to parallel
174         I3DLocation *thiz = (I3DLocation *) self;
175         interface_lock_exclusive(thiz);
176         thiz->mOrientationVectors.mFront = front;
177         thiz->mOrientationVectors.mAbove = above;
178         thiz->mOrientationActive = ANGLES_UNKNOWN_VECTORS_SET;
179         thiz->mRotatePending = SL_BOOLEAN_FALSE;
180         interface_unlock_exclusive(thiz);
181         result = SL_RESULT_SUCCESS;
182     }
183 
184     SL_LEAVE_INTERFACE
185 }
186 
187 
I3DLocation_SetOrientationAngles(SL3DLocationItf self,SLmillidegree heading,SLmillidegree pitch,SLmillidegree roll)188 static SLresult I3DLocation_SetOrientationAngles(SL3DLocationItf self,
189     SLmillidegree heading, SLmillidegree pitch, SLmillidegree roll)
190 {
191     SL_ENTER_INTERFACE
192 
193     if (!((-360000 <= heading) && (heading <= 360000) &&
194         (-90000 <= pitch) && (pitch <= 90000) &&
195         (-360000 <= roll) && (roll <= 360000))) {
196         result = SL_RESULT_PARAMETER_INVALID;
197     } else {
198         I3DLocation *thiz = (I3DLocation *) self;
199         interface_lock_exclusive(thiz);
200         thiz->mOrientationAngles.mHeading = heading;
201         thiz->mOrientationAngles.mPitch = pitch;
202         thiz->mOrientationAngles.mRoll = roll;
203         thiz->mOrientationActive = ANGLES_SET_VECTORS_UNKNOWN;
204         thiz->mRotatePending = SL_BOOLEAN_FALSE;
205         interface_unlock_exclusive(thiz);
206         result = SL_RESULT_SUCCESS;
207     }
208 
209     SL_LEAVE_INTERFACE
210 }
211 
212 
I3DLocation_Rotate(SL3DLocationItf self,SLmillidegree theta,const SLVec3D * pAxis)213 static SLresult I3DLocation_Rotate(SL3DLocationItf self, SLmillidegree theta, const SLVec3D *pAxis)
214 {
215     SL_ENTER_INTERFACE
216 
217     if (!((-360000 <= theta) && (theta <= 360000)) || (NULL == pAxis)) {
218         result = SL_RESULT_PARAMETER_INVALID;
219     } else {
220         SLVec3D axis = *pAxis;
221         // NTH Check that axis is not (close to) zero vector, length does not matter
222         I3DLocation *thiz = (I3DLocation *) self;
223         interface_lock_exclusive(thiz);
224         while (thiz->mRotatePending)
225 #if 0
226             interface_cond_wait(thiz);
227 #else
228             break;
229 #endif
230         thiz->mTheta = theta;
231         thiz->mAxis = axis;
232         thiz->mRotatePending = SL_BOOLEAN_TRUE;
233         interface_unlock_exclusive(thiz);
234         result = SL_RESULT_SUCCESS;
235     }
236 
237     SL_LEAVE_INTERFACE
238 }
239 
240 
I3DLocation_GetOrientationVectors(SL3DLocationItf self,SLVec3D * pFront,SLVec3D * pUp)241 static SLresult I3DLocation_GetOrientationVectors(SL3DLocationItf self,
242     SLVec3D *pFront, SLVec3D *pUp)
243 {
244     SL_ENTER_INTERFACE
245 
246     if (NULL == pFront || NULL == pUp) {
247         result = SL_RESULT_PARAMETER_INVALID;
248     } else {
249         I3DLocation *thiz = (I3DLocation *) self;
250         interface_lock_shared(thiz);
251         SLVec3D front = thiz->mOrientationVectors.mFront;
252         SLVec3D up = thiz->mOrientationVectors.mUp;
253         interface_unlock_shared(thiz);
254         *pFront = front;
255         *pUp = up;
256         result = SL_RESULT_SUCCESS;
257     }
258 
259     SL_LEAVE_INTERFACE
260 }
261 
262 
263 static const struct SL3DLocationItf_ I3DLocation_Itf = {
264     I3DLocation_SetLocationCartesian,
265     I3DLocation_SetLocationSpherical,
266     I3DLocation_Move,
267     I3DLocation_GetLocationCartesian,
268     I3DLocation_SetOrientationVectors,
269     I3DLocation_SetOrientationAngles,
270     I3DLocation_Rotate,
271     I3DLocation_GetOrientationVectors
272 };
273 
I3DLocation_init(void * self)274 void I3DLocation_init(void *self)
275 {
276     I3DLocation *thiz = (I3DLocation *) self;
277     thiz->mItf = &I3DLocation_Itf;
278     thiz->mLocationCartesian.x = 0;
279     thiz->mLocationCartesian.y = 0;
280     thiz->mLocationCartesian.z = 0;
281     memset(&thiz->mLocationSpherical, 0x55, sizeof(thiz->mLocationSpherical));
282     thiz->mLocationActive = CARTESIAN_SET_SPHERICAL_UNKNOWN;
283     thiz->mOrientationAngles.mHeading = 0;
284     thiz->mOrientationAngles.mPitch = 0;
285     thiz->mOrientationAngles.mRoll = 0;
286     memset(&thiz->mOrientationVectors, 0x55, sizeof(thiz->mOrientationVectors));
287     thiz->mOrientationActive = ANGLES_SET_VECTORS_UNKNOWN;
288     thiz->mTheta = 0x55555555;
289     thiz->mAxis.x = 0x55555555;
290     thiz->mAxis.y = 0x55555555;
291     thiz->mAxis.z = 0x55555555;
292     thiz->mRotatePending = SL_BOOLEAN_FALSE;
293 }
294