Oolite 1.91.0.7645-241119-222d325
Loading...
Searching...
No Matches
OOJSQuaternion.m
Go to the documentation of this file.
1/*
2
3OOJSQuaternion.m
4
5Oolite
6Copyright (C) 2004-2013 Giles C Williams and contributors
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; either version 2
11of the License, or (at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with this program; if not, write to the Free Software
20Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21MA 02110-1301, USA.
22
23*/
24
25#import "OOJSQuaternion.h"
27
28#if OOLITE_GNUSTEP
29#import <GNUstepBase/GSObjCRuntime.h>
30#else
31#import <objc/objc-runtime.h>
32#endif
33
34#import "OOConstToString.h"
35#import "OOJSEntity.h"
36#import "OOJSVector.h"
37
38
39static JSObject *sQuaternionPrototype;
40
41
42static BOOL GetThisQuaternion(JSContext *context, JSObject *quaternionObj, Quaternion *outQuaternion, NSString *method) NONNULL_FUNC;
43
44
45static JSBool QuaternionGetProperty(JSContext *context, JSObject *this, jsid propID, jsval *value);
46static JSBool QuaternionSetProperty(JSContext *context, JSObject *this, jsid propID, JSBool strict, jsval *value);
47static void QuaternionFinalize(JSContext *context, JSObject *this);
48static JSBool QuaternionConstruct(JSContext *context, uintN argc, jsval *vp);
49
50// Methods
51static JSBool QuaternionToString(JSContext *context, uintN argc, jsval *vp);
52static JSBool QuaternionToSource(JSContext *context, uintN argc, jsval *vp);
53static JSBool QuaternionMultiply(JSContext *context, uintN argc, jsval *vp);
54static JSBool QuaternionDot(JSContext *context, uintN argc, jsval *vp);
55static JSBool QuaternionRotate(JSContext *context, uintN argc, jsval *vp);
56static JSBool QuaternionRotateX(JSContext *context, uintN argc, jsval *vp);
57static JSBool QuaternionRotateY(JSContext *context, uintN argc, jsval *vp);
58static JSBool QuaternionRotateZ(JSContext *context, uintN argc, jsval *vp);
59static JSBool QuaternionNormalize(JSContext *context, uintN argc, jsval *vp);
60static JSBool QuaternionConjugate(JSContext *context, uintN argc, jsval *vp);
61static JSBool QuaternionVectorForward(JSContext *context, uintN argc, jsval *vp);
62static JSBool QuaternionVectorUp(JSContext *context, uintN argc, jsval *vp);
63static JSBool QuaternionVectorRight(JSContext *context, uintN argc, jsval *vp);
64static JSBool QuaternionToArray(JSContext *context, uintN argc, jsval *vp);
65
66// Static methods
67static JSBool QuaternionStaticRandom(JSContext *context, uintN argc, jsval *vp);
68
69
70static JSClass sQuaternionClass =
71{
72 "Quaternion",
73 JSCLASS_HAS_PRIVATE,
74
75 JS_PropertyStub, // addProperty
76 JS_PropertyStub, // delProperty
77 QuaternionGetProperty, // getProperty
78 QuaternionSetProperty, // setProperty
79 JS_EnumerateStub, // enumerate
80 JS_ResolveStub, // resolve
81 JS_ConvertStub, // convert
82 QuaternionFinalize, // finalize
83 JSCLASS_NO_OPTIONAL_MEMBERS
84};
85
86
87enum
88{
89 // Property IDs
94};
95
96
97static JSPropertySpec sQuaternionProperties[] =
98{
99 // JS name ID flags
104 { 0 }
105};
106
107
108static JSFunctionSpec sQuaternionMethods[] =
109{
110 // JS name Function min args
111 { "toString", QuaternionToString, 0, },
112 { "toSource", QuaternionToSource, 0, },
113 { "dot", QuaternionDot, 1, },
114 { "multiply", QuaternionMultiply, 1, },
115 { "normalize", QuaternionNormalize, 0, },
116 { "conjugate", QuaternionConjugate, 0, },
117 { "rotate", QuaternionRotate, 2, },
118 { "rotateX", QuaternionRotateX, 1, },
119 { "rotateY", QuaternionRotateY, 1, },
120 { "rotateZ", QuaternionRotateZ, 1, },
121 { "toArray", QuaternionToArray, 0, },
122 { "vectorForward", QuaternionVectorForward, 0, },
123 { "vectorRight", QuaternionVectorRight, 0, },
124 { "vectorUp", QuaternionVectorUp, 0, },
125 { 0 }
126};
127
128
129static JSFunctionSpec sQuaternionStaticMethods[] =
130{
131 // JS name Function min args
132 { "random", QuaternionStaticRandom, 0, },
133 { 0 }
134};
135
136
137// *** Public ***
138
139void InitOOJSQuaternion(JSContext *context, JSObject *global)
140{
142}
143
144
145JSObject *JSQuaternionWithQuaternion(JSContext *context, Quaternion quaternion)
146{
148
149 JSObject *result = NULL;
150 Quaternion *private = NULL;
151
152 private = malloc(sizeof *private);
153 if (EXPECT_NOT(private == NULL)) return NULL;
154
155 *private = quaternion;
156
157 result = JS_NewObject(context, &sQuaternionClass, sQuaternionPrototype, NULL);
158 if (result != NULL)
159 {
160 if (!JS_SetPrivate(context, result, private)) result = NULL;
161 }
162
163 if (EXPECT_NOT(result == NULL)) free(private);
164
165 return result;
166
168}
169
170
171BOOL QuaternionToJSValue(JSContext *context, Quaternion quaternion, jsval *outValue)
172{
174
175 JSObject *object = NULL;
176
177 assert(outValue != NULL);
178
179 object = JSQuaternionWithQuaternion(context, quaternion);
180 if (EXPECT_NOT(object == NULL)) return NO;
181
182 *outValue = OBJECT_TO_JSVAL(object);
183 return YES;
184
186}
187
188
189BOOL JSValueToQuaternion(JSContext *context, jsval value, Quaternion *outQuaternion)
190{
191 if (EXPECT_NOT(!JSVAL_IS_OBJECT(value))) return NO;
192
193 return JSObjectGetQuaternion(context, JSVAL_TO_OBJECT(value), outQuaternion);
194}
195
196
197#if OO_DEBUG
198
199typedef struct
200{
201 NSUInteger quatCount;
202 NSUInteger entityCount;
203 NSUInteger arrayCount;
204 NSUInteger protoCount;
205 NSUInteger nullCount;
206 NSUInteger failCount;
207} QuaternionStatistics;
208static QuaternionStatistics sQuaternionConversionStats;
209
210
211@implementation PlayerEntity (JSQuaternionStatistics)
212
213// :setM quatStats PS.callObjC("reportJSQuaternionStatistics")
214// :quatStats
215
216- (NSString *) reportJSQuaternionStatistics
217{
218 QuaternionStatistics *stats = &sQuaternionConversionStats;
219
220 NSUInteger sum = stats->quatCount + stats->entityCount + stats->arrayCount + stats->protoCount;
221 double convFac = 100.0 / sum;
222
223 return [NSString stringWithFormat:
224 @"quaternion-to-quaternion conversions: %lu (%g %%)\n"
225 " entity-to-quaternion conversions: %lu (%g %%)\n"
226 " array-to-quaternion conversions: %lu (%g %%)\n"
227 " prototype-to-zero conversions: %lu (%g %%)\n"
228 " null conversions: %lu (%g %%)\n"
229 " failed conversions: %lu (%g %%)\n"
230 " total: %lu",
231 (long)stats->quatCount, stats->quatCount * convFac,
232 (long)stats->entityCount, stats->entityCount * convFac,
233 (long)stats->arrayCount, stats->arrayCount * convFac,
234 (long)stats->protoCount, stats->protoCount * convFac,
235 (long)stats->nullCount, stats->nullCount * convFac,
236 (long)stats->failCount, stats->failCount * convFac,
237 (long)sum];
238}
239
240
241- (void) clearJSQuaternionStatistics
242{
243 memset(&sQuaternionConversionStats, 0, sizeof sQuaternionConversionStats);
244}
245
246@end
247
248#define COUNT(FIELD) do { sQuaternionConversionStats.FIELD++; } while (0)
249
250#else
251
252#define COUNT(FIELD) do {} while (0)
253
254#endif
255
256
257BOOL JSObjectGetQuaternion(JSContext *context, JSObject *quaternionObj, Quaternion *outQuaternion)
258{
260
261 assert(outQuaternion != NULL);
262
263 Quaternion *private = NULL;
264 jsuint arrayLength;
265 jsval arrayW, arrayX, arrayY, arrayZ;
266 jsdouble dVal;
267
268 // quaternionObj can legitimately be NULL, e.g. when JS_NULL is converted to a JSObject *.
269 if (EXPECT_NOT(quaternionObj == NULL))
270 {
271 COUNT(nullCount);
272 return NO;
273 }
274
275 // If this is a (JS) Quaternion...
276 private = JS_GetInstancePrivate(context, quaternionObj, &sQuaternionClass, NULL);
277 if (EXPECT(private != NULL))
278 {
279 COUNT(quatCount);
280 *outQuaternion = *private;
281 return YES;
282 }
283
284 // If it's an array...
285 if (EXPECT(JS_IsArrayObject(context, quaternionObj)))
286 {
287 // ...and it has exactly four elements...
288 if (JS_GetArrayLength(context, quaternionObj, &arrayLength) && arrayLength == 4)
289 {
290 if (JS_LookupElement(context, quaternionObj, 0, &arrayW) &&
291 JS_LookupElement(context, quaternionObj, 1, &arrayX) &&
292 JS_LookupElement(context, quaternionObj, 2, &arrayY) &&
293 JS_LookupElement(context, quaternionObj, 3, &arrayZ))
294 {
295 // ...se the four numbers as [w, x, y, z]
296 if (!JS_ValueToNumber(context, arrayW, &dVal)) return NO;
297 outQuaternion->w = dVal;
298 if (!JS_ValueToNumber(context, arrayX, &dVal)) return NO;
299 outQuaternion->x = dVal;
300 if (!JS_ValueToNumber(context, arrayY, &dVal)) return NO;
301 outQuaternion->y = dVal;
302 if (!JS_ValueToNumber(context, arrayZ, &dVal)) return NO;
303 outQuaternion->z = dVal;
304
305 COUNT(arrayCount);
306 return YES;
307 }
308 }
309 }
310
311 // If it's an entity, use its orientation.
312 if (OOJSIsMemberOfSubclass(context, quaternionObj, JSEntityClass()))
313 {
314 COUNT(entityCount);
315 Entity *entity = JS_GetPrivate(context, quaternionObj);
316 *outQuaternion = [entity orientation];
317 return YES;
318 }
319
320 /*
321 If it's actually a Quaternion but with no private field (this happens for
322 Quaternion.prototype)...
323
324 NOTE: it would be prettier to do this at the top when we handle normal
325 Quaternions, but it's a rare case which should be kept off the fast path.
326 */
327 if (JS_InstanceOf(context, quaternionObj, &sQuaternionClass, NULL))
328 {
329 COUNT(protoCount);
330 *outQuaternion = kZeroQuaternion;
331 return YES;
332 }
333
334 COUNT(failCount);
335 return NO;
336
338}
339
340
341static BOOL GetThisQuaternion(JSContext *context, JSObject *quaternionObj, Quaternion *outQuaternion, NSString *method)
342{
343 if (EXPECT(JSObjectGetQuaternion(context, quaternionObj, outQuaternion))) return YES;
344
345 jsval arg = OBJECT_TO_JSVAL(quaternionObj);
346 OOJSReportBadArguments(context, @"Quaternion", method, 1, &arg, @"Invalid target object", @"Quaternion");
347 return NO;
348}
349
350
351BOOL JSQuaternionSetQuaternion(JSContext *context, JSObject *quaternionObj, Quaternion quaternion)
352{
354
355 Quaternion *private = NULL;
356
357 assert(quaternionObj != NULL);
358
359 private = JS_GetInstancePrivate(context, quaternionObj, &sQuaternionClass, NULL);
360 if (private != NULL) // If this is a (JS) Quaternion...
361 {
362 *private = quaternion;
363 return YES;
364 }
365
366 if (JS_InstanceOf(context, quaternionObj, &sQuaternionClass, NULL))
367 {
368 // Silently fail for the prototype.
369 return YES;
370 }
371
372 return NO;
373
375}
376
377
378static BOOL QuaternionFromArgumentListNoErrorInternal(JSContext *context, uintN argc, jsval *argv, Quaternion *outQuaternion, uintN *outConsumed, BOOL permitNumberList)
379{
381
382 double w, x, y, z;
383
384 if (EXPECT_NOT(argc == 0)) return NO;
385 assert(argv != NULL && outQuaternion != NULL);
386
387 if (outConsumed != NULL) *outConsumed = 0;
388
389 // Is first object a quaternion or entity?
390 if (JSVAL_IS_OBJECT(argv[0]))
391 {
392 if (JSObjectGetQuaternion(context, JSVAL_TO_OBJECT(argv[0]), outQuaternion))
393 {
394 if (outConsumed != NULL) *outConsumed = 1;
395 return YES;
396 }
397 }
398
399 if (!permitNumberList) return NO;
400
401 // As a special case for QuaternionConstruct(), look for four numbers.
402 if (EXPECT_NOT(argc < 4)) return NO;
403
404 // Given a string, JS_ValueToNumber() returns YES but provides a NaN number.
405 if (EXPECT_NOT(!JS_ValueToNumber(context, argv[0], &w) || isnan(w))) return NO;
406 if (EXPECT_NOT(!JS_ValueToNumber(context, argv[1], &x) || isnan(x))) return NO;
407 if (EXPECT_NOT(!JS_ValueToNumber(context, argv[2], &y) || isnan(y))) return NO;
408 if (EXPECT_NOT(!JS_ValueToNumber(context, argv[3], &z) || isnan(z))) return NO;
409
410 // We got our four numbers.
411 *outQuaternion = make_quaternion(w, x, y, z);
412 if (outConsumed != NULL) *outConsumed = 4;
413
414 return YES;
415
417}
418
419
420// EMMSTRAN: remove outConsumed, since it can only be 1 except in failure (constructor is an exception, but it uses QuaternionFromArgumentListNoErrorInternal() directly).
421BOOL QuaternionFromArgumentList(JSContext *context, NSString *scriptClass, NSString *function, uintN argc, jsval *argv, Quaternion *outQuaternion, uintN *outConsumed)
422{
423 if (QuaternionFromArgumentListNoErrorInternal(context, argc, argv, outQuaternion, outConsumed, NO)) return YES;
424 else
425 {
426 OOJSReportBadArguments(context, scriptClass, function, argc, argv,
427 @"Could not construct quaternion from parameters",
428 @"Quaternion, Entity or four numbers");
429 return NO;
430 }
431}
432
433
434BOOL QuaternionFromArgumentListNoError(JSContext *context, uintN argc, jsval *argv, Quaternion *outQuaternion, uintN *outConsumed)
435{
436 return QuaternionFromArgumentListNoErrorInternal(context, argc, argv, outQuaternion, outConsumed, NO);
437}
438
439
440// *** Implementation stuff ***
441
442static JSBool QuaternionGetProperty(JSContext *context, JSObject *this, jsid propID, jsval *value)
443{
444 if (!JSID_IS_INT(propID)) return YES;
445
447
448 Quaternion quaternion;
449 GLfloat fValue;
450
451 if (EXPECT_NOT(!JSObjectGetQuaternion(context, this, &quaternion))) return NO;
452
453 switch (JSID_TO_INT(propID))
454 {
455 case kQuaternion_w:
456 fValue = quaternion.w;
457 break;
458
459 case kQuaternion_x:
460 fValue = quaternion.x;
461 break;
462
463 case kQuaternion_y:
464 fValue = quaternion.y;
465 break;
466
467 case kQuaternion_z:
468 fValue = quaternion.z;
469 break;
470
471 default:
473 return NO;
474 }
475
476 return JS_NewNumberValue(context, fValue, value);
477
479}
480
481
482static JSBool QuaternionSetProperty(JSContext *context, JSObject *this, jsid propID, JSBool strict, jsval *value)
483{
484 if (!JSID_IS_INT(propID)) return YES;
485
487
488 Quaternion quaternion;
489 jsdouble dval;
490
491 if (EXPECT_NOT(!JSObjectGetQuaternion(context, this, &quaternion))) return NO;
492 if (EXPECT_NOT(!JS_ValueToNumber(context, *value, &dval)))
493 {
494 OOJSReportBadPropertyValue(context, this, propID, sQuaternionProperties, *value);
495 return NO;
496 }
497
498 switch (JSID_TO_INT(propID))
499 {
500 case kQuaternion_w:
501 quaternion.w = dval;
502 break;
503
504 case kQuaternion_x:
505 quaternion.x = dval;
506 break;
507
508 case kQuaternion_y:
509 quaternion.y = dval;
510 break;
511
512 case kQuaternion_z:
513 quaternion.z = dval;
514 break;
515
516 default:
518 return NO;
519 }
520
521 return JSQuaternionSetQuaternion(context, this, quaternion);
522
524}
525
526
527static void QuaternionFinalize(JSContext *context, JSObject *this)
528{
529 Quaternion *private = NULL;
530
531 private = JS_GetInstancePrivate(context, this, &sQuaternionClass, NULL);
532 if (private != NULL)
533 {
534 free(private);
535 }
536}
537
538
539static JSBool QuaternionConstruct(JSContext *context, uintN argc, jsval *vp)
540{
542
543 Quaternion quaternion = kIdentityQuaternion;
544 Quaternion *private = NULL;
545 JSObject *this = NULL;
546
547 private = malloc(sizeof *private);
548 if (EXPECT_NOT(private == NULL)) return NO;
549
550 this = JS_NewObject(context, &sQuaternionClass, NULL, NULL);
551 if (EXPECT_NOT(this == NULL)) return NO;
552
553 if (argc != 0)
554 {
555 if (EXPECT_NOT(!QuaternionFromArgumentListNoErrorInternal(context, argc, OOJS_ARGV, &quaternion, NULL, YES)))
556 {
557 free(private);
558 OOJSReportBadArguments(context, NULL, NULL, argc, OOJS_ARGV,
559 @"Could not construct quaternion from parameters",
560 @"Quaternion, Entity or array of four numbers");
561 return NO;
562 }
563 }
564
565 *private = quaternion;
566
567 if (!JS_SetPrivate(context, this, private))
568 {
569 free(private);
570 return NO;
571 }
572
574
576}
577
578
579// *** Methods ***
580
581// toString() : String
582static JSBool QuaternionToString(JSContext *context, uintN argc, jsval *vp)
583{
584 OOJS_NATIVE_ENTER(context)
585
586 Quaternion thisq;
587
588 if (EXPECT_NOT(!GetThisQuaternion(context, OOJS_THIS, &thisq, @"toString"))) return NO;
589
590 OOJS_RETURN_OBJECT(QuaternionDescription(thisq));
591
593}
594
595
596// toSource() : String
597static JSBool QuaternionToSource(JSContext *context, uintN argc, jsval *vp)
598{
599 OOJS_NATIVE_ENTER(context)
600
601 Quaternion thisq;
602
603 if (EXPECT_NOT(!GetThisQuaternion(context, OOJS_THIS, &thisq, @"toSource"))) return NO;
604
605 NSString *str = [NSString stringWithFormat:@"Quaternion(%g, %g, %g, %g)", thisq.w, thisq.x, thisq.y, thisq.z];
607
609}
610
611
612// multiply(q : quaternionExpression) : Quaternion
613static JSBool QuaternionMultiply(JSContext *context, uintN argc, jsval *vp)
614{
616
617 Quaternion thisq, thatq, result;
618
619 if (EXPECT_NOT(!GetThisQuaternion(context, OOJS_THIS, &thisq, @"multiply"))) return NO;
620 if (EXPECT_NOT(!QuaternionFromArgumentList(context, @"Quaternion", @"multiply", argc, OOJS_ARGV, &thatq, NULL))) return NO;
621
622 result = quaternion_multiply(thisq, thatq);
623
625
627}
628
629
630// dot(q : quaternionExpression) : Number
631static JSBool QuaternionDot(JSContext *context, uintN argc, jsval *vp)
632{
634
635 Quaternion thisq, thatq;
636 OOScalar result;
637
638 if (EXPECT_NOT(!GetThisQuaternion(context, OOJS_THIS, &thisq, @"dot"))) return NO;
639 if (EXPECT_NOT(!QuaternionFromArgumentList(context, @"Quaternion", @"dot", argc, OOJS_ARGV, &thatq, NULL))) return NO;
640
641 result = quaternion_dot_product(thisq, thatq);
642
643 OOJS_RETURN_DOUBLE(result);
644
646}
647
648
649// rotate(axis : vectorExpression, angle : Number) : Quaternion
650static JSBool QuaternionRotate(JSContext *context, uintN argc, jsval *vp)
651{
653
654 Quaternion thisq;
655 HPVector axis;
656 double angle;
657 uintN consumed;
658 jsval *argv = OOJS_ARGV;
659
660 if (EXPECT_NOT(!GetThisQuaternion(context, OOJS_THIS, &thisq, @"rotate"))) return NO;
661 if (EXPECT_NOT(!VectorFromArgumentList(context, @"Quaternion", @"rotate", argc, argv, &axis, &consumed))) return NO;
662 argv += consumed;
663 argc -= consumed;
664 if (argc > 0)
665 {
666 if (EXPECT_NOT(!OOJSArgumentListGetNumber(context, @"Quaternion", @"rotate", argc, argv, &angle, NULL))) return NO;
667 quaternion_rotate_about_axis(&thisq, HPVectorToVector(axis), angle);
668 }
669 // Else no angle specified, so don't rotate and pass value through unchanged.
670
672
674}
675
676
677// rotateX(angle : Number) : Quaternion
678static JSBool QuaternionRotateX(JSContext *context, uintN argc, jsval *vp)
679{
681
682 Quaternion quat;
683 double angle;
684
685 if (EXPECT_NOT(!GetThisQuaternion(context, OOJS_THIS, &quat, @"rotateX"))) return NO;
686 if (EXPECT_NOT(!OOJSArgumentListGetNumber(context, @"Quaternion", @"rotateX", argc, OOJS_ARGV, &angle, NULL))) return NO;
687
688 quaternion_rotate_about_x(&quat, angle);
689
691
693}
694
695
696// rotateY(angle : Number) : Quaternion
697static JSBool QuaternionRotateY(JSContext *context, uintN argc, jsval *vp)
698{
700
701 Quaternion quat;
702 double angle;
703
704 if (EXPECT_NOT(!GetThisQuaternion(context, OOJS_THIS, &quat, @"rotateY"))) return NO;
705 if (EXPECT_NOT(!OOJSArgumentListGetNumber(context, @"Quaternion", @"rotateY", argc, OOJS_ARGV, &angle, NULL))) return NO;
706
707 quaternion_rotate_about_y(&quat, angle);
708
710
712}
713
714
715// rotateZ(angle : Number) : Quaternion
716static JSBool QuaternionRotateZ(JSContext *context, uintN argc, jsval *vp)
717{
719
720 Quaternion quat;
721 double angle;
722
723 if (EXPECT_NOT(!GetThisQuaternion(context, OOJS_THIS, &quat, @"rotateZ"))) return NO;
724 if (EXPECT_NOT(!OOJSArgumentListGetNumber(context, @"Quaternion", @"rotateZ", argc, OOJS_ARGV, &angle, NULL))) return NO;
725
726 quaternion_rotate_about_z(&quat, angle);
727
729
731}
732
733
734// normalize() : Quaternion
735static JSBool QuaternionNormalize(JSContext *context, uintN argc, jsval *vp)
736{
738
739 Quaternion quat;
740
741 if (EXPECT_NOT(!GetThisQuaternion(context, OOJS_THIS, &quat, @"normalize"))) return NO;
742
743 quaternion_normalize(&quat);
744
746
748}
749
750
751// conjugate() : Quaternion
752static JSBool QuaternionConjugate(JSContext *context, uintN argc, jsval *vp)
753{
755
756 Quaternion quat, result;
757
758 if (EXPECT_NOT(!GetThisQuaternion(context, OOJS_THIS, &quat, @"conjugate"))) return NO;
759
760 result = quaternion_conjugate(quat);
761
763
765}
766
767
768// vectorForward() : Vector
769static JSBool QuaternionVectorForward(JSContext *context, uintN argc, jsval *vp)
770{
772
773 Quaternion thisq;
774 Vector result;
775
776 if (EXPECT_NOT(!GetThisQuaternion(context, OOJS_THIS, &thisq, @"vectorForward"))) return NO;
777
778 result = vector_forward_from_quaternion(thisq);
779
780 OOJS_RETURN_VECTOR(result);
781
783}
784
785
786// vectorUp() : Vector
787static JSBool QuaternionVectorUp(JSContext *context, uintN argc, jsval *vp)
788{
790
791 Quaternion thisq;
792 Vector result;
793
794 if (EXPECT_NOT(!GetThisQuaternion(context, OOJS_THIS, &thisq, @"vectorUp"))) return NO;
795
796 result = vector_up_from_quaternion(thisq);
797
798 OOJS_RETURN_VECTOR(result);
799
801}
802
803
804// vectorRight() : Vector
805static JSBool QuaternionVectorRight(JSContext *context, uintN argc, jsval *vp)
806{
808
809 Quaternion thisq;
810 Vector result;
811
812 if (EXPECT_NOT(!GetThisQuaternion(context, OOJS_THIS, &thisq, @"vectorRight"))) return NO;
813
814 result = vector_right_from_quaternion(thisq);
815
816 OOJS_RETURN_VECTOR(result);
817
819}
820
821
822// toArray() : Array
823static JSBool QuaternionToArray(JSContext *context, uintN argc, jsval *vp)
824{
826
827 Quaternion thisq;
828 JSObject *result = NULL;
829 BOOL OK = YES;
830 jsval nVal;
831
832 if (EXPECT_NOT(!GetThisQuaternion(context, OOJS_THIS, &thisq, @"toArray"))) return NO;
833
834 result = JS_NewArrayObject(context, 0, NULL);
835 if (result != NULL)
836 {
837 // We do this at the top because *outResult is a GC root.
838 OOJS_SET_RVAL(OBJECT_TO_JSVAL(result));
839
840 if (JS_NewNumberValue(context, thisq.w, &nVal)) JS_SetElement(context, result, 0, &nVal);
841 else OK = NO;
842 if (JS_NewNumberValue(context, thisq.x, &nVal)) JS_SetElement(context, result, 1, &nVal);
843 else OK = NO;
844 if (JS_NewNumberValue(context, thisq.y, &nVal)) JS_SetElement(context, result, 2, &nVal);
845 else OK = NO;
846 if (JS_NewNumberValue(context, thisq.z, &nVal)) JS_SetElement(context, result, 3, &nVal);
847 else OK = NO;
848 }
849
850 if (!OK) OOJS_SET_RVAL(JSVAL_VOID);
851 return YES;
852
854}
855
856
857// *** Static methods ***
858
859// random() : Quaternion
860static JSBool QuaternionStaticRandom(JSContext *context, uintN argc, jsval *vp)
861{
863
864 OOJS_RETURN_QUATERNION(OORandomQuaternion());
865
867}
#define EXPECT_NOT(x)
#define NONNULL_FUNC
#define EXPECT(x)
#define OOJS_PROFILE_EXIT
#define OOJS_NATIVE_ENTER(cx)
#define OOJS_NATIVE_EXIT
#define OOJS_PROFILE_ENTER
OOINLINE JSClass * JSEntityClass(void)
Definition OOJSEntity.h:42
BOOL BOOL JSQuaternionSetQuaternion(JSContext *context, JSObject *quaternionObj, Quaternion quaternion) GCC_ATTR((nonnull(1)))
BOOL QuaternionFromArgumentList(JSContext *context, NSString *scriptClass, NSString *function, uintN argc, jsval *argv, Quaternion *outQuaternion, uintN *outConsumed) GCC_ATTR((nonnull(1
BOOL BOOL QuaternionFromArgumentListNoError(JSContext *context, uintN argc, jsval *argv, Quaternion *outVector, uintN *outConsumed) GCC_ATTR((nonnull(1
BOOL JSObjectGetQuaternion(JSContext *context, JSObject *quaternionObj, Quaternion *outQuaternion) GCC_ATTR((nonnull(1
JSObject * JSQuaternionWithQuaternion(JSContext *context, Quaternion quaternion)
static JSBool QuaternionRotate(JSContext *context, uintN argc, jsval *vp)
static JSClass sQuaternionClass
BOOL JSValueToQuaternion(JSContext *context, jsval value, Quaternion *outQuaternion)
void InitOOJSQuaternion(JSContext *context, JSObject *global)
static JSBool QuaternionToArray(JSContext *context, uintN argc, jsval *vp)
static JSBool QuaternionStaticRandom(JSContext *context, uintN argc, jsval *vp)
static JSBool QuaternionRotateY(JSContext *context, uintN argc, jsval *vp)
static BOOL GetThisQuaternion(JSContext *context, JSObject *quaternionObj, Quaternion *outQuaternion, NSString *method) NONNULL_FUNC
static JSBool QuaternionToString(JSContext *context, uintN argc, jsval *vp)
static JSBool QuaternionToSource(JSContext *context, uintN argc, jsval *vp)
static JSObject * sQuaternionPrototype
static JSBool QuaternionVectorRight(JSContext *context, uintN argc, jsval *vp)
static JSBool QuaternionConstruct(JSContext *context, uintN argc, jsval *vp)
static JSBool QuaternionRotateX(JSContext *context, uintN argc, jsval *vp)
BOOL QuaternionToJSValue(JSContext *context, Quaternion quaternion, jsval *outValue)
static JSBool QuaternionGetProperty(JSContext *context, JSObject *this, jsid propID, jsval *value)
static JSBool QuaternionMultiply(JSContext *context, uintN argc, jsval *vp)
static JSBool QuaternionVectorForward(JSContext *context, uintN argc, jsval *vp)
static JSFunctionSpec sQuaternionMethods[]
#define COUNT(FIELD)
static JSPropertySpec sQuaternionProperties[]
@ kQuaternion_x
@ kQuaternion_w
@ kQuaternion_z
@ kQuaternion_y
static BOOL QuaternionFromArgumentListNoErrorInternal(JSContext *context, uintN argc, jsval *argv, Quaternion *outQuaternion, uintN *outConsumed, BOOL permitNumberList)
static JSBool QuaternionRotateZ(JSContext *context, uintN argc, jsval *vp)
static JSBool QuaternionVectorUp(JSContext *context, uintN argc, jsval *vp)
static JSBool QuaternionSetProperty(JSContext *context, JSObject *this, jsid propID, JSBool strict, jsval *value)
static void QuaternionFinalize(JSContext *context, JSObject *this)
static JSBool QuaternionConjugate(JSContext *context, uintN argc, jsval *vp)
static JSBool QuaternionNormalize(JSContext *context, uintN argc, jsval *vp)
static JSBool QuaternionDot(JSContext *context, uintN argc, jsval *vp)
static JSFunctionSpec sQuaternionStaticMethods[]
BOOL JSObjectGetQuaternion(JSContext *context, JSObject *quaternionObj, Quaternion *outQuaternion)
BOOL VectorFromArgumentList(JSContext *context, NSString *scriptClass, NSString *function, uintN argc, jsval *argv, HPVector *outVector, uintN *outConsumed) GCC_ATTR((nonnull(1
#define OOJS_THIS
BOOL OOJSArgumentListGetNumber(JSContext *context, NSString *scriptClass, NSString *function, uintN argc, jsval *argv, double *outNumber, uintN *outConsumed)
#define OOJS_SET_RVAL(v)
#define OOJS_PROP_READWRITE_CB
#define OOJS_RETURN_DOUBLE(value)
#define OOJS_RETURN_OBJECT(o)
void OOJSReportBadPropertySelector(JSContext *context, JSObject *thisObj, jsid propID, JSPropertySpec *propertySpec)
OOINLINE BOOL OOJSIsMemberOfSubclass(JSContext *context, JSObject *object, JSClass *superclass)
#define OOJS_RETURN_QUATERNION(value)
#define OOJS_ARGV
#define OOJS_RETURN_JSOBJECT(o)
void OOJSReportBadPropertyValue(JSContext *context, JSObject *thisObj, jsid propID, JSPropertySpec *propertySpec, jsval value)
void OOJSReportBadArguments(JSContext *context, NSString *scriptClass, NSString *function, uintN argc, jsval *argv, NSString *message, NSString *expectedArgsDescription)
#define OOJS_RETURN_VECTOR(value)
GLfloat OOScalar
Definition OOMaths.h:64
Vector vector_up_from_quaternion(Quaternion quat)
void quaternion_rotate_about_x(Quaternion *quat, OOScalar angle)
Vector vector_right_from_quaternion(Quaternion quat)
Vector vector_forward_from_quaternion(Quaternion quat)
void quaternion_rotate_about_z(Quaternion *quat, OOScalar angle)
const Quaternion kIdentityQuaternion
void quaternion_rotate_about_y(Quaternion *quat, OOScalar angle)
const Quaternion kZeroQuaternion
void quaternion_rotate_about_axis(Quaternion *quat, Vector axis, OOScalar angle)
Quaternion quaternion_multiply(Quaternion q1, Quaternion q2)
float y
float x
Quaternion orientation
Definition Entity.h:114