// This file is a part of the Framsticks GDK. // Copyright (C) 1999-2014 Maciej Komosinski and Szymon Ulatowski. See LICENSE.txt for details. // Refer to http://www.framsticks.com/ for further information. #include #include #include #include #include #include #include /////////////////////////////// MODELPARTS.CPP /////////////// #include "modelparts.h" #include "model.h" #include #include #include #include #include #include #include F0_DEFASSIGN_FILE #ifndef GDK_WITHOUT_FRAMS #include #endif template<> char ModelUserTags::reg[5]={0}; ///////////////////////// PartBase::~PartBase() {if (mapped) delete mapped;} void PartBase::notifyMappingChange() { if (owner) owner->partmappingchanged=1; } void PartBase::setMapping(const IRange &r) { if (mapped) (*mapped)=r; else mapped=new MultiRange(r); notifyMappingChange(); } void PartBase::clearMapping() { if (mapped) {delete mapped; mapped=0;} } void PartBase::addMapping(const IRange &r) { if (mapped) mapped->add(r); else mapped=new MultiRange(r); notifyMappingChange(); } void PartBase::setMapping(const MultiRange &mr) { if (mapped) (*mapped)=mr; else mapped=new MultiRange(mr); notifyMappingChange(); } void PartBase::addMapping(const MultiRange &mr) { if (mapped) mapped->add(mr); else mapped=new MultiRange(mr); notifyMappingChange(); } void PartBase::setInfo(const SString& name,const SString& value) { strSetField(info,name,value); } void PartBase::setInfo(const SString& name,int value) { setInfo(name,SString::valueOf(value)); } void PartBase::setInfo(const SString& name,double value) { setInfo(name,SString::valueOf(value)); } SString PartBase::getInfo(const SString& name) { return strGetField(info,name); } ///////////////////////// NeuroClass::NeuroClass(ParamEntry *_props,SString _description, int _prefinputs,int _prefoutput,int _preflocation, int *_vectordata,bool own_vd,int vhints) :ownedvectordata(own_vd), name(_props->name),longname(_props->id),description(_description), props(_props),ownedprops(false), prefinputs(_prefinputs), prefoutput(_prefoutput), preflocation(_preflocation), vectordata(_vectordata), visualhints(vhints),impl_count(0),/*impl(0),*/active(1),genactive(0) {} NeuroClass::~NeuroClass() { setSymbolGlyph(0,0); if (props && ownedprops) ParamObject::freeParamTab(props); } NeuroClass::NeuroClass() :ownedvectordata(0), name("Invalid"), props(empty_paramtab),ownedprops(false), prefinputs(0), prefoutput(0), preflocation(0), vectordata(0), visualhints(0),impl_count(0), /*impl(0),*/ active(1), genactive(0) {} SString NeuroClass::getSummary() { SString t; t=getDescription(); if (t.len()) t+="\n\n"; t+="Characteristics:\n"; if(getPreferredInputs()) { if (getPreferredInputs()<0) t+=" supports any number of inputs\n"; else if (getPreferredInputs()==1) t+=" uses single input\n"; else t+=SString::sprintf(" uses %d inputs\n",getPreferredInputs()); } else t+=" does not use inputs\n"; if(getPreferredOutput()) t+=" provides output value\n"; else t+=" does not provide output value\n"; switch(getPreferredLocation()) { case 0: t+=" does not require location in body\n"; break; case 1: t+=" should be located on a Part\n"; break; case 2: t+=" should be located on a Joint\n"; break; } Param p=getProperties(); if (p.getPropCount()) { if (t.len()) t+="\n\n"; t+="Properties:\n"; const char *h; int i; for(i=0;i=2) t+=SString::sprintf(" %d..%d",a,b);} break; case 'f': t+=" float"; {double a,b,c; if (p.getMinMax(i,a,b,c)>=2) t+=SString::sprintf(" %g..%g",a,b);} break; case 's': t+=" string"; break; case 'x': t+=" anything"; break; } if (h=p.help(i)) if (*h) {t+=" - "; t+=h;} } } return t; } ///////////////////////// ///////////////////////////////////// Neuro::Neuro(double _state,double _inertia,double _force,double _sigmo) :PartBase(getDefaultStyle()),state(_state) #ifdef MODEL_V1_COMPATIBLE ,inertia(_inertia),force(_force),sigmo(_sigmo) #endif { #ifdef MODEL_V1_COMPATIBLE olditems=0; #endif flags=0; myclass=0; knownclass=1; part_refno=-1; joint_refno=-1; } Neuro::Neuro(void):PartBase(getDefaultStyle()) { defassign(); state=0.0; myclass=NULL; myclassname="N";//default d="N" but f0.def is unable to set this (d is GETSET, not a regular FIELD) knownclass=0; refno=0; pos=Pt3D_0; rot=Pt3D_0; parent=0; part=0; joint=0; parentcount=0; #ifdef MODEL_V1_COMPATIBLE olditems=0; #endif flags=0; part_refno=-1; joint_refno=-1; } Neuro::~Neuro() { #ifdef MODEL_V1_COMPATIBLE if (olditems) delete olditems; #endif int i; for(i=0;i=getInputCount()) return 0; return &inputs(i).info; } void Neuro::setInputInfo(int i,const SString& name,const SString &value) { SString **s=inputInfo(i); if (!s) return; if (!*s) *s=new SString(); strSetField(**s,name,value); } void Neuro::setInputInfo(int i,const SString& name,int value) { setInputInfo(i,name,SString::valueOf(value)); } void Neuro::setInputInfo(int i,const SString& name,double value) { setInputInfo(i,name,SString::valueOf(value)); } SString Neuro::getInputInfo(int i) { SString **s=inputInfo(i); if (!s) return SString(); if (!*s) return SString(); return **s; } SString Neuro::getInputInfo(int i,const SString& name) { SString **s=inputInfo(i); if (!s) return SString(); if (!*s) return SString(); return strGetField(**s,name); } void Neuro::operator=(const Neuro& src) { refno=src.refno; #ifdef MODEL_V1_COMPATIBLE neuro_refno=-1; conn_refno=-1; force=src.force; sigmo=src.sigmo; inertia=src.inertia; weight=src.weight; olditems=0; #endif state=src.state; part_refno=-1; joint_refno=-1; pos=src.pos; rot=src.rot; parent=0; part=0; joint=0; parentcount=0; flags=0; myclass=src.myclass; knownclass=src.knownclass; myclassname=src.myclassname; myclassparams=src.myclassparams; } void Neuro::attachToPart(int i) {attachToPart((i>=0)?owner->getPart(i):0);} void Neuro::attachToJoint(int i) {attachToJoint((i>=0)?owner->getJoint(i):0);} int Neuro::getClassCount() {return NeuroLibrary::staticlibrary.getClassCount();} NeuroClass* Neuro::getClass(int classindex) {return NeuroLibrary::staticlibrary.getClass(classindex);} NeuroClass* Neuro::getClass(const SString& classname) {return NeuroLibrary::staticlibrary.findClass(classname);} int Neuro::getClassIndex(const NeuroClass*nc) {return NeuroLibrary::staticlibrary.classes.find((void*)nc);} NeuroClass* Neuro::getClass() { checkClass(); return myclass; } void Neuro::setClass(NeuroClass* cl) { myclass=cl; myclassname=cl->getName(); knownclass=1; } SString Neuro::getClassName(int classindex) { NeuroClass *cl=NeuroLibrary::staticlibrary.getClass(classindex); return cl? cl->getName() : SString(); } void Neuro::setDetails(const SString& details) { int colon=details.indexOf(':'); if (colon>=0) {myclassname=details.substr(0,colon); myclassparams=details.substr(colon+1);} else {myclassname=details; myclassparams=0;} knownclass=0; } SString Neuro::getDetails() { SString ret=getClassName(); if (myclassparams.len()) {if (!ret.len()) ret="N"; ret+=":"; ret+=myclassparams;} return ret; } void Neuro::checkClass() { if (knownclass) return; myclass=getClass(myclassname); knownclass=1; } SyntParam Neuro::classProperties(bool handle_defaults_when_saving) { NeuroClass *cl=getClass(); ParamEntry *pe = cl ? cl->getParamTab() : emptyParamTab; return SyntParam(pe,&myclassparams,handle_defaults_when_saving); } SString Neuro::getClassName() { return myclassname; } void Neuro::setClassName(const SString& clazz) { myclassname=clazz; knownclass=0; } int Neuro::addInput(Neuro* child,double weight,const SString *info) { inputs+=NInput(child,weight,(info&&(info->len()))?new SString(*info):0); child->parentcount++; if (child->parentcount==1) {child->parent=this;} return inputs.size()-1; } int Neuro::findInput(Neuro* child) const { for(int i=0;i=getInputCount()) return 0; NInput &inp=inputs(i); weight=inp.weight; return inp.n; } double Neuro::getInputWeight(int i) const { return inputs(i).weight; } void Neuro::setInputWeight(int i,double w) { inputs(i).weight=w; } void Neuro::setInput(int i,Neuro* n) { NInput &inp=inputs(i); inp.n=n; } void Neuro::setInput(int i,Neuro* n,double w) { NInput &inp=inputs(i); inp.n=n; inp.weight=w; } void Neuro::removeInput(int refno) { Neuro *child=getInput(refno); child->parentcount--; if (child->parent==this) child->parent=0; SString *s=inputs(refno).info; if (s) delete s; inputs.remove(refno); } int Neuro::removeInput(Neuro* child) { int i=findInput(child); if (i>=0) removeInput(i); return i; } int Neuro::getOutputsCount() const { int c=0; for(int i=0;igetNeuroCount();i++) for(int j=0;jgetNeuro(i)->getInputCount();j++) c+=owner->getNeuro(i)->getInput(j)==this; return c; } int Neuro::isOldEffector() { static SString bend("|"),rot("@"); return ((getClassName()==bend)||(getClassName()==rot)); } int Neuro::isOldReceptor() { static SString g("G"),t("T"),s("S"); return ((getClassName()==g)||(getClassName()==t)||(getClassName()==s)); } int Neuro::isOldNeuron() { static SString n("N"); return (getClassName()==n); } int Neuro::isNNConnection() { static SString conn("-"); return (getClassName()==conn); } int Neuro::findInputs(SList& result,const char* classname,const Part* part,const Joint* joint) const { Neuro *nu; SString cn(classname); int n0=result.size(); for(int i=0;nu=getInput(i);i++) { if (part) if (nu->part != part) continue; if (joint) if (nu->joint != joint) continue; if (classname) if (nu->getClassName() != cn) continue; result+=(void*)nu; } return result.size()-n0; } int Neuro::findOutputs(SList& result,const char* classname,const Part* part,const Joint* joint) const { // not very efficient... Neuro *nu,*inp; SString cn(classname); SList found; int n0=result.size(); for(int i=0;nu=getModel().getNeuro(i);i++) { if (part) if (nu->part != part) continue; if (joint) if (nu->joint != joint) continue; if (classname) if (inp->getClassName() != cn) continue; for (int j=0;inp=nu->getInput(j);j++) if (inp==this) { result+=(void*)nu; break; } } return result.size()-n0; } void Neuro::get_inputCount(PARAMGETARGS) {ret->setInt(inputs.size());} void Neuro::p_getInputNeuroDef(ExtValue *args,ExtValue *ret) { int i=args->getInt(); if ((i<0)||(i>=inputs.size())) ret->setEmpty(); else ret->setObject(ExtObject(&Neuro::getStaticParam(),inputs(i).n)); } void Neuro::p_getInputWeight(ExtValue *args,ExtValue *ret) { int i=args->getInt(); if ((i<0)||(i>=inputs.size())) ret->setEmpty(); else ret->setDouble(inputs(i).weight); } void Neuro::p_getInputNeuroIndex(ExtValue *args,ExtValue *ret) { int i=args->getInt(); if ((i<0)||(i>=inputs.size())) ret->setInt(-1); else ret->setInt(inputs(i).n->refno); } void Neuro::get_classObject(PARAMGETARGS) { #ifndef GDK_WITHOUT_FRAMS NeuroClassExt::makeStaticObject(ret,getClass()); #endif } /////// old items #ifdef MODEL_V1_COMPATIBLE void OldItems::buildlist() { // guaranteed to work only for old NN layouts // (neurons,neuro connections, old receptors and effectors) if (listok) return; // inputs can contain both neuroitem connections (details="") and direct neuron references (details="N") // in OldItems we create neuroitems freom direct references for(int i=0;iisOldNeuron()) { Neuro *ni=new Neuro(); ni->setClassName("-"); ni->weight=w; ni->neuro_refno=neuro.refno; ni->conn_refno=n->refno; items+=ni; syntitems+=ni; } else { items+=n; n->weight=w; } } SList outputs; neuro.findOutputs(outputs); FOREACH(Neuro*,n,outputs) { if (n->isNNConnection() || n->isOldNeuron()) outputs-=n; } items+=outputs; listok=1; } void OldItems::freelist() { FOREACH(Neuro*,n,syntitems) delete n; syntitems.clear(); items.clear(); listok=0; } int OldItems::getItemCount() { buildlist(); return items.size(); } NeuroItem *OldItems::getNeuroItem(int i) { buildlist(); return (NeuroItem*)items(i); } NeuroItem *OldItems::addNewNeuroItem() { Neuro *nu=neuro.getModel().addNewNeuro(); nu->setClassName("-"); if (listok) items+=nu; neuro.addInput(nu); return (NeuroItem*)nu; } int OldItems::findNeuroItem(NeuroItem *ni) { buildlist(); return items.find((void*)ni); } #endif /////////////////////////////////////// SString Part::getDefaultStyle() {return SString("part");} SString Joint::getDefaultStyle() {return SString("joint");} /* const SString& Neuro::getDefaultStyle() {static SString s("neuro"); return s;} const SString& NeuroItem::getDefaultStyle() {static SString s("neuroitem"); return s;} */ SString Neuro::getDefaultStyle() {return SString("neuro");} Part::Part(enum Shape s):PartBase(getDefaultStyle()) { o=Orient_1; p=Pt3D_0; rot=Pt3D_0; flags=0; defassign(); shape=s; } void Part::operator=(const Part& src) { p=src.p; o=src.o; flags=src.flags; mass=src.mass; density=src.density; friction=src.friction; ingest=src.ingest; assim=src.assim; size=src.size; rot=src.rot; refno=src.refno; vcolor=src.vcolor; vsize=src.vsize; shape=src.shape; } void Part::setOrient(const Orient &_o) { o=_o; rot.getAngles(o.x,o.z); } void Part::setRot(const Pt3D &r) { rot=r; o=Orient_1; o.rotate(rot); } void Part::setPositionAndRotationFromAxis(const Pt3D &p1,const Pt3D &p2) { Pt3D x=p2-p1; Pt3D dir(x.y,x.z,x.x); p=p1+x*0.5; rot.getAngles(x,dir); } Param& Part::getStaticParam() { static Param p(f0_part_paramtab,0,"Part"); return p; } /////////////////////////// Joint::Joint():PartBase(getDefaultStyle()) { rot=Pt3D_0; defassign(); d.x=JOINT_DELTA_MARKER; d.y=JOINT_DELTA_MARKER; d.z=JOINT_DELTA_MARKER; part1=0; part2=0; flags=0; usedelta=0; } void Joint::operator=(const Joint& src) { rot=src.rot; d=src.d; stamina=src.stamina; stif=src.stif; rotstif=src.rotstif; part1=0; part2=0; flags=src.flags; usedelta=src.usedelta; refno=src.refno; } void Joint::attachToParts(Part* p1,Part* p2) { part1=p1; part2=p2; if (p1 && p2) { o=rot; if (usedelta) { p1->o.transform(p2->o,o); // p2->o.x=p1->o/o.x; p2->o.y=p1->o/o.y; p2->o.z=p1->o/o.z; p2->p=p2->o.transform(d)+p1->p; } } } void Joint::attachToParts(int p1,int p2) { attachToParts((p1>=0)?owner->getPart(p1):0,(p2>=0)?owner->getPart(p2):0); } void Joint::resetDelta() { d=Pt3D(JOINT_DELTA_MARKER,JOINT_DELTA_MARKER,JOINT_DELTA_MARKER); } void Joint::resetDeltaMarkers() { if (d.x==JOINT_DELTA_MARKER) d.x=0; if (d.y==JOINT_DELTA_MARKER) d.y=0; if (d.z==JOINT_DELTA_MARKER) d.z=0; } void Joint::useDelta(bool use) { usedelta=use; } bool Joint::isDelta() { return usedelta; } Param& Joint::getStaticParam() { static Param p(f0_joint_paramtab,0,"Joint"); return p; } ///////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// #include F0_CLASSES_FILE #ifdef MODEL_V1_COMPATIBLE #define FIELDSTRUCT Neuro ParamEntry f0_old_neuro_tab[]= { {"Connections",2,6,"n",}, {"Other properties",}, {"p",0,0,"part ref#","d",FIELD(part_refno),}, {"j",0,0,"joint ref#","d",FIELD(joint_refno),}, {"s",1,0,"state","f",FIELD(state),}, {"in",1,0,"Inertia","f",FIELD(inertia),}, {"fo",1,0,"Force","f",FIELD(force),}, {"si",1,0,"Sigmoid","f",FIELD(sigmo),}, {0,0,0,}, }; #undef FIELDSTRUCT #define FIELDSTRUCT NeuroItem ParamEntry f0_neuroitem_paramtab[]= { {"Connections",3,12,"ni",}, {"Geometry",}, {"Other",}, {"n",0,0,"neuron ref#","d",FIELD(neuro_refno),}, {"c",2,0,"connection ref#","d",FIELD(conn_refno),}, {"w",2,0,"connection weight","f",FIELD(weight),}, {"p",0,0,"part ref#","d",FIELD(part_refno),}, {"j",0,0,"joint ref#","d",FIELD(joint_refno),}, {"px",1,0,"position.x","f",FIELD(pos.x),}, {"py",1,0,"position.y","f",FIELD(pos.y),}, {"pz",1,0,"position.z","f",FIELD(pos.z),}, {"rx",1,0,"rotation.x","f",FIELD(rot.x),}, {"ry",1,0,"rotation.y","f",FIELD(rot.y),}, {"rz",1,0,"rotation.z","f",FIELD(rot.z),}, {"d",2,0,"item details","s",GETSET(details),}, {0,0,0,}, }; #undef FIELDSTRUCT #endif //////////////////////////////////////// ParamEntry Neuro::emptyParamTab[]= { {"Undefined Neuro",1,0,"?",}, {0,0,0,}, }; Param Part::extraProperties() { return Param(f0_part_xtra_paramtab,this); } Param Joint::extraProperties() { return Param(f0_joint_xtra_paramtab,this); } Param Neuro::extraProperties() { return Param(f0_neuro_xtra_paramtab,this); } Param Part::properties() { return Param(f0_part_paramtab,this); } Param Joint::properties() { return Param(usedelta?f0_joint_paramtab:f0_nodeltajoint_paramtab,this); } Param Neuro::properties() { return Param(f0_neuro_paramtab,this); } class NeuroExtParamTab: public ParamTab { public: NeuroExtParamTab():ParamTab(f0_neuro_paramtab) { #define FIELDSTRUCT NeuroExt ParamEntry entry={"class",2,0,"neuro class","s",GETSET(neuroclass)}; #undef FIELDSTRUCT add(&entry); #define FIELDSTRUCT Neuro ParamEntry entry2={"state",2,0,"state","f",FIELD(state)}; #undef FIELDSTRUCT add(&entry2); } }; Param& Neuro::getStaticParam() { static Param p(f0_neuro_paramtab,0,"NeuroDef"); return p; } //////////////////////// NeuroConn::NeuroConn() { defassign(); } ////////////////////////////////////// ParamEntry *NeuroExt::getParamTab() { static NeuroExtParamTab tab; return tab.getParamTab(); } void NeuroExt::get_neuroclass(PARAMGETARGS) {ret->setString(getClassName());} int NeuroExt::set_neuroclass(PARAMSETARGS) {setClassName(arg->getString());return PSET_CHANGED;}