LCOV - code coverage report
Current view: top level - Core/Scripting - OOJSQuaternion.m (source / functions) Hit Total Coverage
Test: coverxygen.info Lines: 0 37 0.0 %
Date: 2025-05-28 07:50:54 Functions: 0 0 -

          Line data    Source code
       1           0 : /*
       2             : 
       3             : OOJSQuaternion.m
       4             : 
       5             : Oolite
       6             : Copyright (C) 2004-2013 Giles C Williams and contributors
       7             : 
       8             : This program is free software; you can redistribute it and/or
       9             : modify it under the terms of the GNU General Public License
      10             : as published by the Free Software Foundation; either version 2
      11             : of the License, or (at your option) any later version.
      12             : 
      13             : This program is distributed in the hope that it will be useful,
      14             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             : GNU General Public License for more details.
      17             : 
      18             : You should have received a copy of the GNU General Public License
      19             : along with this program; if not, write to the Free Software
      20             : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
      21             : MA 02110-1301, USA.
      22             : 
      23             : */
      24             : 
      25             : #import "OOJSQuaternion.h"
      26             : #import "OOJavaScriptEngine.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             : 
      39           0 : static JSObject *sQuaternionPrototype;
      40             : 
      41             : 
      42             : static BOOL GetThisQuaternion(JSContext *context, JSObject *quaternionObj, Quaternion *outQuaternion, NSString *method)  NONNULL_FUNC;
      43             : 
      44             : 
      45             : static JSBool QuaternionGetProperty(JSContext *context, JSObject *this, jsid propID, jsval *value);
      46             : static JSBool QuaternionSetProperty(JSContext *context, JSObject *this, jsid propID, JSBool strict, jsval *value);
      47             : static void QuaternionFinalize(JSContext *context, JSObject *this);
      48             : static JSBool QuaternionConstruct(JSContext *context, uintN argc, jsval *vp);
      49             : 
      50             : // Methods
      51             : static JSBool QuaternionToString(JSContext *context, uintN argc, jsval *vp);
      52             : static JSBool QuaternionToSource(JSContext *context, uintN argc, jsval *vp);
      53             : static JSBool QuaternionMultiply(JSContext *context, uintN argc, jsval *vp);
      54             : static JSBool QuaternionDot(JSContext *context, uintN argc, jsval *vp);
      55             : static JSBool QuaternionRotate(JSContext *context, uintN argc, jsval *vp);
      56             : static JSBool QuaternionRotateX(JSContext *context, uintN argc, jsval *vp);
      57             : static JSBool QuaternionRotateY(JSContext *context, uintN argc, jsval *vp);
      58             : static JSBool QuaternionRotateZ(JSContext *context, uintN argc, jsval *vp);
      59             : static JSBool QuaternionNormalize(JSContext *context, uintN argc, jsval *vp);
      60             : static JSBool QuaternionConjugate(JSContext *context, uintN argc, jsval *vp);
      61             : static JSBool QuaternionVectorForward(JSContext *context, uintN argc, jsval *vp);
      62             : static JSBool QuaternionVectorUp(JSContext *context, uintN argc, jsval *vp);
      63             : static JSBool QuaternionVectorRight(JSContext *context, uintN argc, jsval *vp);
      64             : static JSBool QuaternionToArray(JSContext *context, uintN argc, jsval *vp);
      65             : 
      66             : // Static methods
      67             : static JSBool QuaternionStaticRandom(JSContext *context, uintN argc, jsval *vp);
      68             : 
      69             : 
      70           0 : static 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             : 
      87           0 : enum
      88             : {
      89             :         // Property IDs
      90             :         kQuaternion_w,
      91             :         kQuaternion_x,
      92             :         kQuaternion_y,
      93             :         kQuaternion_z
      94             : };
      95             : 
      96             : 
      97           0 : static JSPropertySpec sQuaternionProperties[] =
      98             : {
      99             :         // JS name                                      ID                                                      flags
     100             :         { "w",                                                kQuaternion_w,                          OOJS_PROP_READWRITE_CB },
     101             :         { "x",                                                kQuaternion_x,                          OOJS_PROP_READWRITE_CB },
     102             :         { "y",                                                kQuaternion_y,                          OOJS_PROP_READWRITE_CB },
     103             :         { "z",                                                kQuaternion_z,                          OOJS_PROP_READWRITE_CB },
     104             :         { 0 }
     105             : };
     106             : 
     107             : 
     108           0 : static 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             : 
     129           0 : static JSFunctionSpec sQuaternionStaticMethods[] =
     130             : {
     131             :         // JS name                                      Function                                        min args
     132             :         { "random",                                   QuaternionStaticRandom,         0, },
     133             :         { 0 }
     134             : };
     135             : 
     136             : 
     137             : // *** Public ***
     138             : 
     139           0 : void InitOOJSQuaternion(JSContext *context, JSObject *global)
     140             : {
     141             :         sQuaternionPrototype = JS_InitClass(context, global, NULL, &sQuaternionClass, QuaternionConstruct, 4, sQuaternionProperties, sQuaternionMethods, NULL, sQuaternionStaticMethods);
     142             : }
     143             : 
     144             : 
     145           0 : JSObject *JSQuaternionWithQuaternion(JSContext *context, Quaternion quaternion)
     146             : {
     147             :         OOJS_PROFILE_ENTER
     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             :         
     167             :         OOJS_PROFILE_EXIT
     168             : }
     169             : 
     170             : 
     171           0 : BOOL QuaternionToJSValue(JSContext *context, Quaternion quaternion, jsval *outValue)
     172             : {
     173             :         OOJS_PROFILE_ENTER
     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             :         
     185             :         OOJS_PROFILE_EXIT
     186             : }
     187             : 
     188             : 
     189           0 : BOOL 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             : 
     199             : typedef struct
     200             : {
     201             :         NSUInteger                      quatCount;
     202             :         NSUInteger                      entityCount;
     203             :         NSUInteger                      arrayCount;
     204             :         NSUInteger                      protoCount;
     205             :         NSUInteger                      nullCount;
     206             :         NSUInteger                      failCount;
     207             : } QuaternionStatistics;
     208             : static 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           0 : #define COUNT(FIELD) do {} while (0)
     253             : 
     254             : #endif
     255             : 
     256             : 
     257           0 : BOOL JSObjectGetQuaternion(JSContext *context, JSObject *quaternionObj, Quaternion *outQuaternion)
     258             : {
     259             :         OOJS_PROFILE_ENTER
     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             :         
     337             :         OOJS_PROFILE_EXIT
     338             : }
     339             : 
     340             : 
     341           0 : static 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             : 
     351           0 : BOOL JSQuaternionSetQuaternion(JSContext *context, JSObject *quaternionObj, Quaternion quaternion)
     352             : {
     353             :         OOJS_PROFILE_ENTER
     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             :         
     374             :         OOJS_PROFILE_EXIT
     375             : }
     376             : 
     377             : 
     378           0 : static BOOL QuaternionFromArgumentListNoErrorInternal(JSContext *context, uintN argc, jsval *argv, Quaternion *outQuaternion, uintN *outConsumed, BOOL permitNumberList)
     379             : {
     380             :         OOJS_PROFILE_ENTER
     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             :         
     416             :         OOJS_PROFILE_EXIT
     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).
     421           0 : BOOL 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             : 
     434           0 : BOOL 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             : 
     442           0 : static JSBool QuaternionGetProperty(JSContext *context, JSObject *this, jsid propID, jsval *value)
     443             : {
     444             :         if (!JSID_IS_INT(propID))  return YES;
     445             :         
     446             :         OOJS_PROFILE_ENTER
     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:
     472             :                         OOJSReportBadPropertySelector(context, this, propID, sQuaternionProperties);
     473             :                         return NO;
     474             :         }
     475             :         
     476             :         return JS_NewNumberValue(context, fValue, value);
     477             :         
     478             :         OOJS_PROFILE_EXIT
     479             : }
     480             : 
     481             : 
     482           0 : static JSBool QuaternionSetProperty(JSContext *context, JSObject *this, jsid propID, JSBool strict, jsval *value)
     483             : {
     484             :         if (!JSID_IS_INT(propID))  return YES;
     485             :         
     486             :         OOJS_PROFILE_ENTER
     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:
     517             :                         OOJSReportBadPropertySelector(context, this, propID, sQuaternionProperties);
     518             :                         return NO;
     519             :         }
     520             :         
     521             :         return JSQuaternionSetQuaternion(context, this, quaternion);
     522             :         
     523             :         OOJS_PROFILE_EXIT
     524             : }
     525             : 
     526             : 
     527           0 : static 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             : 
     539           0 : static JSBool QuaternionConstruct(JSContext *context, uintN argc, jsval *vp)
     540             : {
     541             :         OOJS_PROFILE_ENTER
     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             :         
     573             :         OOJS_RETURN_JSOBJECT(this);
     574             :         
     575             :         OOJS_PROFILE_EXIT
     576             : }
     577             : 
     578             : 
     579             : // *** Methods ***
     580             : 
     581             : // toString() : String
     582           0 : static 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             :         
     592             :         OOJS_NATIVE_EXIT
     593             : }
     594             : 
     595             : 
     596             : // toSource() : String
     597           0 : static 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];
     606             :         OOJS_RETURN_OBJECT(str);
     607             :         
     608             :         OOJS_NATIVE_EXIT
     609             : }
     610             : 
     611             : 
     612             : // multiply(q : quaternionExpression) : Quaternion
     613           0 : static JSBool QuaternionMultiply(JSContext *context, uintN argc, jsval *vp)
     614             : {
     615             :         OOJS_PROFILE_ENTER
     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             :         
     624             :         OOJS_RETURN_QUATERNION(result);
     625             :         
     626             :         OOJS_PROFILE_EXIT
     627             : }
     628             : 
     629             : 
     630             : // dot(q : quaternionExpression) : Number
     631           0 : static JSBool QuaternionDot(JSContext *context, uintN argc, jsval *vp)
     632             : {
     633             :         OOJS_PROFILE_ENTER
     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             :         
     645             :         OOJS_PROFILE_EXIT
     646             : }
     647             : 
     648             : 
     649             : // rotate(axis : vectorExpression, angle : Number) : Quaternion
     650           0 : static JSBool QuaternionRotate(JSContext *context, uintN argc, jsval *vp)
     651             : {
     652             :         OOJS_PROFILE_ENTER
     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             :         
     671             :         OOJS_RETURN_QUATERNION(thisq);
     672             :         
     673             :         OOJS_PROFILE_EXIT
     674             : }
     675             : 
     676             : 
     677             : // rotateX(angle : Number) : Quaternion
     678           0 : static JSBool QuaternionRotateX(JSContext *context, uintN argc, jsval *vp)
     679             : {
     680             :         OOJS_PROFILE_ENTER
     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             :         
     690             :         OOJS_RETURN_QUATERNION(quat);
     691             :         
     692             :         OOJS_PROFILE_EXIT
     693             : }
     694             : 
     695             : 
     696             : // rotateY(angle : Number) : Quaternion
     697           0 : static JSBool QuaternionRotateY(JSContext *context, uintN argc, jsval *vp)
     698             : {
     699             :         OOJS_PROFILE_ENTER
     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             :         
     709             :         OOJS_RETURN_QUATERNION(quat);
     710             :         
     711             :         OOJS_PROFILE_EXIT
     712             : }
     713             : 
     714             : 
     715             : // rotateZ(angle : Number) : Quaternion
     716           0 : static JSBool QuaternionRotateZ(JSContext *context, uintN argc, jsval *vp)
     717             : {
     718             :         OOJS_PROFILE_ENTER
     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             :         
     728             :         OOJS_RETURN_QUATERNION(quat);
     729             :         
     730             :         OOJS_PROFILE_EXIT
     731             : }
     732             : 
     733             : 
     734             : // normalize() : Quaternion
     735           0 : static JSBool QuaternionNormalize(JSContext *context, uintN argc, jsval *vp)
     736             : {
     737             :         OOJS_PROFILE_ENTER
     738             :         
     739             :         Quaternion                              quat;
     740             :         
     741             :         if (EXPECT_NOT(!GetThisQuaternion(context, OOJS_THIS, &quat, @"normalize"))) return NO;
     742             :         
     743             :         quaternion_normalize(&quat);
     744             :         
     745             :         OOJS_RETURN_QUATERNION(quat);
     746             :         
     747             :         OOJS_PROFILE_EXIT
     748             : }
     749             : 
     750             : 
     751             : // conjugate() : Quaternion
     752           0 : static JSBool QuaternionConjugate(JSContext *context, uintN argc, jsval *vp)
     753             : {
     754             :         OOJS_PROFILE_ENTER
     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             :         
     762             :         OOJS_RETURN_QUATERNION(result);
     763             :         
     764             :         OOJS_PROFILE_EXIT
     765             : }
     766             : 
     767             : 
     768             : // vectorForward() : Vector
     769           0 : static JSBool QuaternionVectorForward(JSContext *context, uintN argc, jsval *vp)
     770             : {
     771             :         OOJS_PROFILE_ENTER
     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             :         
     782             :         OOJS_PROFILE_EXIT
     783             : }
     784             : 
     785             : 
     786             : // vectorUp() : Vector
     787           0 : static JSBool QuaternionVectorUp(JSContext *context, uintN argc, jsval *vp)
     788             : {
     789             :         OOJS_PROFILE_ENTER
     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             :         
     800             :         OOJS_PROFILE_EXIT
     801             : }
     802             : 
     803             : 
     804             : // vectorRight() : Vector
     805           0 : static JSBool QuaternionVectorRight(JSContext *context, uintN argc, jsval *vp)
     806             : {
     807             :         OOJS_PROFILE_ENTER
     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             :         
     818             :         OOJS_PROFILE_EXIT
     819             : }
     820             : 
     821             : 
     822             : // toArray() : Array
     823           0 : static JSBool QuaternionToArray(JSContext *context, uintN argc, jsval *vp)
     824             : {
     825             :         OOJS_PROFILE_ENTER
     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             :         
     853             :         OOJS_PROFILE_EXIT
     854             : }
     855             : 
     856             : 
     857             : // *** Static methods ***
     858             : 
     859             : // random() : Quaternion
     860           0 : static JSBool QuaternionStaticRandom(JSContext *context, uintN argc, jsval *vp)
     861             : {
     862             :         OOJS_PROFILE_ENTER
     863             :         
     864             :         OOJS_RETURN_QUATERNION(OORandomQuaternion());
     865             :         
     866             :         OOJS_PROFILE_EXIT
     867             : }

Generated by: LCOV version 1.14