source: cpp/frams/vm/classes/3dobject.cpp @ 951

Last change on this file since 951 was 951, checked in by Maciej Komosinski, 4 years ago

Fixed a bug in 3D orientation rotation (only concerns scripts)

  • Property svn:eol-style set to native
File size: 14.7 KB
RevLine 
[286]1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
[825]2// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
[286]3// See LICENSE.txt for details.
[121]4
[109]5#include <frams/util/3d.h>
6#include "3dobject.h"
7#include <frams/param/param.h>
8#include "collectionobj.h"
9
10ParamEntry* Pt3D_Ext::getStaticParamtab()
11{
12#define FIELDSTRUCT Pt3D_Ext
[343]13        static ParamEntry paramtab[] =
14        {
15                { "XYZ", 1, 18, "XYZ", "3D vector" },
[109]16
[343]17                { "x", 0, PARAM_NOSTATIC, "x", "f", FIELD(p.x), },
18                { "y", 0, PARAM_NOSTATIC, "y", "f", FIELD(p.y), },
19                { "z", 0, PARAM_NOSTATIC, "z", "f", FIELD(p.z), },
20                { "new", 0, 0, "create new XYZ object", "p oXYZ(f x,f y,f z)", PROCEDURE(p_new), "3D vectors objects can be also created using the (x,y,z) notation, i.e. var v=(1,2,3) is the same as var v=XYZ.new(1,2,3);", },
21                { "newFromVector", 0, 0, "create new XYZ object", "p oXYZ(oVector)", PROCEDURE(p_newFromVector), "used for deserialization" },
22                { "clone", 0, PARAM_NOSTATIC, "create new XYZ object copying the coordinates", "p oXYZ()", PROCEDURE(p_clone), "Note: copying object references does not create new objects. Use clone() if a new object is needed.\n\nExample:\nvar o1=(1,2,3), o2=o1, o3=o1.clone();\no1.y=9999;\n//o2 is now (1,9999,3) but o3 is still (1,2,3)", },
23                { "set", 0, PARAM_NOSTATIC, "set (copy) coordinates from another XYZ object", "p(oXYZ)", PROCEDURE(p_set), },
24                { "set3", 0, PARAM_NOSTATIC, "set individual 3 coordinates", "p(f x,f y,f z)", PROCEDURE(p_set3), },
25                { "add", 0, PARAM_NOSTATIC, "add", "p(oXYZ)", PROCEDURE(p_addvec), "Note: it does not return a new object, just modifies the existing one" },
26                { "sub", 0, PARAM_NOSTATIC, "subtract", "p(oXYZ)", PROCEDURE(p_subvec), "Note: it does not return a new object, just modifies the existing one" },
27                { "scale", 0, PARAM_NOSTATIC, "multiply by scalar", "p(f)", PROCEDURE(p_scale), },
28                { "length", 0, PARAM_READONLY | PARAM_NOSTATIC, "length", "f", GETONLY(length), },
29                { "normalize", 0, PARAM_NOSTATIC, "normalize", "p()", PROCEDURE(p_normalize), "scales the vector length to 1.0" },
30                { "toString", 0, PARAM_READONLY | PARAM_NOSTATIC, "textual form", "s", GETONLY(toString), },
31                { "toVector", 0, PARAM_READONLY | PARAM_NOSTATIC, "vector of [x,y,z]", "oVector", GETONLY(toVector), },
32                { "rotate", 0, PARAM_NOSTATIC, "rotate using Orient object", "p(oOrient)", PROCEDURE(p_rotate), },
33                { "revRotate", 0, PARAM_NOSTATIC, "reverse rotate using Orient object", "p(oOrient)", PROCEDURE(p_revrotate), },
34                { "get", 0, PARAM_NOSTATIC, "get one of coordinates", "p f(d index)", PROCEDURE(p_get), "this function makes the XYZ objects \"indexable\" (so you can use [] for accessing subsequent fields, like in Vector)", },
35                { 0, 0, 0, },
36        };
[109]37#undef FIELDSTRUCT
[343]38        return paramtab;
[109]39}
40
[343]41void Pt3D_Ext::p_new(ExtValue *args, ExtValue *ret)
[109]42{
[343]43        *ret = makeDynamicObject(new Pt3D_Ext(args[2].getDouble(), args[1].getDouble(), args[0].getDouble()));
[109]44}
45
[343]46static double doubleFromVec(VectorObject *vec, int i)
[109]47{
[343]48        if (i >= vec->data.size()) return 0;
49        ExtValue *v = (ExtValue*)vec->data.get(i);
50        if (v)
51                return v->getDouble();
52        return 0;
[109]53}
54
[343]55static Pt3D pt3DFromVec(VectorObject* v, int offset = 0)
[109]56{
[343]57        return Pt3D(doubleFromVec(v, offset), doubleFromVec(v, offset + 1), doubleFromVec(v, offset + 2));
[109]58}
59
[343]60void Pt3D_Ext::p_newFromVector(ExtValue *args, ExtValue *ret)
[109]61{
[343]62        VectorObject *vec = VectorObject::fromObject(args->getObject());
63        if (vec)
64                *ret = makeDynamicObject(new Pt3D_Ext(pt3DFromVec(vec)));
65        else
66                ret->setEmpty();
[109]67}
68
[343]69void Pt3D_Ext::p_clone(ExtValue *args, ExtValue *ret)
[109]70{
[343]71        *ret = makeDynamicObject(new Pt3D_Ext(p.x, p.y, p.z));
[109]72}
73
[343]74void Pt3D_Ext::p_set3(ExtValue *args, ExtValue *ret)
[109]75{
[343]76        p.x = args[2].getDouble();
77        p.y = args[1].getDouble();
78        p.z = args[0].getDouble();
79        ret->setEmpty();
[109]80}
81
[343]82void Pt3D_Ext::p_set(ExtValue *args, ExtValue *ret)
[109]83{
[343]84        Pt3D_Ext *other = fromObject(args[0]);
85        if (other)
86                p = other->p;
87        ret->setEmpty();
[109]88}
89
90void Pt3D_Ext::get_length(ExtValue *ret)
91{
[343]92        ret->setDouble(p.length());
[109]93}
94
[825]95SString Pt3D_Ext::toString() const
[109]96{
[343]97        SString s = "(";
[825]98        s += SString::valueOf(p.x);
[343]99        s += ",";
[825]100        s += SString::valueOf(p.y);
[343]101        s += ",";
[825]102        s += SString::valueOf(p.z);
[343]103        s += ")";
[825]104        return s;
[109]105}
106
[825]107void Pt3D_Ext::get_toString(ExtValue *ret)
108{
109        ret->setString(toString());
110}
111
[343]112static void add3Coords(VectorObject* vec, const Pt3D& p)
[109]113{
[343]114        vec->data += new ExtValue(p.x);
115        vec->data += new ExtValue(p.y);
116        vec->data += new ExtValue(p.z);
[109]117}
118
119void Pt3D_Ext::get_toVector(ExtValue *ret)
120{
[343]121        VectorObject *vec = new VectorObject;
122        add3Coords(vec, p);
123        ret->setObject(ExtObject(&VectorObject::par, vec));
[109]124}
125
[343]126void Pt3D_Ext::p_addvec(ExtValue *args, ExtValue *ret)
[109]127{
[343]128        Pt3D_Ext *other = fromObject(args[0]);
129        if (other)
130                p += other->p;
131        ret->setEmpty();
[109]132}
133
[343]134void Pt3D_Ext::p_subvec(ExtValue *args, ExtValue *ret)
[109]135{
[343]136        Pt3D_Ext *other = fromObject(args[0]);
137        if (other)
138                p -= other->p;
139        ret->setEmpty();
[109]140}
141
[343]142void Pt3D_Ext::p_scale(ExtValue *args, ExtValue *ret)
[109]143{
[343]144        double d = args[0].getDouble();
145        p.x *= d; p.y *= d; p.z *= d;
146        ret->setEmpty();
[109]147}
148
[343]149void Pt3D_Ext::p_normalize(ExtValue *args, ExtValue *ret)
[109]150{
[343]151        p.normalize();
152        ret->setEmpty();
[109]153}
154
[343]155void Pt3D_Ext::p_rotate(ExtValue *args, ExtValue *ret)
[109]156{
[343]157        Orient_Ext *o = Orient_Ext::fromObject(args[0]);
158        if (o)
[109]159        {
[343]160                Pt3D tmp = p;
161                o->o.transform(p, tmp);
[109]162        }
[343]163        ret->setEmpty();
[109]164}
165
[343]166void Pt3D_Ext::p_revrotate(ExtValue *args, ExtValue *ret)
[109]167{
[343]168        Orient_Ext *o = Orient_Ext::fromObject(args[0]);
169        if (o)
[109]170        {
[343]171                Pt3D tmp = p;
172                o->o.revTransform(p, tmp);
[109]173        }
[343]174        ret->setEmpty();
[109]175}
176
[343]177void Pt3D_Ext::p_get(ExtValue *args, ExtValue *ret)
[109]178{
[343]179        int index = args->getInt();
[825]180        if ((index < 0) || (index > 2))
[343]181                ret->setEmpty();
182        else
183                ret->setDouble((&p.x)[index]);
[109]184}
185
186Param& Pt3D_Ext::getStaticParam()
187{
188#ifdef __CODEGUARD__
[343]189        static Pt3D_Ext static_pt3dobj;
[825]190        static Param static_pt3dparam(getStaticParamtab(), &static_pt3dobj);
[109]191#else
[343]192        static Param static_pt3dparam(getStaticParamtab());
[109]193#endif
[343]194        return static_pt3dparam;
[109]195}
196
[343]197Pt3D_Ext* Pt3D_Ext::fromObject(const ExtValue& v, bool warn)
[109]198{
[343]199        return (Pt3D_Ext*)v.getObjectTarget(getStaticParam().getName(), warn);
[109]200}
201
[343]202ParamInterface* Pt3D_Ext::getInterface() { return &getStaticParam(); }
[109]203
204ExtObject Pt3D_Ext::makeStaticObject(Pt3D* p)
[343]205{
206        return ExtObject(&getStaticParam(), ((char*)p) + (((char*)&p->x) - ((char*)&((Pt3D_Ext*)p)->p.x)));
207}
[109]208
209ExtObject Pt3D_Ext::makeDynamicObject(Pt3D_Ext* p)
[343]210{
211        return ExtObject(&getStaticParam(), p);
212}
[109]213
[222]214ExtObject Pt3D_Ext::makeDynamicObject(const Pt3D& p)
215{
[343]216        Pt3D_Ext *pe = new Pt3D_Ext(p);
217        return ExtObject(&getStaticParam(), pe);
[222]218}
219
[109]220//////////////////////////////////////
221
222ParamEntry* Orient_Ext::getStaticParamtab()
223{
224#define FIELDSTRUCT Orient_Ext
[343]225        static ParamEntry paramtab[] =
226        {
227                { "Orient", 1, 29, "Orient", "3D orientation, stored as 3x3 matrix." },
[109]228
[343]229                { "xx", 1, PARAM_NOSTATIC, "orientation.x.x", "f", FIELD(o.x.x), },
230                { "xy", 1, PARAM_NOSTATIC, "orientation.x.y", "f", FIELD(o.x.y), },
231                { "xz", 1, PARAM_NOSTATIC, "orientation.x.z", "f", FIELD(o.x.z), },
232                { "yx", 1, PARAM_NOSTATIC, "orientation.y.x", "f", FIELD(o.y.x), },
233                { "yy", 1, PARAM_NOSTATIC, "orientation.y.y", "f", FIELD(o.y.y), },
234                { "yz", 1, PARAM_NOSTATIC, "orientation.y.z", "f", FIELD(o.y.z), },
235                { "zx", 1, PARAM_NOSTATIC, "orientation.z.x", "f", FIELD(o.z.x), },
236                { "zy", 1, PARAM_NOSTATIC, "orientation.z.y", "f", FIELD(o.z.y), },
237                { "zz", 1, PARAM_NOSTATIC, "orientation.z.z", "f", FIELD(o.z.z), },
[109]238
[343]239                { "x", 0, PARAM_NOSTATIC | PARAM_READONLY, "x vector", "oXYZ", GETONLY(x), },
240                { "y", 0, PARAM_NOSTATIC | PARAM_READONLY, "y vector", "oXYZ", GETONLY(y), },
241                { "z", 0, PARAM_NOSTATIC | PARAM_READONLY, "z vector", "oXYZ", GETONLY(z), },
[109]242
[343]243                { "new", 0, 0, "create new Orient object", "p oOrient()", PROCEDURE(p_new), },
244                { "newFromVector", 0, 0, "create new Orient object", "p oOrient(oVector)", PROCEDURE(p_newFromVector), },
245                { "toVector", 0, PARAM_READONLY | PARAM_NOSTATIC, "vector representation", "oVector", GETONLY(toVector), "for serialization" },
246                { "clone", 0, PARAM_NOSTATIC, "create new Orient object", "p oOrient()", PROCEDURE(p_clone), },
247                { "set", 0, PARAM_NOSTATIC, "copy from another Orient object", "p(oOrient)", PROCEDURE(p_set), },
248                { "reset", 0, PARAM_NOSTATIC, "set identity matrix", "p()", PROCEDURE(p_reset), },
249                { "rotate3", 0, PARAM_NOSTATIC, "rotate around 3 axes", "p(f x,f y,f z)", PROCEDURE(p_rotate3), },
250                { "rotate", 0, PARAM_NOSTATIC, "rotate using Orient object", "p(oOrient)", PROCEDURE(p_rotate), },
251                { "revRotate", 0, PARAM_NOSTATIC, "reverse rotate using Orient object", "p(oOrient)", PROCEDURE(p_revrotate), },
252                { "lookAt", 0, PARAM_NOSTATIC, "calculate rotation from 2 vectors", "p(oXYZ direction,oXYZ up)", PROCEDURE(p_lookat), },
253                { "normalize", 0, PARAM_NOSTATIC, "normalize", "p()", PROCEDURE(p_normalize), },
254                { "between2", 0, PARAM_NOSTATIC, "interpolate orientation", "p(oOrient,oOrient,f amount)", PROCEDURE(p_between2), "The calling Orient receives the orientation interpolated from 2 input orientations.\nExample:\n"
255                "var o1=Orient.new(), o2=Orient.new(), o3=Orient.new();\n"
256                "o2.rotate3(0,Math.pi/2,0);\n"
257                "o3.between2(o1,o2,0); // o3 equals o2\n"
258                "o3.between2(o1,o2,1); // o3 equals o1\n"
259                "o3.between2(o1,o2,0.5); // o3 is halfway between o1 and o2\n" },
260                { "betweenOV", 0, PARAM_NOSTATIC, "interpolate orientation", "p(oOrient,oXYZ,f amount)", PROCEDURE(p_betweenOV), "Like between2(), but the second Orient is composed of the supplied XYZ vector (X component) and Y Z vectors from the calling object.\n"
261                "Example:\n"
262                "var o=Orient.new();\n"
263                "o.betweenOV(o,(0,1,0),1); //no change, o remains 100 010 001\n"
264                "o.betweenOV(o,(0,1,0),0.9); //o is slightly rotated towards (0,1,0)\n"
265                "o.betweenOV(o,(0,1,0),0); //o is completely transformed, o.x=(0,1,0)\n"
266                },
267                { "localToWorld", 0, PARAM_NOSTATIC, "transform coordinates", "p oXYZ(oXYZ point,oXYZ center)", PROCEDURE(p_localToWorld), },
268                { "worldToLocal", 0, PARAM_NOSTATIC, "transform coordinates", "p oXYZ(oXYZ point,oXYZ center)", PROCEDURE(p_worldToLocal), },
269                { "angles", 0, PARAM_READONLY | PARAM_NOSTATIC, "Euler angles representation", "oXYZ", GETONLY(angles), },
270                { "toString", 0, PARAM_READONLY | PARAM_NOSTATIC, "textual form", "s", GETONLY(toString), },
271                { 0, 0, 0, },
272        };
[109]273#undef FIELDSTRUCT
[343]274        return paramtab;
[109]275}
276
[343]277void Orient_Ext::p_new(ExtValue *args, ExtValue *ret)
[109]278{
[343]279        *ret = makeDynamicObject(new Orient_Ext());
[109]280}
281
[343]282void Orient_Ext::p_newFromVector(ExtValue *args, ExtValue *ret)
[109]283{
[343]284        VectorObject *vec = VectorObject::fromObject(args->getObject());
285        if (vec)
286                *ret = makeDynamicObject(new Orient_Ext(Orient(pt3DFromVec(vec, 0), pt3DFromVec(vec, 3), pt3DFromVec(vec, 6))));
287        else
288                ret->setEmpty();
[109]289}
290
291void Orient_Ext::get_toVector(ExtValue *ret)
292{
[343]293        VectorObject *vec = new VectorObject;
294        add3Coords(vec, o.x);
295        add3Coords(vec, o.y);
296        add3Coords(vec, o.z);
297        ret->setObject(ExtObject(&VectorObject::par, vec));
[109]298}
299
[343]300void Orient_Ext::p_clone(ExtValue *args, ExtValue *ret)
[109]301{
[343]302        *ret = makeDynamicObject(new Orient_Ext(o));
[109]303}
304
[343]305void Orient_Ext::p_set(ExtValue *args, ExtValue *ret)
[109]306{
[343]307        Orient_Ext *other = fromObject(args[0]);
308        if (other)
309                o = other->o;
310        ret->setEmpty();
[109]311}
312
[343]313void Orient_Ext::p_reset(ExtValue *args, ExtValue *ret)
[109]314{
[343]315        o = Orient_1;
316        ret->setEmpty();
[109]317}
318
319void Orient_Ext::get_x(PARAMGETARGS)
320{
[343]321        *ret = Pt3D_Ext::makeStaticObject(&o.x);
[109]322}
323
324void Orient_Ext::get_y(PARAMGETARGS)
325{
[343]326        *ret = Pt3D_Ext::makeStaticObject(&o.y);
[109]327}
328
329void Orient_Ext::get_z(PARAMGETARGS)
330{
[343]331        *ret = Pt3D_Ext::makeStaticObject(&o.z);
[109]332}
333
[343]334void Orient_Ext::p_lookat(ExtValue *args, ExtValue *ret)
[109]335{
[343]336        Pt3D_Ext *dir = Pt3D_Ext::fromObject(args[1]), *up = Pt3D_Ext::fromObject(args[0]);
337        if (dir&&up)
338                o.lookAt(dir->p, up->p);
339        ret->setEmpty();
[109]340}
341
[343]342void Orient_Ext::p_rotate3(ExtValue *args, ExtValue *ret)
[109]343{
[343]344        Pt3D p(args[2].getDouble(), args[1].getDouble(), args[0].getDouble());
345        o.rotate(p);
346        ret->setEmpty();
[109]347}
348
[343]349void Orient_Ext::p_rotate(ExtValue *args, ExtValue *ret)
[109]350{
[343]351        Orient_Ext *obj = Orient_Ext::fromObject(args[0]);
[951]352        if (obj)
[109]353        {
[343]354                Orient tmp = o;
355                obj->o.transform(o, tmp);
[109]356        }
[343]357        ret->setEmpty();
[109]358}
359
[343]360void Orient_Ext::p_revrotate(ExtValue *args, ExtValue *ret)
[109]361{
[343]362        Orient_Ext *obj = Orient_Ext::fromObject(args[0]);
363        if (obj)
[109]364        {
[343]365                Orient tmp = o;
366                obj->o.revTransform(o, tmp);
[109]367        }
[343]368        ret->setEmpty();
[109]369}
370
[343]371void Orient_Ext::p_normalize(ExtValue *args, ExtValue *ret)
[109]372{
[343]373        o.normalize();
374        ret->setEmpty();
[109]375}
376
[343]377void Orient_Ext::p_between2(ExtValue *args, ExtValue *ret)
[109]378{
[343]379        Orient_Ext *o1 = Orient_Ext::fromObject(args[2]);
380        Orient_Ext *o2 = Orient_Ext::fromObject(args[1]);
381        if (o1&&o2)
[109]382        {
[343]383                double q1 = args[0].getDouble(), q2 = 1.0 - q1;
[825]384                o.x.x = q1 * o1->o.x.x + q2 * o2->o.x.x;
385                o.x.y = q1 * o1->o.x.y + q2 * o2->o.x.y;
386                o.x.z = q1 * o1->o.x.z + q2 * o2->o.x.z;
387                o.y.x = q1 * o1->o.y.x + q2 * o2->o.y.x;
388                o.y.y = q1 * o1->o.y.y + q2 * o2->o.y.y;
389                o.y.z = q1 * o1->o.y.z + q2 * o2->o.y.z;
390                o.z.x = q1 * o1->o.z.x + q2 * o2->o.z.x;
391                o.z.y = q1 * o1->o.z.y + q2 * o2->o.z.y;
392                o.z.z = q1 * o1->o.z.z + q2 * o2->o.z.z;
[343]393                o.normalize();
[109]394        }
[343]395        ret->setEmpty();
[109]396}
397
[343]398void Orient_Ext::p_betweenOV(ExtValue *args, ExtValue *ret)
[109]399{
[343]400        Orient_Ext *o1 = Orient_Ext::fromObject(args[2]);
401        Pt3D_Ext *p2 = Pt3D_Ext::fromObject(args[1]);
402        if (o1&&p2)
[109]403        {
[343]404                double q1 = args[0].getDouble(), q2 = 1.0 - q1;
[825]405                o.x.x = q1 * o1->o.x.x + q2 * p2->p.x;
406                o.x.y = q1 * o1->o.x.y + q2 * p2->p.y;
407                o.x.z = q1 * o1->o.x.z + q2 * p2->p.z;
[343]408                o.normalize();
[109]409        }
[343]410        ret->setEmpty();
[109]411}
412
[343]413void Orient_Ext::p_localToWorld(ExtValue *args, ExtValue *ret)
[109]414{
[343]415        Pt3D_Ext *center, *point;
416        point = Pt3D_Ext::fromObject(args[1]);
417        center = Pt3D_Ext::fromObject(args[0]);
418        if (center && point)
[109]419        {
[343]420                Pt3D d;
421                Pt3D src = point->p;
422                o.transform(d, src);
423                d += center->p;
424                *ret = Pt3D_Ext::makeDynamicObject(new Pt3D_Ext(d));
[109]425        }
[343]426        else
427                ret->setEmpty();
[109]428}
429
[343]430void Orient_Ext::p_worldToLocal(ExtValue *args, ExtValue *ret)
[109]431{
[343]432        Pt3D_Ext *center, *point;
433        point = Pt3D_Ext::fromObject(args[1]);
434        center = Pt3D_Ext::fromObject(args[0]);
435        if (center && point)
[109]436        {
[343]437                Pt3D d;
438                Pt3D src = point->p;
439                d -= center->p;
440                o.revTransform(d, src);
441                *ret = Pt3D_Ext::makeDynamicObject(new Pt3D_Ext(d));
[109]442        }
[343]443        else
444                ret->setEmpty();
[109]445}
446
[241]447void Orient_Ext::get_angles(ExtValue *ret)
448{
[343]449        *ret = Pt3D_Ext::makeDynamicObject(new Pt3D_Ext(o.getAngles()));
[241]450}
451
452void Orient_Ext::get_toString(ExtValue *ret)
453{
[825]454        Pt3D_Ext a(o.getAngles());
455        ret->setString(SString("Orient@") + a.toString());
[241]456}
457
[109]458Param& Orient_Ext::getStaticParam()
459{
460#ifdef __CODEGUARD__
[343]461        static Orient_Ext static_orientobj;
[825]462        static Param static_orientparam(getStaticParamtab(), &static_orientobj);
[109]463#else
[343]464        static Param static_orientparam(getStaticParamtab());
[109]465#endif
[343]466        return static_orientparam;
[109]467}
468
469Orient_Ext* Orient_Ext::fromObject(const ExtValue& v)
470{
[343]471        return (Orient_Ext*)v.getObjectTarget(getStaticParam().getName());
[109]472}
473
[343]474ParamInterface* Orient_Ext::getInterface() { return &getStaticParam(); }
[109]475
476ExtObject Orient_Ext::makeStaticObject(Orient* o)
[343]477{
478        return ExtObject(&getStaticParam(), ((char*)o) + (((char*)&o->x) - ((char*)&((Orient_Ext*)o)->o.x)));
479}
[109]480
481ExtObject Orient_Ext::makeDynamicObject(Orient_Ext* p)
[343]482{
483        return ExtObject(&getStaticParam(), p);
484}
[109]485
[222]486/////////////
487
488REGISTER_DESERIALIZABLE(Pt3D_Ext)
489REGISTER_DESERIALIZABLE(Orient_Ext)
Note: See TracBrowser for help on using the repository browser.