// This file is a part of the Framsticks GDK. // Copyright (C) 2002-2014 Maciej Komosinski and Szymon Ulatowski. See LICENSE.txt for details. // Refer to http://www.framsticks.com/ for further information. #include #include "3dobject.h" #include #include "collectionobj.h" ParamEntry* Pt3D_Ext::getStaticParamtab() { #define FIELDSTRUCT Pt3D_Ext static ParamEntry paramtab[]= { {"XYZ",1,18,"XYZ","3D vector"}, {"x",0,PARAM_NOSTATIC,"x","f",FIELD(p.x),}, {"y",0,PARAM_NOSTATIC,"y","f",FIELD(p.y),}, {"z",0,PARAM_NOSTATIC,"z","f",FIELD(p.z),}, {"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);",}, {"newFromVector",0,0,"create new XYZ object","p oXYZ(oVector)",PROCEDURE(p_newFromVector),"used for deserialization"}, {"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)",}, {"set",0,PARAM_NOSTATIC,"set (copy) coordinates from another XYZ object","p(oXYZ)",PROCEDURE(p_set),}, {"set3",0,PARAM_NOSTATIC,"set individual 3 coordinates","p(f x,f y,f z)",PROCEDURE(p_set3),}, {"add",0,PARAM_NOSTATIC,"add","p(oXYZ)",PROCEDURE(p_addvec),"Note: it does not return a new object, just modifies the existing one"}, {"sub",0,PARAM_NOSTATIC,"subtract","p(oXYZ)",PROCEDURE(p_subvec),"Note: it does not return a new object, just modifies the existing one"}, {"scale",0,PARAM_NOSTATIC,"multiply by scalar","p(f)",PROCEDURE(p_scale),}, {"length",0,PARAM_READONLY+PARAM_NOSTATIC,"length","f",GETONLY(length),}, {"normalize",0,PARAM_NOSTATIC,"normalize","p()",PROCEDURE(p_normalize),"scales the vector length to 1.0"}, {"toString",0,PARAM_READONLY+PARAM_NOSTATIC,"textual form","s",GETONLY(toString),}, {"toVector",0,PARAM_READONLY+PARAM_NOSTATIC,"vector of [x,y,z]","oVector",GETONLY(toVector),}, {"rotate",0,PARAM_NOSTATIC,"rotate using Orient object","p(oOrient)",PROCEDURE(p_rotate),}, {"revRotate",0,PARAM_NOSTATIC,"reverse rotate using Orient object","p(oOrient)",PROCEDURE(p_revrotate),}, {"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)",}, {0,0,0,}, }; #undef FIELDSTRUCT return paramtab; } void Pt3D_Ext::p_new(ExtValue *args,ExtValue *ret) { *ret=makeDynamicObject(new Pt3D_Ext(args[2].getDouble(),args[1].getDouble(),args[0].getDouble())); } static double doubleFromVec(VectorObject *vec,int i) { if (i>=vec->data.size()) return 0; ExtValue *v=(ExtValue*)vec->data.get(i); if (v) return v->getDouble(); return 0; } static Pt3D pt3DFromVec(VectorObject* v,int offset=0) { return Pt3D(doubleFromVec(v,offset),doubleFromVec(v,offset+1),doubleFromVec(v,offset+2)); } void Pt3D_Ext::p_newFromVector(ExtValue *args,ExtValue *ret) { VectorObject *vec=VectorObject::fromObject(args->getObject()); if (vec) *ret=makeDynamicObject(new Pt3D_Ext(pt3DFromVec(vec))); else ret->setEmpty(); } void Pt3D_Ext::p_clone(ExtValue *args,ExtValue *ret) { *ret=makeDynamicObject(new Pt3D_Ext(p.x,p.y,p.z)); } void Pt3D_Ext::p_set3(ExtValue *args,ExtValue *ret) { p.x=args[2].getDouble(); p.y=args[1].getDouble(); p.z=args[0].getDouble(); ret->setEmpty(); } void Pt3D_Ext::p_set(ExtValue *args,ExtValue *ret) { Pt3D_Ext *other=fromObject(args[0]); if (other) p=other->p; ret->setEmpty(); } void Pt3D_Ext::get_length(ExtValue *ret) { ret->setDouble(p.length()); } void Pt3D_Ext::get_toString(ExtValue *ret) { SString s="("; ExtValue v; v.setDouble(p.x); s+=v.getString(); s+=","; v.setDouble(p.y); s+=v.getString(); s+=","; v.setDouble(p.z); s+=v.getString(); s+=")"; ret->setString(s); } static void add3Coords(VectorObject* vec,const Pt3D& p) { vec->data+=new ExtValue(p.x); vec->data+=new ExtValue(p.y); vec->data+=new ExtValue(p.z); } void Pt3D_Ext::get_toVector(ExtValue *ret) { VectorObject *vec=new VectorObject; add3Coords(vec,p); ret->setObject(ExtObject(&VectorObject::par,vec)); } void Pt3D_Ext::p_addvec(ExtValue *args,ExtValue *ret) { Pt3D_Ext *other=fromObject(args[0]); if (other) p+=other->p; ret->setEmpty(); } void Pt3D_Ext::p_subvec(ExtValue *args,ExtValue *ret) { Pt3D_Ext *other=fromObject(args[0]); if (other) p-=other->p; ret->setEmpty(); } void Pt3D_Ext::p_scale(ExtValue *args,ExtValue *ret) { double d=args[0].getDouble(); p.x*=d; p.y*=d; p.z*=d; ret->setEmpty(); } void Pt3D_Ext::p_normalize(ExtValue *args,ExtValue *ret) { p.normalize(); ret->setEmpty(); } void Pt3D_Ext::p_rotate(ExtValue *args,ExtValue *ret) { Orient_Ext *o=Orient_Ext::fromObject(args[0]); if (o) { Pt3D tmp=p; o->o.transform(p,tmp); } ret->setEmpty(); } void Pt3D_Ext::p_revrotate(ExtValue *args,ExtValue *ret) { Orient_Ext *o=Orient_Ext::fromObject(args[0]); if (o) { Pt3D tmp=p; o->o.revTransform(p,tmp); } ret->setEmpty(); } void Pt3D_Ext::p_get(ExtValue *args,ExtValue *ret) { int index=args->getInt(); if ((index<0)||(index>2)) ret->setEmpty(); else ret->setDouble((&p.x)[index]); } Param& Pt3D_Ext::getStaticParam() { #ifdef __CODEGUARD__ static Pt3D_Ext static_pt3dobj; static Param static_pt3dparam(getStaticParamtab(),&static_pt3dobj); #else static Param static_pt3dparam(getStaticParamtab()); #endif return static_pt3dparam; } Pt3D_Ext* Pt3D_Ext::fromObject(const ExtValue& v) { return (Pt3D_Ext*)v.getObjectTarget(getStaticParam().getName()); } ParamInterface* Pt3D_Ext::getInterface() {return &getStaticParam();} ExtObject Pt3D_Ext::makeStaticObject(Pt3D* p) {return ExtObject(&getStaticParam(),((char*)p)+(((char*)&p->x)-((char*)&((Pt3D_Ext*)p)->p.x)));} ExtObject Pt3D_Ext::makeDynamicObject(Pt3D_Ext* p) {return ExtObject(&getStaticParam(),p);} ////////////////////////////////////// ParamEntry* Orient_Ext::getStaticParamtab() { #define FIELDSTRUCT Orient_Ext static ParamEntry paramtab[]= { {"Orient",1,27,"Orient","3D orientation, stored as 3x3 matrix."}, {"xx",1,PARAM_NOSTATIC,"orientation.x.x","f",FIELD(o.x.x),}, {"xy",1,PARAM_NOSTATIC,"orientation.x.y","f",FIELD(o.x.y),}, {"xz",1,PARAM_NOSTATIC,"orientation.x.z","f",FIELD(o.x.z),}, {"yx",1,PARAM_NOSTATIC,"orientation.y.x","f",FIELD(o.y.x),}, {"yy",1,PARAM_NOSTATIC,"orientation.y.y","f",FIELD(o.y.y),}, {"yz",1,PARAM_NOSTATIC,"orientation.y.z","f",FIELD(o.y.z),}, {"zx",1,PARAM_NOSTATIC,"orientation.z.x","f",FIELD(o.z.x),}, {"zy",1,PARAM_NOSTATIC,"orientation.z.y","f",FIELD(o.z.y),}, {"zz",1,PARAM_NOSTATIC,"orientation.z.z","f",FIELD(o.z.z),}, {"x",0,PARAM_NOSTATIC+PARAM_READONLY,"x vector","oXYZ",GETONLY(x),}, {"y",0,PARAM_NOSTATIC+PARAM_READONLY,"y vector","oXYZ",GETONLY(y),}, {"z",0,PARAM_NOSTATIC+PARAM_READONLY,"z vector","oXYZ",GETONLY(z),}, {"new",0,0,"create new Orient object","p oOrient()",PROCEDURE(p_new),}, {"newFromVector",0,0,"create new Orient object","p oOrient(oVector)",PROCEDURE(p_newFromVector),}, {"toVector",0,PARAM_READONLY+PARAM_NOSTATIC,"vector representation","oVector",GETONLY(toVector),"for serialization"}, {"clone",0,PARAM_NOSTATIC,"create new Orient object","p oOrient()",PROCEDURE(p_clone),}, {"set",0,PARAM_NOSTATIC,"copy from another Orient object","p(oOrient)",PROCEDURE(p_set),}, {"reset",0,PARAM_NOSTATIC,"set identity matrix","p()",PROCEDURE(p_reset),}, {"rotate3",0,PARAM_NOSTATIC,"rotate around 3 axes","p(f x,f y,f z)",PROCEDURE(p_rotate3),}, {"rotate",0,PARAM_NOSTATIC,"rotate using Orient object","p(oOrient)",PROCEDURE(p_rotate),}, {"revRotate",0,PARAM_NOSTATIC,"reverse rotate using Orient object","p(oOrient)",PROCEDURE(p_revrotate),}, {"lookAt",0,PARAM_NOSTATIC,"calculate rotation from 2 vectors","p(oXYZ direction,oXYZ up)",PROCEDURE(p_lookat),}, {"normalize",0,PARAM_NOSTATIC,"normalize","p()",PROCEDURE(p_normalize),}, {"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" "var o1=Orient.new(), o2=Orient.new(), o3=Orient.new();\n" "o2.rotate3(0,Math.pi/2,0);\n" "o3.between2(o1,o2,0); // o3 equals o2\n" "o3.between2(o1,o2,1); // o3 equals o1\n" "o3.between2(o1,o2,0.5); // o3 is halfway between o1 and o2\n"}, {"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" "Example:\n" "var o=Orient.new();\n" "o.betweenOV(o,(0,1,0),1); //no change, o remains 100 010 001\n" "o.betweenOV(o,(0,1,0),0.9); //o is slightly rotated towards (0,1,0)\n" "o.betweenOV(o,(0,1,0),0); //o is completely transformed, o.x=(0,1,0)\n" }, {"localToWorld",0,PARAM_NOSTATIC,"transform coordinates","p oXYZ(oXYZ point,oXYZ center)",PROCEDURE(p_localToWorld),}, {"worldToLocal",0,PARAM_NOSTATIC,"transform coordinates","p oXYZ(oXYZ point,oXYZ center)",PROCEDURE(p_worldToLocal),}, {0,0,0,}, }; #undef FIELDSTRUCT return paramtab; } void Orient_Ext::p_new(ExtValue *args,ExtValue *ret) { *ret=makeDynamicObject(new Orient_Ext()); } void Orient_Ext::p_newFromVector(ExtValue *args,ExtValue *ret) { VectorObject *vec=VectorObject::fromObject(args->getObject()); if (vec) *ret=makeDynamicObject(new Orient_Ext(Orient(pt3DFromVec(vec,0),pt3DFromVec(vec,3),pt3DFromVec(vec,6)))); else ret->setEmpty(); } void Orient_Ext::get_toVector(ExtValue *ret) { VectorObject *vec=new VectorObject; add3Coords(vec,o.x); add3Coords(vec,o.y); add3Coords(vec,o.z); ret->setObject(ExtObject(&VectorObject::par,vec)); } void Orient_Ext::p_clone(ExtValue *args,ExtValue *ret) { *ret=makeDynamicObject(new Orient_Ext(o)); } void Orient_Ext::p_set(ExtValue *args,ExtValue *ret) { Orient_Ext *other=fromObject(args[0]); if (other) o=other->o; ret->setEmpty(); } void Orient_Ext::p_reset(ExtValue *args,ExtValue *ret) { o=Orient_1; ret->setEmpty(); } void Orient_Ext::get_x(PARAMGETARGS) { *ret=Pt3D_Ext::makeStaticObject(&o.x); } void Orient_Ext::get_y(PARAMGETARGS) { *ret=Pt3D_Ext::makeStaticObject(&o.y); } void Orient_Ext::get_z(PARAMGETARGS) { *ret=Pt3D_Ext::makeStaticObject(&o.z); } void Orient_Ext::p_lookat(ExtValue *args,ExtValue *ret) { Pt3D_Ext *dir=Pt3D_Ext::fromObject(args[1]),*up=Pt3D_Ext::fromObject(args[0]); if (dir&&up) o.lookAt(dir->p,up->p); ret->setEmpty(); } void Orient_Ext::p_rotate3(ExtValue *args,ExtValue *ret) { Pt3D p(args[2].getDouble(),args[1].getDouble(),args[0].getDouble()); o.rotate(p); ret->setEmpty(); } void Orient_Ext::p_rotate(ExtValue *args,ExtValue *ret) { Orient_Ext *obj=Orient_Ext::fromObject(args[0]); if (!obj) { Orient tmp=o; obj->o.transform(o,tmp); } ret->setEmpty(); } void Orient_Ext::p_revrotate(ExtValue *args,ExtValue *ret) { Orient_Ext *obj=Orient_Ext::fromObject(args[0]); if (obj) { Orient tmp=o; obj->o.revTransform(o,tmp); } ret->setEmpty(); } void Orient_Ext::p_normalize(ExtValue *args,ExtValue *ret) { o.normalize(); ret->setEmpty(); } void Orient_Ext::p_between2(ExtValue *args,ExtValue *ret) { Orient_Ext *o1=Orient_Ext::fromObject(args[2]); Orient_Ext *o2=Orient_Ext::fromObject(args[1]); if (o1&&o2) { double q1=args[0].getDouble(),q2=1.0-q1; o.x.x=q1*o1->o.x.x+q2*o2->o.x.x; o.x.y=q1*o1->o.x.y+q2*o2->o.x.y; o.x.z=q1*o1->o.x.z+q2*o2->o.x.z; o.y.x=q1*o1->o.y.x+q2*o2->o.y.x; o.y.y=q1*o1->o.y.y+q2*o2->o.y.y; o.y.z=q1*o1->o.y.z+q2*o2->o.y.z; o.z.x=q1*o1->o.z.x+q2*o2->o.z.x; o.z.y=q1*o1->o.z.y+q2*o2->o.z.y; o.z.z=q1*o1->o.z.z+q2*o2->o.z.z; o.normalize(); } ret->setEmpty(); } void Orient_Ext::p_betweenOV(ExtValue *args,ExtValue *ret) { Orient_Ext *o1=Orient_Ext::fromObject(args[2]); Pt3D_Ext *p2=Pt3D_Ext::fromObject(args[1]); if (o1&&p2) { double q1=args[0].getDouble(),q2=1.0-q1; o.x.x=q1*o1->o.x.x+q2*p2->p.x; o.x.y=q1*o1->o.x.y+q2*p2->p.y; o.x.z=q1*o1->o.x.z+q2*p2->p.z; o.normalize(); } ret->setEmpty(); } void Orient_Ext::p_localToWorld(ExtValue *args,ExtValue *ret) { Pt3D_Ext *center,*point; point=Pt3D_Ext::fromObject(args[1]); center=Pt3D_Ext::fromObject(args[0]); if (center && point) { Pt3D d; Pt3D src=point->p; o.transform(d,src); d+=center->p; *ret=Pt3D_Ext::makeDynamicObject(new Pt3D_Ext(d)); } else ret->setEmpty(); } void Orient_Ext::p_worldToLocal(ExtValue *args,ExtValue *ret) { Pt3D_Ext *center,*point; point=Pt3D_Ext::fromObject(args[1]); center=Pt3D_Ext::fromObject(args[0]); if (center && point) { Pt3D d; Pt3D src=point->p; d-=center->p; o.revTransform(d,src); *ret=Pt3D_Ext::makeDynamicObject(new Pt3D_Ext(d)); } else ret->setEmpty(); } Param& Orient_Ext::getStaticParam() { #ifdef __CODEGUARD__ static Orient_Ext static_orientobj; static Param static_orientparam(getStaticParamtab(),&static_orientobj); #else static Param static_orientparam(getStaticParamtab()); #endif return static_orientparam; } Orient_Ext* Orient_Ext::fromObject(const ExtValue& v) { return (Orient_Ext*)v.getObjectTarget(getStaticParam().getName()); } ParamInterface* Orient_Ext::getInterface() {return &getStaticParam();} ExtObject Orient_Ext::makeStaticObject(Orient* o) {return ExtObject(&getStaticParam(),((char*)o)+(((char*)&o->x)-((char*)&((Orient_Ext*)o)->o.x)));} ExtObject Orient_Ext::makeDynamicObject(Orient_Ext* p) {return ExtObject(&getStaticParam(),p);} ParamEntry* ReferenceObj::getStaticParamtab() { #define FIELDSTRUCT ReferenceObj static ParamEntry paramtab[]= { {"Ref",1,5,"Ref","Reference objects. Useful for returning things from functions.\n\nExample:\nvar x=111;\nsquare(&x);// '&' creates the Reference object\nSimulator.print(x);//x is now 12321\n\nfunction square(r)\n{r.value=r.value*r.value;}\n//square receives the Reference objects and changes its 'value' field"}, {"value",0,PARAM_NOSTATIC,"value","x",GETSET(value),}, {"newS",0,0,"create new reference","p",PROCEDURE(p_newS),"(for internal use only) use &variablename to create Ref objects.",}, {"newO",0,0,"create new reference","p",PROCEDURE(p_newO),"(for internal use only) use &variablename to create Ref objects.",}, {"copyFrom",0,0,"copy the reference","p(oRef)",PROCEDURE(p_copyFrom),"make the reference point to the same target,"}, {"toString",0,PARAM_READONLY+PARAM_NOSTATIC,"textual form","s",GETONLY(toString),}, {0,0,0,}, }; #undef FIELDSTRUCT return paramtab; } Param& ReferenceObj::getStaticParam() { #ifdef __CODEGUARD__ static ReferenceObj static_referenceobj; static Param static_refobjectparam(getStaticParamtab(),&static_referenceobj); #else static Param static_refobjectparam(getStaticParamtab()); #endif return static_refobjectparam; } void ReferenceObj::p_newS(ExtValue *args,ExtValue *ret) { *ret=makeDynamicObject(new ReferenceObj((ExtValue*)args->getInt())); } void ReferenceObj::p_newO(ExtValue *args,ExtValue *ret) { if (args[0].type==TInt) *ret=makeDynamicObject(new ReferenceObj(args[1].getObject(),args[0].getInt())); else *ret=makeDynamicObject(new ReferenceObj(args[1].getObject(),args[0].getString())); } void ReferenceObj::p_copyFrom(ExtValue *args,ExtValue *ret) { ReferenceObj* other=fromObject(args[0]); if (other) { value=other->value; obj=other->obj; prop=other->prop; } } void ReferenceObj::get_toString(ExtValue *ret) { SString s="("; static SListTempl trace; if (trace.find(this)>=0) s+="..."; else { trace+=this; if (value) s+=value->getString(); else { ExtValue v; Param tmp_param; ParamInterface *pi=obj.getParamInterface(tmp_param); pi->get(prop,v); s+=v.getString(); } trace-=this; } s+=")"; ret->setString(s); } void ReferenceObj::get_value(ExtValue *ret) { if (value) *ret=*value; else { Param tmp_param; ParamInterface *pi=obj.getParamInterface(tmp_param); pi->get(prop,*ret); } } int ReferenceObj::set_value(const ExtValue *val) { if (value) *value=*val; else { Param tmp_param; ParamInterface *pi=obj.getParamInterface(tmp_param); pi->set(prop,*val); } return PSET_CHANGED; } ReferenceObj::ReferenceObj(const ExtObject &o,const SString &p) :value(0),obj(o) { Param tmp_param; ParamInterface *pi=obj.getParamInterface(tmp_param); prop=pi->findId(p); } ExtObject ReferenceObj::makeDynamicObject(ReferenceObj* r) {return ExtObject(&getStaticParam(),r);} ReferenceObj* ReferenceObj::fromObject(const ExtValue& v) { return (ReferenceObj*)v.getObjectTarget(getStaticParam().getName()); }