Index: /cpp/gdk/3d.cpp
===================================================================
--- /cpp/gdk/3d.cpp	(revision 5)
+++ /cpp/gdk/3d.cpp	(revision 5)
@@ -0,0 +1,225 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include <math.h>
+#include <string.h>
+#include "nonstd.h"
+#include "3d.h"
+#include "framsg.h"
+
+Pt3D operator+(const Pt3D &p1,const Pt3D &p2) {return Pt3D(p1.x+p2.x,p1.y+p2.y,p1.z+p2.z);}
+Pt3D operator-(const Pt3D &p1,const Pt3D &p2) {return Pt3D(p1.x-p2.x,p1.y-p2.y,p1.z-p2.z);}
+
+Pt3D Pt3D_0(0,0,0);
+
+bool Pt3D::report_errors=true;
+
+double Pt3D::operator()() const
+{
+double q=x*x+y*y+z*z;
+if (q<0) {if (report_errors) FramMessage("Pt3D","operator()","sqrt domain error",3); return 0;}
+return sqrt(q);
+}
+
+bool Pt3D::normalize()
+{
+double len=length();
+if (fabs(len)<1e-50) {if (report_errors) FramMessage("Pt3D","normalize()","vector too small",1); x=1;y=0;z=0; return false;}
+operator/=(len);
+return true;
+}
+
+double Pt3D::distanceTo(const Pt3D& p) const
+{
+return sqrt((x-p.x)*(x-p.x)+(y-p.y)*(y-p.y)+(z-p.z)*(z-p.z));
+}
+
+double Pt3D::manhattanDistanceTo(const Pt3D& p) const
+{
+return fabs(x-p.x)+fabs(y-p.y)+fabs(z-p.z);
+}
+
+Orient Orient_1(Pt3D(1,0,0),Pt3D(0,1,0),Pt3D(0,0,1));
+
+// prosty obrot
+void rotate2D(double k,double &x,double &y)
+{double s=sin(k),c=cos(k);
+double t=c*x-s*y; y=s*x+c*y; x=t;}
+
+void rotate2D(double s,double c,double &x,double &y)
+{double t=c*x-s*y; y=s*x+c*y; x=t;}
+
+int Pt3D::getAngle(double dx,double dy,double &wyn)
+{
+if ((fabs(dx)+fabs(dy))<0.0001) return 0;
+wyn=atan2(dy,dx);
+return 1;
+}
+
+void Pt3D::getAngles(const Pt3D& X,const Pt3D& dir)
+{
+Pt3D	t1(X), t2(dir);
+if (getAngle(t1.x,t1.y,z))
+	{	// nie pionowo
+	rotate2D(-z,t1.x,t1.y);
+	rotate2D(-z,t2.x,t2.y);
+	getAngle(t1.x, t1.z, y);
+	}
+else
+	{	// pionowo
+	z=0;
+	if (t1.z<0)
+		y=-M_PI_2; // w dol
+	else
+		y=M_PI_2; // w gore
+	}
+rotate2D(-y,t2.x,t2.z);
+if (!getAngle(t2.z,-t2.y,x))
+	x=0;// to zly wynik ale dobrego nie ma :P
+}
+
+void Pt3D::getMin(const Pt3D& p)
+{
+if (p.x<x) x=p.x;
+if (p.y<y) y=p.y;
+if (p.z<z) z=p.z;
+}
+void Pt3D::getMax(const Pt3D& p)
+{
+if (p.x>x) x=p.x;
+if (p.y>y) y=p.y;
+if (p.z>z) z=p.z;
+}
+
+void Pt3D::vectorProduct(const Pt3D& a,const Pt3D& b)
+{
+x=a.y*b.z-a.z*b.y;
+y=a.z*b.x-a.x*b.z;
+z=a.x*b.y-a.y*b.x;
+}
+
+void Orient::lookAt(const Pt3D& X,const Pt3D& dir)
+{
+x=X; x.normalize();
+y.vectorProduct(dir,x);
+z.vectorProduct(x,y);
+if ((!y.normalize()) || (!z.normalize()))
+	{
+	y.x=dir.y; y.y=dir.z; y.z=dir.x;
+	z.vectorProduct(x,y);
+	z.normalize();
+	}
+}
+
+// odleglosc 2d
+double d2(double x,double y)
+{
+double q=x*x+y*y;
+if (q<0) {if (Pt3D::report_errors) FramMessage("","d2()","sqrt domain error",3); return 0;}
+return sqrt(q);
+}
+
+Orient::Orient(const Matrix44& m)
+{
+x.x=m[0];  x.y=m[1];  x.z=m[2];
+y.x=m[4];  y.y=m[5];  y.z=m[6];
+z.x=m[8];  z.y=m[9];  z.z=m[10];
+}
+
+void Orient::operator=(const Pt3D &rot)
+{
+*this=Orient_1;
+rotate(rot);
+}
+
+void Orient::rotate(const Pt3D &v)
+{
+double s,c;
+if (fabs(v.x)>0.0001)
+	{
+	s=sin(v.x); c=cos(v.x);
+	rotate2D(s,c,x.y,x.z);
+	rotate2D(s,c,y.y,y.z);
+	rotate2D(s,c,z.y,z.z);
+	}
+if (fabs(v.y)>0.0001)
+	{
+	s=sin(v.y); c=cos(v.y);
+	rotate2D(s,c,x.x,x.z);
+	rotate2D(s,c,y.x,y.z);
+	rotate2D(s,c,z.x,z.z);
+	}
+if (fabs(v.z)>0.0001)
+	{
+	s=sin(v.z); c=cos(v.z);
+	rotate2D(s,c,x.x,x.y);
+	rotate2D(s,c,y.x,y.y);
+	rotate2D(s,c,z.x,z.y);
+	}
+}
+
+void Orient::transform(Pt3D& target,const Pt3D &s) const
+{
+target.x=s.x*x.x+s.y*y.x+s.z*z.x;
+target.y=s.x*x.y+s.y*y.y+s.z*z.y;
+target.z=s.x*x.z+s.y*y.z+s.z*z.z;
+}
+
+void Orient::revTransform(Pt3D& target,const Pt3D &s) const
+{
+target.x=s.x*x.x+s.y*x.y+s.z*x.z;
+target.y=s.x*y.x+s.y*y.y+s.z*y.z;
+target.z=s.x*z.x+s.y*z.y+s.z*z.z;
+}
+
+void Orient::transform(Orient& target,const Orient& src) const
+{
+transform(target.x,src.x);
+transform(target.y,src.y);
+transform(target.z,src.z);
+}
+
+void Orient::revTransform(Orient& target,const Orient& src) const
+{
+revTransform(target.x,src.x);
+revTransform(target.y,src.y);
+revTransform(target.z,src.z);
+}
+
+void Orient::getAngles(Pt3D &angles) const
+{
+angles.getAngles(x,z);
+}
+
+bool Orient::normalize()
+{
+bool ret=1;
+y.vectorProduct(z,x);
+z.vectorProduct(x,y);
+if (!x.normalize()) ret=0;
+if (!z.normalize()) ret=0;
+if (!y.normalize()) ret=0;
+return ret;
+}
+
+Matrix44::Matrix44(const Orient &rot)
+{
+m[0]=rot.x.x;  m[1]=rot.x.y;  m[2]=rot.x.z;  m[3]=0;
+m[4]=rot.y.x;  m[5]=rot.y.y;  m[6]=rot.y.z;  m[7]=0;
+m[8]=rot.z.x;  m[9]=rot.z.y;  m[10]=rot.z.z; m[11]=0;
+m[12]=0;       m[13]=0;       m[14]=0;       m[15]=1;
+}
+
+void Matrix44::operator+=(const Pt3D &)
+{
+
+}
+
+void Matrix44::operator*=(const Pt3D &)
+{
+}
+
+void Matrix44::operator*=(double sc)
+{
+}
Index: /cpp/gdk/3d.h
===================================================================
--- /cpp/gdk/3d.h	(revision 5)
+++ /cpp/gdk/3d.h	(revision 5)
@@ -0,0 +1,133 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _3D_H_
+#define _3D_H_
+
+#include <memory.h>
+
+/**********************************
+\file 3d.h 3d.cpp
+
+   basic 3d classes and operators     
+*********************************/
+
+/// point in 3d space
+
+class Pt3D
+{
+public:	double x,y,z;
+static bool report_errors;
+
+Pt3D(double _x,double _y,double _z):x(_x),y(_y),z(_z) {} ///< constructor initializing all coords
+Pt3D(double xyz):x(xyz),y(xyz),z(xyz) {} ///< all coords equal 
+Pt3D() {} ///< coords will be not initialized!
+Pt3D(const Pt3D &p):x(p.x),y(p.y),z(p.z) {} ///< copy from another point
+bool 	operator==(const Pt3D& p)	{return (x==p.x)&&(y==p.y)&&(z==p.z);}
+void 	operator+=(const Pt3D& p)	{x+=p.x;y+=p.y;z+=p.z;}
+void 	operator-=(const Pt3D& p)	{x-=p.x;y-=p.y;z-=p.z;}
+void  	operator*=(double d)	{x*=d;y*=d;z*=d;}
+Pt3D  	operator*(const Pt3D &p) const {return Pt3D(y*p.z-z*p.y, z*p.x-x*p.z, x*p.y-y*p.x);}
+void 	operator/=(double d)	{x/=d; y/=d; z/=d;}
+//Pt3D 	operator+(const Pt3D& p) const {return Pt3D(x+p.x,y+p.y,z+p.z);}
+//Pt3D 	operator-(const Pt3D& p) const {return Pt3D(x-p.x,y-p.y,z-p.z);}
+Pt3D 	operator-() const {return Pt3D(-x,-y,-z);}
+Pt3D 	operator*(double d) const {return Pt3D(x*d,y*d,z*d);}
+Pt3D 	operator/(double d) const {return Pt3D(x/d,y/d,z/d);}
+int	operator<(const Pt3D& p) const {return (x<p.x)&&(y<p.y)&&(z<p.z);}
+	///< check if all coords are below the second point
+int	operator>(const Pt3D& p) const {return (x>p.x)&&(y>p.y)&&(z>p.z);}
+	///< check if all coords are above the second point
+int	operator<=(const Pt3D& p) const {return (x<p.x)||(y<p.y)||(z<p.z);}
+	///< check if some coords are below the second point
+int	operator>=(const Pt3D& p) const {return (x>p.x)||(y>p.y)||(z>p.z);}
+	///< check if some coords are above the second point
+void getMin(const Pt3D& p);
+void getMax(const Pt3D& p);
+/** vector length = \f$\sqrt{x^2+y^2+z^2}\f$  */
+double operator()() const;
+/** vector length = \f$\sqrt{x^2+y^2+z^2}\f$  */
+double length() const {return operator()();} 
+double distanceTo(const Pt3D& p) const;
+double manhattanDistanceTo(const Pt3D& p) const;
+/** calculate angle between (0,0)-(dx,dy), @return 1=ok, 0=can't calculate */
+static int getAngle(double dx,double dy,double &angle);
+/** calculate 3 rotation angles translating (1,0,0) into 'X' and (0,0,1) into 'dir' */
+void getAngles(const Pt3D& X,const Pt3D& dir);
+void vectorProduct(const Pt3D& a,const Pt3D& b);
+bool normalize();
+};
+Pt3D operator+(const Pt3D &p1,const Pt3D &p2);
+Pt3D operator-(const Pt3D &p1,const Pt3D &p2);
+
+class Pt3D_DontReportErrors
+{
+bool state;
+public:
+Pt3D_DontReportErrors() {state=Pt3D::report_errors; Pt3D::report_errors=false;}
+~Pt3D_DontReportErrors() {Pt3D::report_errors=state;}
+};
+
+///  orientation in 3d space = rotation matrix
+
+class Matrix44;
+
+class Orient
+{
+public: Pt3D x,y,z; ///< 3 vectors (= 3x3 matrix)
+
+	Orient() {}
+	Orient(const Orient& src) {x=src.x; y=src.y; z=src.z;}
+	Orient(const Pt3D& a,const Pt3D& b,const Pt3D& c):x(a),y(b),z(c) {}
+//	Orient(const Pt3D& rot) {*this=rot;}
+	Orient(const Matrix44& m);
+	void operator=(const Pt3D &rot);
+	void rotate(const Pt3D &); ///< rotate matrix around 3 axes
+
+	void transform(Pt3D &target,const Pt3D &src) const;	///< transform a vector
+	void revTransform(Pt3D &target,const Pt3D &src) const;	///< reverse transform
+	Pt3D transform(const Pt3D &src) const {Pt3D t; transform(t,src); return t;}
+	Pt3D revTransform(const Pt3D &src) const {Pt3D t; revTransform(t,src); return t;}
+
+	void transform(Orient& target,const Orient& src) const;    ///< transform other orient
+	void revTransform(Orient& target,const Orient& src) const; ///< reverse transform other orient
+
+	void transform(const Orient &rot) {Orient tmp; rot.transform(tmp,*this); *this=tmp;}
+	void revTransform(const Orient &rot) {Orient tmp; rot.revTransform(tmp,*this); *this=tmp;}
+
+	void getAngles(Pt3D &) const; ///< calculate rotation from current matrix
+	void lookAt(const Pt3D &X,const Pt3D &dir); ///< calculate orientation matrix from 2 vectors
+
+	bool normalize();
+};
+
+class Matrix44
+{
+public:
+double m[16];
+Matrix44() {}
+Matrix44(const Matrix44& src) {memcpy(m,src.m,sizeof(m));}
+Matrix44(double *srcm) {memcpy(m,srcm,sizeof(m));}
+Matrix44(const Orient &rot);
+
+const double& operator()(int i,int j) const {return m[i+16*j];}
+const double& operator[](int i) const {return m[i];}
+double& operator()(int i,int j) {return m[i+16*j];}
+double& operator[](int i) {return m[i];}
+
+void operator+=(const Pt3D &); ///< translate matrix
+void operator*=(const Pt3D &); ///< scale matrix
+void operator*=(double sc); ///< scale matrix
+};
+
+extern Pt3D Pt3D_0; ///< zero vector
+extern Orient Orient_1; ///< standard unit matrix: 100 010 001
+extern Matrix44 Matrix44_1; ///< standard unit matrix: 1000 0100 0010 0001
+
+void rotate2D(double,double &,double &); ///< rotate 2d vector, given angle
+void rotate2D(double,double,double &,double &); ///< rotate 2d vector, given sin and cos
+double d2(double,double); ///< distance in 2D
+
+#endif
+
Index: /cpp/gdk/GDK.dsw
===================================================================
--- /cpp/gdk/GDK.dsw	(revision 5)
+++ /cpp/gdk/GDK.dsw	(revision 5)
@@ -0,0 +1,77 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "convtest"=".\convtest.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "gdktest"=".\gdktest.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "genotest"=".\genotest.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "loadertest"=".\loadertest.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "neurotest"=".\neurotest.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
Index: /cpp/gdk/Makefile
===================================================================
--- /cpp/gdk/Makefile	(revision 5)
+++ /cpp/gdk/Makefile	(revision 5)
@@ -0,0 +1,197 @@
+#
+# Framsticks GDK makefile
+#
+
+TARGETS=convtest gdktest genotest neurotest loadertest f0def.xml model.def
+
+all: $(TARGETS)
+
+CXXOPTS= -DNOCREATUREOBJECT -DEASYMAPDEBUG -g -Wno-parentheses -Wno-overloaded-virtual -Wno-format
+# -DEASYMAPDEBUG is required for convtest
+
+AUTOGENERATED=defassign-f0_joint.h defassign-f0_part.h defassign-f0_neuro.h f0classes.h \
+	defassign-f0_neuroconn.h f0def.xml neurocls-library.h neurocls-factory.h model.def
+
+CONVMODULES=conv_f1.o
+
+GDKOBJS=list.o advlist.o param.o sstring.o 3d.o model.o modelparts.o errmanager.o \
+	neurolibrary.o geno.o genoconv.o extvalue.o framsg.o callbacks.o syntparam.o \
+	multirange.o multimap.o paramtabobj.o defgenoconv.o sstringutils.o paramobj.o \
+	$(CONVMODULES)
+
+libgdk.a: $(GDKOBJS)
+
+CONVTESTOBJS= convtest.o printconvmap.o stdouterr.o virtfile.o
+
+convtest: libgdk.a $(CONVTESTOBJS)
+	g++ $(CONVTESTOBJS) -L. -lgdk -o $@
+
+GDKTESTOBJS= gdktest.o stdouterr.o virtfile.o
+
+gdktest: libgdk.a $(GDKTESTOBJS)
+	g++ $(GDKTESTOBJS) -L. -lgdk -o $@
+
+GENOTESTOBJS= genotest.o virtfile.o
+
+genotest: libgdk.a $(GENOTESTOBJS)
+	g++ $(GENOTESTOBJS) -L. -lgdk -o $@
+
+NEUROTESTOBJS= neurotest.o stdouterr.o virtfile.o neuroimpl.o neurofactory.o \
+	neuroimpl-simple.o neuroimpl-channels.o neuroimpl-fuzzy.o neuroimpl-fuzzy-f0.o
+
+neurotest: libgdk.a $(NEUROTESTOBJS)
+	g++ $(NEUROTESTOBJS) -L. -lgdk -o $@
+
+LOADERTESTOBJS=genotypeloader.o loadertest.o virtfile.o multiparamload.o stdiofile-autoinit.o stdiofile.o
+
+loadertest: libgdk.a $(LOADERTESTOBJS)
+	g++ $(LOADERTESTOBJS) -L. -lgdk -o $@
+
+neurocls-library.h: f0.def neurocls-library.m4
+	m4 neurocls-library.m4 f0.def >neurocls-library.h
+
+neurocls-factory.h: f0.def neurocls-factory.m4
+	m4 neurocls-factory.m4 f0.def >neurocls-factory.h
+
+f0classes.h: f0.def f0classes.m4
+	m4 f0classes.m4 f0.def >f0classes.h
+
+f0def.xml: f0.def f0defxml.m4
+	m4 f0defxml.m4 f0.def >f0def.xml
+
+model.def: f0-modeldef.m4 f0.def
+	m4 f0-modeldef.m4 f0.def >model.def
+
+defassign-%.h: defassign.m4 f0.def
+	m4 -DUSECLASS=$* defassign.m4 f0.def >$@
+
+neurolibrary.cpp: neurocls-library.h
+neurofactory.cpp: neurocls-factory.h
+modelparts.cpp: f0classes.h defassign-f0_part.h defassign-f0_joint.h \
+		defassign-f0_neuro.h defassign-f0_neuroconn.h
+
+#############
+
+%.o : %.cpp
+	g++ -c $(CXXOPTS) $<
+
+%.a:
+	rm -f $@
+	ar r $@ $^
+	ranlib $@
+
+clean:
+	rm -f *.o *~ *.bak *.a
+
+fullclean:	clean
+	rm -f $(TARGETS) $(AUTOGENERATED)
+
+prepare: $(AUTOGENERATED) depend
+	rm -f Makefile.bak
+	~/bin/addhead ../gdk-head.txt *.h *.cpp
+
+depend:
+	makedepend -Y *.cpp
+
+# DO NOT DELETE
+
+3d.o: nonstd.h 3d.h framsg.h
+advlist.o: advlist.h list.h nonstd.h callbacks.h statrick.h
+callbacks.o: callbacks.h list.h nonstd.h statrick.h
+conv_f1.o: conv_f1.h genoconv.h geno.h sstring.h extvalue.h param.h list.h
+conv_f1.o: nonstd.h statrick.h virtfile.h model.h modelparts.h 3d.h
+conv_f1.o: sstringutils.h syntparam.h usertags.h paramtabobj.h advlist.h
+conv_f1.o: callbacks.h framsg.h multirange.h multimap.h
+convtest.o: genoconv.h geno.h sstring.h extvalue.h param.h list.h nonstd.h
+convtest.o: statrick.h virtfile.h model.h modelparts.h 3d.h sstringutils.h
+convtest.o: syntparam.h usertags.h paramtabobj.h advlist.h callbacks.h
+convtest.o: multimap.h multirange.h conv_f1.h printconvmap.h stdouterr.h
+convtest.o: errmanager.h framsg.h
+defgenoconv.o: defgenoconv.h genoconv.h geno.h sstring.h extvalue.h param.h
+defgenoconv.o: list.h nonstd.h statrick.h virtfile.h gen-config.h conv_f1.h
+defgenoconv.o: model.h modelparts.h 3d.h sstringutils.h syntparam.h
+defgenoconv.o: usertags.h paramtabobj.h advlist.h callbacks.h
+errmanager.o: errmanager.h list.h nonstd.h sstring.h framsg.h
+extvalue.o: extvalue.h sstring.h param.h list.h nonstd.h statrick.h
+extvalue.o: virtfile.h framsg.h
+framsg.o: nonstd.h framsg.h
+gdktest.o: model.h modelparts.h 3d.h genoconv.h geno.h sstring.h extvalue.h
+gdktest.o: param.h list.h nonstd.h statrick.h virtfile.h sstringutils.h
+gdktest.o: syntparam.h usertags.h paramtabobj.h advlist.h callbacks.h
+gdktest.o: defgenoconv.h stdouterr.h errmanager.h framsg.h
+genoconv.o: nonstd.h genoconv.h geno.h sstring.h extvalue.h param.h list.h
+genoconv.o: statrick.h virtfile.h multimap.h multirange.h
+geno.o: geno.h sstring.h extvalue.h param.h list.h nonstd.h statrick.h
+geno.o: virtfile.h genoconv.h model.h modelparts.h 3d.h sstringutils.h
+geno.o: syntparam.h usertags.h paramtabobj.h advlist.h callbacks.h
+genotest.o: geno.h sstring.h extvalue.h param.h list.h nonstd.h statrick.h
+genotest.o: virtfile.h genoconv.h stdiofile.h sstringutils.h defgenoconv.h
+genotypeloader.o: genotypeloader.h sstring.h multiparamload.h param.h list.h
+genotypeloader.o: nonstd.h statrick.h virtfile.h
+list.o: list.h nonstd.h
+loadertest.o: genotypeloader.h sstring.h multiparamload.h param.h list.h
+loadertest.o: nonstd.h statrick.h virtfile.h
+model.o: nonstd.h model.h modelparts.h 3d.h genoconv.h geno.h sstring.h
+model.o: extvalue.h param.h list.h statrick.h virtfile.h sstringutils.h
+model.o: syntparam.h usertags.h paramtabobj.h advlist.h callbacks.h framsg.h
+model.o: multimap.h multirange.h errmanager.h
+modelparts.o: modelparts.h 3d.h genoconv.h geno.h sstring.h extvalue.h
+modelparts.o: param.h list.h nonstd.h statrick.h virtfile.h sstringutils.h
+modelparts.o: syntparam.h usertags.h paramtabobj.h model.h advlist.h
+modelparts.o: callbacks.h neurolibrary.h multirange.h defassign-f0_neuro.h
+modelparts.o: defassign-f0_part.h defassign-f0_joint.h f0classes.h
+modelparts.o: defassign-f0_neuroconn.h
+multimap.o: multimap.h multirange.h list.h nonstd.h
+multiparamload.o: multiparamload.h param.h sstring.h list.h nonstd.h
+multiparamload.o: statrick.h virtfile.h framsg.h
+multirange.o: multirange.h list.h nonstd.h
+neurofactory.o: neurofactory.h modelparts.h 3d.h genoconv.h geno.h sstring.h
+neurofactory.o: extvalue.h param.h list.h nonstd.h statrick.h virtfile.h
+neurofactory.o: sstringutils.h syntparam.h usertags.h paramtabobj.h
+neurofactory.o: neuroimpl.h model.h advlist.h callbacks.h framsg.h
+neurofactory.o: neuroimplfiles.h neuroimpl-simple.h neuroimpl-channels.h
+neurofactory.o: neuroimpl-fuzzy.h neuroimpl-body-gdk.h neurocls-factory.h
+neuroimpl-channels.o: neuroimpl-channels.h neuroimpl.h model.h modelparts.h
+neuroimpl-channels.o: 3d.h genoconv.h geno.h sstring.h extvalue.h param.h
+neuroimpl-channels.o: list.h nonstd.h statrick.h virtfile.h sstringutils.h
+neuroimpl-channels.o: syntparam.h usertags.h paramtabobj.h advlist.h
+neuroimpl-channels.o: callbacks.h framsg.h
+neuroimpl.o: neuroimpl.h model.h modelparts.h 3d.h genoconv.h geno.h
+neuroimpl.o: sstring.h extvalue.h param.h list.h nonstd.h statrick.h
+neuroimpl.o: virtfile.h sstringutils.h syntparam.h usertags.h paramtabobj.h
+neuroimpl.o: advlist.h callbacks.h framsg.h neurofactory.h
+neuroimpl-fuzzy.o: neuroimpl-fuzzy.h neuroimpl.h model.h modelparts.h 3d.h
+neuroimpl-fuzzy.o: genoconv.h geno.h sstring.h extvalue.h param.h list.h
+neuroimpl-fuzzy.o: nonstd.h statrick.h virtfile.h sstringutils.h syntparam.h
+neuroimpl-fuzzy.o: usertags.h paramtabobj.h advlist.h callbacks.h framsg.h
+neuroimpl-fuzzy.o: neuroimpl-fuzzy-f0.h
+neuroimpl-fuzzy-f0.o: neuroimpl-fuzzy-f0.h sstring.h nonstd.h
+neuroimpl-simple.o: neuroimpl-simple.h neuroimpl.h model.h modelparts.h 3d.h
+neuroimpl-simple.o: genoconv.h geno.h sstring.h extvalue.h param.h list.h
+neuroimpl-simple.o: nonstd.h statrick.h virtfile.h sstringutils.h syntparam.h
+neuroimpl-simple.o: usertags.h paramtabobj.h advlist.h callbacks.h framsg.h
+neurolibrary.o: neurolibrary.h advlist.h list.h nonstd.h callbacks.h
+neurolibrary.o: statrick.h param.h sstring.h virtfile.h modelparts.h 3d.h
+neurolibrary.o: genoconv.h geno.h extvalue.h sstringutils.h syntparam.h
+neurolibrary.o: usertags.h paramtabobj.h neurocls-library.h
+neurotest.o: geno.h sstring.h extvalue.h param.h list.h nonstd.h statrick.h
+neurotest.o: virtfile.h genoconv.h stdiofile.h sstringutils.h defgenoconv.h
+neurotest.o: neuroimpl.h model.h modelparts.h 3d.h syntparam.h usertags.h
+neurotest.o: paramtabobj.h advlist.h callbacks.h framsg.h neurofactory.h
+neurotest.o: stdouterr.h errmanager.h
+param.o: param.h sstring.h list.h nonstd.h statrick.h virtfile.h extvalue.h
+param.o: framsg.h sstringutils.h
+paramobj.o: paramobj.h param.h sstring.h list.h nonstd.h statrick.h
+paramobj.o: virtfile.h extvalue.h
+paramtabobj.o: paramtabobj.h param.h sstring.h list.h nonstd.h statrick.h
+paramtabobj.o: virtfile.h
+printconvmap.o: printconvmap.h sstring.h multimap.h multirange.h list.h
+printconvmap.o: nonstd.h
+sstring.o: sstring.h nonstd.h
+sstringutils.o: sstringutils.h sstring.h virtfile.h framsg.h
+stdiofile-autoinit.o: stdiofile.h virtfile.h sstring.h
+stdiofile.o: stdiofile.h virtfile.h sstring.h nonstd.h nonstd_io.h
+stdouterr.o: stdouterr.h errmanager.h list.h nonstd.h sstring.h framsg.h
+syntparam.o: nonstd.h syntparam.h param.h sstring.h list.h statrick.h
+syntparam.o: virtfile.h paramobj.h
+virtfile.o: virtfile.h
Index: /cpp/gdk/advlist.cpp
===================================================================
--- /cpp/gdk/advlist.cpp	(revision 5)
+++ /cpp/gdk/advlist.cpp	(revision 5)
@@ -0,0 +1,43 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "advlist.h"
+
+void AdvList::remove(int i)
+{
+l_del.action(i);
+SList::remove(i);
+l_postdel.action(i);
+}
+
+void AdvList::clear()
+{
+int i;
+for (i=size()-1;i>=0;i--) remove(i);
+resize(0);
+used=0;
+}
+
+void AdvList::operator-=(void* e)
+{
+int i=find(e);
+if (i>=0) remove(i);
+}
+
+int AdvList::operator+=(void* e)
+{
+int p=size();
+SList::operator+=(e);
+l_add.action(p);
+return p;
+}
+
+void AdvList::mod(int x)
+{
+if (x<-1) x=-1;
+l_mod.action(x);
+}
Index: /cpp/gdk/advlist.h
===================================================================
--- /cpp/gdk/advlist.h	(revision 5)
+++ /cpp/gdk/advlist.h	(revision 5)
@@ -0,0 +1,35 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _ADVLIST_H_
+#define _ADVLIST_H_
+
+#include "list.h"
+#include "nonstd.h"
+#include "callbacks.h"
+
+////////////////////////////////////////////
+/// no more DuoList -> now we have Callback class (callbacks.h)
+
+/// list with notification support.
+/// you can register callbacks which will be activated
+/// as the list contents changes
+
+/// sorting functions moved to SortView class
+
+class AdvList: public SList
+{
+public:
+Callback l_add, l_del, l_mod, l_postdel;
+void remove(int);
+virtual void mod(int=-1); ///< call this when you change one or more elements in list (-1 means all elements)
+void clear();
+AdvList() {}
+~AdvList() {clear();}
+int operator+=(void*);
+void operator-=(void*);
+void operator-=(int i) {remove(i);}
+};
+
+#endif
Index: /cpp/gdk/callbacks.cpp
===================================================================
--- /cpp/gdk/callbacks.cpp	(revision 5)
+++ /cpp/gdk/callbacks.cpp	(revision 5)
@@ -0,0 +1,82 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "callbacks.h"
+#include <stdio.h>
+
+#ifdef USEMEMBERCALLBACK
+int MemberCallbackNode::equals(CallbackNode*n)
+{
+if (n==this) return 1;
+MemberCallbackNode *classok=dynamic_cast<MemberCallbackNode*>(n);
+if (!classok) return 0;
+return ((userdata==classok->userdata)&&(object==classok->object)&&(member==classok->member));
+}
+#endif
+
+int FunctionCallbackNode::equals(CallbackNode*n)
+{
+if (n==this) return 1;
+FunctionCallbackNode *classok=dynamic_cast<FunctionCallbackNode*>(n);
+if (!classok) return 0;
+return ((userdata==classok->userdata)&&(fun==classok->fun));
+}
+
+int StatrickCallbackNode::equals(CallbackNode*n)
+{
+if (n==this) return 1;
+StatrickCallbackNode *classok=dynamic_cast<StatrickCallbackNode*>(n);
+if (!classok) return 0;
+return ((object==classok->object)&&(userdata==classok->userdata)&&(fun==classok->fun));
+}
+
+/////////////////
+
+CallbackNode* Callback::add(CallbackNode*n)
+{
+SList::operator+=(n);
+return n;
+}
+
+void Callback::removeNode(CallbackNode*n)
+{
+SList::operator-=(n);
+delete n;
+}
+
+void Callback::remove(CallbackNode*node)
+{
+CallbackNode *n;
+//printf("Hint: removing callbacks (former 'DuoList') is more efficient using removeNode(). (refer to 'callbacks.h')\n");
+for (int i=0;n=(CallbackNode *)operator()(i);i++)
+	if (node->equals(n))
+		{
+		SList::operator-=(i);
+		delete node;
+		if (n!=node) delete n;
+		return;
+		}
+delete node; // tu nie wiem czy na pewno...
+}
+
+void Callback::action(long data)
+{
+FOREACH(CallbackNode*,n,(*this))
+	n->action(data);
+}
+
+Callback::~Callback()
+{
+CallbackNode *n;
+for (int i=size()-1;i>=0;i--)
+	{
+	n=(CallbackNode *)operator()(i);
+	delete n;
+// todo: zrobic zeby kolejnosc delete callbacknode <-> delete callback nie wplywala na poprawne dzialania
+// blad odkryty 24.01 pokazal, ze deletowanie callbacknodow w ~callback
+// moze powodowac problemy, jezeli obiekty sa usuwane w "zlej" kolejnosci
+// ale na razie tak zostanie
+	}
+}
+
Index: /cpp/gdk/callbacks.h
===================================================================
--- /cpp/gdk/callbacks.h	(revision 5)
+++ /cpp/gdk/callbacks.h	(revision 5)
@@ -0,0 +1,120 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _CALLBACKS_H_
+#define _CALLBACKS_H_
+
+#include "list.h"
+#include "statrick.h"
+
+//#define USEMEMBERCALLBACK
+
+class CallbackNode
+{
+public:
+virtual ~CallbackNode() {}
+virtual void action(long calldata)=0;
+virtual int equals(CallbackNode*n) {return (this==n);}
+};
+
+#ifdef USEMEMBERCALLBACK
+class CallBase;
+class MemberCallbackNode :public CallbackNode
+{
+void *userdata;
+CallBase *object;
+void (CallBase::*member)(void*,long);
+  public:
+MemberCallbackNode(CallBase *o,void (CallBase::*m)(void*,long),void *d):object(o),member(m),userdata(d) {}
+void action(long calldata) {(object->*member)(userdata,calldata);}
+int equals(CallbackNode*);
+};
+#define MEMBERCALLBACK(obj,mem,dat) new MemberCallbackNode((CallBase*)(obj),(void (CallBase::*)(void*,long))(mem),(void*)(dat))
+#endif
+
+class FunctionCallbackNode :public CallbackNode
+{
+void *userdata;
+void (*fun)(void*,long);
+  public:
+FunctionCallbackNode(void (*f)(void*,long),void *d):fun(f),userdata(d) {}
+void action(long calldata) {(*fun)(userdata,calldata);}
+int equals(CallbackNode*);
+};
+#define FUNCTIONCALLBACK(fun,dat) new FunctionCallbackNode((void (*)(void*,long))(fun),(void*)(dat))
+
+class StatrickCallbackNode :public CallbackNode
+{
+void *object;
+void *userdata;
+void (*fun)(void*,void*,long);
+  public:
+StatrickCallbackNode(void *o,void (*f)(void*,void*,long),void *d):object(o),fun(f),userdata(d) {}
+void action(long calldata) {(*fun)(object,userdata,calldata);}
+int equals(CallbackNode*);
+};
+#define STATRICKCALLBACK(obj,name,dat) new StatrickCallbackNode((void*)(obj),(void (*)(void*,void*,long))STATRICKNAME(name),(void*)(dat))
+
+/**
+   Like in old 'DuoList' you can register for an event giving function pointer
+      add(Function* fun, void* anydata)
+   'fun' will be called with your pointer as the first argument (void*)
+   and event specific value as the second argument (long)
+      fun(void* anydata,long eventdata)
+
+   'StatrickCallbackNode' uses static functions to emulate object member calls.
+   @see statrick.h
+   
+   Unregistering callbacks:
+   The old remove(...) still works, but removeNode() is more efficient.
+   To use it you have to store what you get from add(...);
+      CallbackNode* node=thelist.l_add.add(&fun,data);
+      // thelist.l_add.remove(&fun,data);
+      thelist.l_add.removeNode(node); // this is better!
+
+ */
+
+class Callback: protected SList
+{
+public:
+~Callback();
+CallbackNode* add(CallbackNode*n);
+CallbackNode* add(void (*f)(void*,long),void *d)
+	{return add(new FunctionCallbackNode(f,d));}
+void remove(void (*f)(void*,long),void *d)
+	{remove(new FunctionCallbackNode(f,d));}
+void remove(CallbackNode*n);
+void removeNode(CallbackNode*n);
+void operator+=(void* fun) {add((void (*)(void*,long))fun,0);}
+void operator-=(void* fun) {remove((void (*)(void*,long))fun,0);}
+void action(long data);
+void action() {action(0);}
+int size() {return SList::size();}
+void clear() {SList::clear();}
+};
+
+///////////////////
+
+#define STCALLBACKDEF(name) STATRICKDEF2(name,void*,long)
+#define STCALLBACKDEFC(cls,name) STATRICKSTUB2(cls,name,void*,long)  \
+	void name(void* arg1,long arg2)
+#define VIRTCALLBACKDEF(name) STATRICKSTUB2(STATRICKCLASS,name,void*,long)  \
+	virtual void name(void* arg1,long arg2)
+#define VIRTCALLBACKDEFC(cls,name) STATRICKSTUB2(cls,name,void*,long)  \
+	virtual void name(void* arg1,long arg2)
+
+/* STCALLBACKDEFC(Class,name)
+
+     |
+     v
+
+   #define STATRICKCLASS Class
+   STCALLBACKDEF(name)
+   #undef STATRICKCLASS
+ */
+
+#define CALLBACKARGS void* arg1,long arg2
+
+#endif
+
Index: /cpp/gdk/conv_f1.cpp
===================================================================
--- /cpp/gdk/conv_f1.cpp	(revision 5)
+++ /cpp/gdk/conv_f1.cpp	(revision 5)
@@ -0,0 +1,436 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "conv_f1.h"
+#include "nonstd.h"
+#include "framsg.h"
+#include "multirange.h"
+#include "multimap.h"
+#include <ctype.h>
+
+//#define v1f1COMPATIBLE
+
+F1Props stdprops={1, 0, 1, 0.4, 0.25, 0.25, 0.25, 0.25, 0.0, 1.0, 1.0, 1 };
+
+class Builder
+{
+public:
+Builder(const char*g,int mapping=0):genbegin(g),usemapping(mapping),energ(0),energ_div(0),invalid(0) {}
+char tmp[222];
+bool invalid;
+Model model;
+const char *genbegin;
+SList neuro_f1_to_f0; // neuro_f1_to_f0(f1_refno) = actual neuro pointer
+Neuro *last_f1_neuro;
+	struct Connection { int n1,n2; double w;
+		Connection(int _n1,int _n2, double _w):n1(_n1),n2(_n2),w(_w) {} };
+SListTempl<Connection> connections;
+int usemapping;
+MultiRange range;
+double lastjoint_muscle_power;
+double energ,energ_div;
+void grow(int part1,const char*g,Pt3D k,F1Props c);
+int growJoint(int part1,int part2,Pt3D &angle,F1Props &c,const char *g);
+int growPart(F1Props &c,const char *g);
+const char *skipNeuro(const char *z);
+const char* growNeuro(const char* t,F1Props &c,int&);
+void growConnection(const char* begin,const char* colon,const char* end,F1Props& props);
+int countBranches(const char*g,SList &out);
+void addClassParam(const SString& newparam);
+void addClassParam(const char* name,double value);
+
+const MultiRange* makeRange(const char*g) {return makeRange(g,g);}
+const MultiRange* makeRange(const char*g,const char*g2);
+Part *getLastPart() {return getLastJoint()->part2;}
+Neuro *getLastNeuro() {return model.getNeuro(model.getNeuroCount()-1);}
+Joint *getLastJoint() {return model.getJoint(model.getJointCount()-1);}
+void addOrRememberInput(int n1,int n2,float w)
+		{
+		if (!addInput(n1,n2,w,false))
+			connections+=Connection(n1,n2,w);
+		}
+bool addInput(int n1,int n2,float w,bool final)
+		{
+		if ((n1<0) || (n2<0) || (n1>=neuro_f1_to_f0.size()) || (n2>=neuro_f1_to_f0.size()))
+			{
+			if (final) FMprintf("GenoConvF1","addInput",FMLV_WARN,
+					    "illegal neuron connection %d <- %d (ignored)",n1,n2);
+			return 0;
+			}
+		Neuro *neuro=(Neuro*)neuro_f1_to_f0(n1);
+		Neuro *input=(Neuro*)neuro_f1_to_f0(n2);
+		neuro->addInput(input,w);
+		return 1;
+		}
+void addPendingInputs()
+		{
+		for(int i=0;i<connections.size();i++)
+			{
+			Connection *c=&connections(i);
+			addInput(c->n1,c->n2,c->w,true);
+			}
+		}
+};
+
+const MultiRange* Builder::makeRange(const char*g,const char*g2)
+{
+if (!usemapping) return 0;
+range.clear();
+range.add(g-genbegin,g2-genbegin);
+return &range;
+}
+
+void F1Props::wykluczanie()
+{
+double s=ruch+asym+odpor+wchl;
+ruch=ruch/s;
+asym=asym/s;
+odpor=odpor/s;
+wchl=wchl/s;
+}
+
+/** main conversion function - with conversion map support */
+SString GenoConv_F1::convert(SString &i,MultiMap *map)
+{
+const char* g=(const char*)i;
+Builder builder(g,map?1:0);
+builder.model.open();
+builder.grow(-1,g,Pt3D_0,stdprops); // uses Model::singleStepBuild to create model elements
+if (builder.invalid) return SString();
+builder.addPendingInputs();
+builder.model.startenergy=(builder.energ_div>0)?(builder.energ/builder.energ_div):1.0;
+builder.model.close(); // model is ready to use now
+if (map) builder.model.getCurrentToF0Map(*map); // generate f1-to-f0 conversion map
+return builder.model.getF0Geno().getGene();
+}
+
+void Builder::grow(int part1,const char*g,Pt3D k,F1Props c)
+{
+int hasmuscles=0;
+k+=Pt3D(c.rot,0,c.skr);
+while(1)
+{
+switch(*g)
+	{
+	case 0: case ',': case ')': return;
+	case 'R': k.x+=0.7853;	break;
+	case 'r': k.x-=0.7853;	break;
+	case 'Q': c.rot+=(1.58-c.rot)*0.3;	break;
+	case 'q': c.rot+=(-1.58-c.rot)*0.3;	break;
+#ifdef v1f1COMPATIBLE
+	case 'L': c.dlug+=(3.0-c.dlug)*0.3; break;
+#else
+	case 'L': c.dlug+=(2.0-c.dlug)*0.3; break;
+#endif                                       
+	case 'l': c.dlug+=(0.33-c.dlug)*0.3; break;
+	case 'A': c.asym+=(1-c.asym)*0.8;	c.wykluczanie(); break;
+	case 'a': c.asym-=c.asym*0.4;	c.wykluczanie(); break;
+	case 'I': c.wchl+=(1-c.wchl)*0.8;	c.wykluczanie(); break;
+	case 'i': c.wchl-=c.wchl*0.4;	c.wykluczanie(); break;
+	case 'S': c.odpor+=(1-c.odpor)*0.8; c.wykluczanie(); break;
+	case 's': c.odpor-=c.odpor*0.4; c.wykluczanie(); break;
+	case 'M': c.ruch+=(1-c.ruch)*0.8;	c.wykluczanie(); break;
+	case 'm': c.ruch-=c.ruch*0.4;	c.wykluczanie(); break;
+	case 'C': c.skr+=(2.0-c.skr)*0.25;	break;
+	case 'c': c.skr+=(-2.0-c.skr)*0.25;break;
+	case 'F': c.tarcie+=(4-c.tarcie)*0.2;	break;
+	case 'f': c.tarcie-=c.tarcie*0.2;		break;
+	case 'W': c.masa+=(2.0-c.masa)*0.3;	break;
+	case 'w': c.masa+=(0.5-c.masa)*0.3;	break;
+	case 'E': c.energ+=(10.0-c.energ)*0.1;	break;
+	case 'e': c.energ-=c.energ*0.1;		break;
+	case '[': //neuron
+//		setdebug(g-(char*)geny,DEBUGNEURO | !l_neu);
+		if (model.getJointCount())
+			g=growNeuro(g+1,c,hasmuscles);
+		else
+			{
+			FramMessage("GenoConv_F1","grow","Illegal neuron position (ignored)",1);
+			g=skipNeuro(g+1);
+			}
+		break;
+	case 'X':
+		{
+		int freshpart=0;
+//setdebug(g-(char*)geny,DEBUGEST | !l_est);
+		if (part1<0) //initial grow
+			{
+		  if (model.getPartCount()>0)
+			    part1=0;
+		    else
+			    {
+			    part1=growPart(c,g);
+			    freshpart=1;
+			    }
+		  }
+		if (!freshpart)
+			{
+			Part *part=model.getPart(part1);
+			part->density=((part->mass*part->density)+1.0/c.masa)/(part->mass+1.0); // v=m*d
+//			part->volume+=1.0/c.masa;
+			part->mass+=1.0;
+			}
+		energ+=0.9*c.energ+0.1;
+		energ_div+=1.0;
+
+		int part2 = growPart(c,g);
+		growJoint(part1,part2,k,c,g);
+//		est* e = new est(*s,*s2,k,c,zz,this);
+
+		// oslabianie cech wzdluz struktury
+		c.dlug=0.5*c.dlug+0.5*stdprops.dlug;
+		c.skr=0.66*c.skr;
+		c.rot=0.66*c.rot;
+		c.tarcie=0.8*c.tarcie+0.2*stdprops.tarcie;
+
+		c.asym=0.8*c.asym+0.2*stdprops.asym;
+		c.odpor=0.8*c.odpor+0.2*stdprops.odpor;
+		c.ruch=0.8*c.ruch+0.2*stdprops.ruch;
+		c.wchl=0.8*c.wchl+0.2*stdprops.wchl;
+		c.masa+=(stdprops.masa-c.masa)*0.5;
+		c.wykluczanie();
+	
+		if (c.resetrange) c.bendrange=1.0; else c.resetrange=1;
+		grow(part2,g+1,Pt3D_0,c);
+		return;
+		}
+	case '(':
+		{
+		SList ga;
+		int i,ile;
+		ile=countBranches(g+1,ga);
+		c.resetrange=0;
+		c.bendrange=1.0/ile;
+		for (i=0;i<ile;i++)
+			grow(part1,(char*)ga(i),k+Pt3D(0,0,-3.141+(i+1)*(6.282/(ile+1))),c);
+		return;
+		}
+	case ' ': case '\t': case '\n': case '\r': break;
+	default: invalid=1; return;
+	}
+	g++;
+	}
+}
+
+void Builder::addClassParam(const SString& newparam)
+{
+SString allparams=last_f1_neuro->getClassParams();
+if (allparams.len()) allparams+=',';
+allparams+=newparam;
+last_f1_neuro->setClassParams(allparams);
+}
+void Builder::addClassParam(const char* name,double value)
+{
+SString t;
+sprintf(t.directWrite(30),"%s=%g",name,value);
+t.endWrite();
+addClassParam(t);
+}
+
+
+int Builder::countBranches(const char*g,SList &out)
+{
+int gl=0;
+out+=(void*)g;
+while (gl>=0)
+	{
+	switch(*g)
+		{
+		case 0: gl=-1; break;
+		case '(': case '[': ++gl; break;
+		case ')': case ']': --gl; break;
+		case ',': if (!gl) out+=(void*)(g+1);
+		}
+	g++;
+	}
+return !out;
+}
+
+int Builder::growJoint(int part1,int part2,Pt3D &angle,F1Props &c,const char *g)
+{
+double len=min(2.0,c.dlug);
+sprintf(tmp,"j:p1=%ld,p2=%ld,dx=%lg,rx=%lg,ry=%lg,rz=%lg,stam=%lg",
+	part1,part2,len,angle.x,angle.y,angle.z,c.odpor);
+lastjoint_muscle_power=c.ruch;
+return model.singleStepBuild(tmp,makeRange(g));
+}
+
+int Builder::growPart(F1Props &c,const char *g)
+{
+sprintf(tmp,"p:m=1,dn=%lg,fr=%lg,ing=%lg,as=%lg",
+	1.0/c.masa,c.tarcie,c.wchl,c.asym);
+return model.singleStepBuild(tmp,makeRange(g));
+}
+
+const char *Builder::skipNeuro(const char *z)
+{
+for (;*z;z++) if ((*z==']')||(*z==')')) break;
+return z-1;
+}
+
+// remove leading & trailing whitespaces
+static void trim(SString& s)
+{
+const char*b=(const char*)s;
+const char*e=b+s.len();
+while((b<e)&&(*b<=' ')) b++;
+while((b<e)&&(e[-1]<=' ')) e--;
+if ((e-b)==s.len()) return;
+char* t=s.directWrite();
+if (t!=b) memmove(t,b,e-b);
+s.endWrite(e-b);
+}
+
+const char* Builder::growNeuro(const char* t, F1Props& props,int &hasmuscles)
+{
+const char*neuroend=skipNeuro(t);
+last_f1_neuro=model.addNewNeuro();
+last_f1_neuro->attachToPart(getLastPart());
+const MultiRange *mr=makeRange(t-1,neuroend+1);
+if (mr) last_f1_neuro->setMapping(*mr);
+neuro_f1_to_f0+=last_f1_neuro;
+
+SString clsname;
+bool haveclass=0;
+while(*t && *t<=' ') t++;
+const char* next=(*t)?(t+1):t;
+while(*next && *next<=' ') next++;
+if (*t && *next!=',' && *next!=']') // old style muscles [|rest] or [@rest]
+switch(*t)
+	{
+	case '@': if (t[1]==':') break;
+		haveclass=1;
+//		if (!(hasmuscles&1))
+                {
+                  hasmuscles|=1;
+		  Neuro *muscle=model.addNewNeuro();
+                  sprintf(tmp,"@:p=%lg",lastjoint_muscle_power);
+		  muscle->addInput(last_f1_neuro);
+		  muscle->setDetails(tmp);
+		  muscle->attachToJoint(getLastJoint());
+		  if (usemapping) muscle->setMapping(*makeRange(t));
+                }
+		t++;
+		break;
+	case '|': if (t[1]==':') break;
+		haveclass=1;
+//		if (!(hasmuscles&2))
+                {
+                  hasmuscles|=2;
+		  Neuro *muscle=model.addNewNeuro();
+                  sprintf(tmp,"|:p=%lg,r=%lg",lastjoint_muscle_power,props.bendrange);
+		  muscle->addInput(last_f1_neuro);
+		  muscle->setDetails(tmp);
+		  muscle->attachToJoint(getLastJoint());
+		  if (usemapping) muscle->setMapping(*makeRange(t));
+                }
+		t++;
+		break;
+	}
+while(*t && *t<=' ') t++;
+bool finished=0;
+const char *begin=t;
+const char* colon=0;
+SString classparams;
+while(!finished)
+	{
+	switch (*t)
+		{
+		case ':': colon=t; break;
+		case 0: case ']': case ')': finished=1;
+			// NO break!
+		case ',':
+			if ( !haveclass && !colon && t>begin )
+				{
+				haveclass=1;
+				SString clsname(begin,t-begin);
+				trim(clsname);
+				last_f1_neuro->setClassName(clsname);
+				NeuroClass *cls=last_f1_neuro->getClass();
+				if (cls)
+					{
+					if (cls->getPreferredLocation()==2)
+						last_f1_neuro->attachToJoint(getLastJoint());
+					else if (cls->getPreferredLocation()==1)
+						last_f1_neuro->attachToPart(getLastPart());
+					}
+				}
+			else if (colon && (colon>begin) && (t>colon))
+				growConnection(begin,colon,t,props);
+			if (t[0]!=',') t--;
+			begin=t+1; colon=0;
+			break;
+		}
+	t++;
+	}
+return t;
+}
+void Builder::growConnection(const char* begin, const char* colon,const char* end,F1Props& props)
+{
+while(*begin && *begin<=' ') begin++;
+int i;
+if (isdigit(begin[0]) || (begin[0]=='-'))
+	{
+	float weight=atof(colon+1);
+	int relative=atoi(begin);
+	int this_refno=neuro_f1_to_f0.size()-1;
+	addOrRememberInput(this_refno,this_refno+relative,weight);
+	}
+else if ((i=last_f1_neuro->extraProperties().findIdn(begin,colon-begin))>=0)
+	{
+	last_f1_neuro->extraProperties().set(i,colon+1);
+	}
+else if (isupper(begin[0]) || strchr("*|@",begin[0]))
+	{
+	SString clsname(begin,colon-begin);
+	trim(clsname);
+	Neuro *receptor=model.addNewNeuro();
+	receptor->setClassName(clsname);
+	NeuroClass *cls=receptor->getClass();
+	if (cls)
+		{
+		if (cls->getPreferredLocation()==2) receptor->attachToJoint(getLastJoint());
+		else if (cls->getPreferredLocation()==1) receptor->attachToPart(getLastPart());
+		}
+	last_f1_neuro->addInput(receptor,atof(colon+1));
+	if (usemapping) receptor->setMapping(*makeRange(begin,end-1));
+	}
+else if ((begin[0]=='>')&&(begin[1]))
+	{
+	Neuro *out=model.addNewNeuro();
+	out->addInput(last_f1_neuro,atof(colon+1));
+	out->setClassName(SString(begin+1,end-colon-1));
+	if (begin[1]=='@')
+		{
+		sprintf(tmp,"p=%lg",lastjoint_muscle_power);
+		out->setClassParams(tmp);
+		}
+	else if (begin[1]=='|')
+		{
+		sprintf(tmp,"p=%lg,r=%lg",lastjoint_muscle_power,props.bendrange);
+		out->setClassParams(tmp);
+		}
+	NeuroClass *cls=out->getClass();
+	if (cls)
+		{
+		if (cls->getPreferredLocation()==2) out->attachToJoint(getLastJoint());
+		else if (cls->getPreferredLocation()==1) out->attachToPart(getLastPart());
+		}
+	if (usemapping) out->setMapping(*makeRange(begin,end-1));
+	}
+else if (*begin=='!') addClassParam("fo",max(0.0,min(1.0,atof(colon+1))));
+else if (*begin=='=') addClassParam("in",max(0.0,min(1.0,atof(colon+1))));
+else if (*begin=='/') addClassParam("si",atof(colon+1));
+/*else if (*begin=='!') last_f1_neuro->force=max(0.0,min(1.0,atof(colon+1)));
+else if (*begin=='=') last_f1_neuro->inertia=max(0.0,min(1.0,atof(colon+1)));
+else if (*begin=='/') last_f1_neuro->sigmo=atof(colon+1);
+*/
+else if (islower(begin[0]))
+	{
+	SString newparam(begin,end-begin);
+	trim(newparam);
+	newparam.directWrite()[colon-begin]='='; // ':' -> '='
+	addClassParam(newparam);
+	}
+}
Index: /cpp/gdk/conv_f1.h
===================================================================
--- /cpp/gdk/conv_f1.h	(revision 5)
+++ /cpp/gdk/conv_f1.h	(revision 5)
@@ -0,0 +1,81 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _CONV_F1_H
+#define _CONV_F1_H
+
+#include "genoconv.h"
+#include "model.h"
+
+struct F1Props
+{
+	double dlug,skr,masa,tarcie,ruch,asym,odpor,wchl,rot,energ;
+	double bendrange;
+	int resetrange;
+	void wykluczanie();
+};
+
+/**
+ Official framsticks f1 -> f0 converter.
+ Source code is published as educational example, but currently not
+ well documented.
+ This converter features building creature using Model class
+ and some advanced tricks (changing model data during construction).
+ Final f0 genotype is generated by model class.
+
+ <b>GDK 1.0.5 NN extension: (for Framsticks 2.0)</B>
+
+ Until now, only the "standard" Framsticks v1 neuron classes could be used.
+ Starting with GDK 1.0.5 you can use all neuron types.
+
+ \b Syntax: [classname , input_or_parameter:weight , input_or_parameter:weight , ...]
+
+ The classname is optional, the default class will be used if it is omitted.
+ Note the comma after \b classname. It must be present if you provide the classname.
+ This is to distinguish between old muscle syntax and new classname specification:
+ - "[|,0:1]" is the neuron of class "|" (bend muscle) with one self connection.
+ \image html nn-ex1.gif
+ - "[|0:1]" describes the default neuron class (N) connected with the bend muscle (|).
+ \image html nn-ex2.gif
+
+
+ Neuron parameters can be specified along with inputs, eg: "[myclass,param1:34,param2:56]"
+ The names beginning with UPPER case character are assumed to be neuron classes.
+ "[myclass,g:1.23,G:2.34]" - the first 'g' is the parameter, the second one is the receptor
+ G ("gyroscope").
+
+ Another example:
+
+ "X[G][-1:2.3][-2:3.4]" - The first neuron is the standalone G receptor. Other neuron can use its output 
+ signal by specifying it as regular input ("-1:2.3" and "-2:3.4"). This NN contains 3 neurons.
+ \image html nn-ex3.gif
+
+ "X[G:2.3][G:3.4]" - with the old syntax it is impossible to connect 2 neurons with the same gyroscope,
+ because everything inside brackets is private to the neuron, others can't refer to it.
+ Adding another neuron with "G" input will add another gyroscope object. This NN contains 4 neurons
+ (or 2 neurons if you try it in Framsticks v1).
+  \image html nn-ex4.gif
+ 
+*/
+class GenoConv_F1: public GenoConverter
+{
+public:
+GenoConv_F1()
+	{
+	name="f1 converter";
+	in_format='1';
+	mapsupport=1;
+	info="Original Framsticks genotype format";
+	}
+SString convert(SString &i,MultiMap *map);
+~GenoConv_F1() {}
+};
+
+
+#endif
+
+
+
+
+
Index: /cpp/gdk/convtest.cpp
===================================================================
--- /cpp/gdk/convtest.cpp	(revision 5)
+++ /cpp/gdk/convtest.cpp	(revision 5)
@@ -0,0 +1,159 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include <ctype.h>
+#include "genoconv.h"
+#include "model.h"
+#include "multimap.h"
+#include "conv_f1.h"
+
+#include "printconvmap.h"
+#include "stdouterr.h"
+
+StdoutErrorHandler err;
+
+/**
+ @file
+ Sample code: Genotype converter class
+*/
+
+/// Sample Geno converter not using Model class.
+/// (this converter generates the same output for each input).
+/// such a converter is responsible for doing valid
+/// f0 (or other format) output and storing temporary data
+class GenoConv_Test: public GenoConverter
+{
+public:
+GenoConv_Test()
+	{
+	name="Test Converter";
+	in_format='x';
+	}
+SString convert(SString &i,MultiMap *map) {return SString("after conversion...");}
+~GenoConv_Test() {}
+};
+
+/// Sample Geno converter using Model class.
+/// (this converter generates the same output for each input).
+class GenoConv_Test2: public GenoConverter
+{
+public:
+GenoConv_Test2()
+	{
+	name="Test Converter #2";
+	in_format='y';
+	}
+SString convert(SString &i,MultiMap *map)
+{
+Model mod;
+mod.open();
+mod.singleStepBuild("p:");
+mod.singleStepBuild("p:");
+mod.singleStepBuild("j:0,1");
+mod.getPart(1)->p=Pt3D(0,0.2,-1);
+mod.close();
+return mod.getGeno().getGene();
+}
+~GenoConv_Test2() {}
+};
+
+/// Sample Geno converter supporting conversion mapping.
+/// the conversion is very simple: any sequence of <digit><character>
+/// (but not inside neurons) is replaced by the repeated sequence of the character
+class GenoConv_Test3: public GenoConverter
+{
+public:
+GenoConv_Test3()
+	{
+	name="Test Converter #3";
+	in_format='z';
+	out_format='1';
+	mapsupport=1;
+	}
+SString convert(SString &in,MultiMap *map);
+~GenoConv_Test3() {}
+};
+
+/** main converting routine - most important: direct conversion map example */
+SString GenoConv_Test3::convert(SString &in,MultiMap *map)
+{
+SString dst;
+const char* src=in;
+const char* t;
+int insideneuron=0;
+int n;
+for(t=src;*t;t++)
+	{
+	if (insideneuron&&*t==']') insideneuron=0;
+	if (*t=='[') insideneuron=1;
+	if ((!insideneuron)&&isdigit(*t)&&t[1])
+		{ // special sequence detected!
+		n=*t-'0';
+		t++; // *t will be repeated 'n' times
+		for (int i=0;i<n;i++)
+			dst+=*t;
+		if (map) // fill in the map only if requested
+			map->add(t-src, t-src, dst.len()-n, dst.len()-1);
+		// meaning: source character (t-src) becomes (dst.len()-n ... dst.len()-1)
+		}
+	else
+		{
+		dst+=*t;
+		if (map)
+			map->add(t-src, t-src, dst.len()-1, dst.len()-1);
+		// meaning: map single to single character: (t-src) into (dst.len()-1)
+		}
+	}
+return dst;
+}
+
+
+///////////////////////////////////////////////
+
+void printGen(Geno &g)
+{
+printf("Genotype:\n%s\nFormat: %c\nValid: %s\nComment: %s\n",
+	(const char*)g.getGene(),g.getFormat(),g.isValid()?"yes":"no",(const char*)g.getComment());
+}
+
+int main(int argc,char *argv[])
+{
+GenoConvManager gcm;
+gcm.addConverter(new GenoConv_Test());
+gcm.addConverter(new GenoConv_Test2());
+gcm.addConverter(new GenoConv_Test3());
+gcm.addConverter(new GenoConv_F1());
+
+const char* src=(argc>1)?argv[1]:"X";
+char dst=(argc>2)?*argv[2]:'0';
+
+printf("*** source genotype:\n");
+Geno g1(src);
+printGen(g1);
+MultiMap m;
+Geno g2=g1.getConverted(dst,&m);
+printf("*** converted to f%c:\n",dst);
+printGen(g2);
+if (m.isEmpty())
+	printf("(conversion map not available)\n");
+else
+	{
+	printf("conversion map:\n");
+	m.print();
+	printConvMap(g1.getGene(),g2.getGene(),m);
+	printf("reverse conversion map:\n");
+	MultiMap rm;
+	rm.addReversed(m);
+	rm.print();
+	printConvMap(g2.getGene(),g1.getGene(),rm);
+	}
+
+Model mod1(g1,1);
+printf("\nmodel map for f%c genotype:\n",g1.getFormat());
+printModelMap(g1.getGene(),mod1.getMap());
+Model mod2(g2,1);
+printf("\nmodel map for f%c genotype:\n",g2.getFormat());
+printModelMap(g2.getGene(),mod2.getMap());
+return 0;
+}
Index: /cpp/gdk/convtest.dsp
===================================================================
--- /cpp/gdk/convtest.dsp	(revision 5)
+++ /cpp/gdk/convtest.dsp	(revision 5)
@@ -0,0 +1,291 @@
+# Microsoft Developer Studio Project File - Name="convtest" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=convtest - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "convtest.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "convtest.mak" CFG="convtest - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "convtest - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "convtest___Win32_Debug"
+# PROP BASE Intermediate_Dir "convtest___Win32_Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ""
+# PROP Intermediate_Dir ""
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GR /GX /ZI /Od /D "_Windows" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "EASYMAPDEBUG" /D "NOCREATUREOBJECT" /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x415 /d "_DEBUG"
+# ADD RSC /l 0x415 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# Begin Target
+
+# Name "convtest - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\3d.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\advlist.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\callbacks.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\conv_f1.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\convtest.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\defgenoconv.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\errmanager.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\extvalue.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\framsg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\geno.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\genoconv.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\list.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\model.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modelparts.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\multimap.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\multirange.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\neurolibrary.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\param.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\paramobj.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\paramtabobj.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\printconvmap.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sstring.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sstringutils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\stdouterr.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\syntparam.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\virtfile.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\3d.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\advlist.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\callbacks.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\conv_f1.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\defassign-f0_joint.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\defassign-f0_neuro.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\defassign-f0_part.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\defgenoconv.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\extvalue.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\f0classes.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\framsg.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\gen-config.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\geno.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\genoconv.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\list.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\model.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\modelparts.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\multimap.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\multirange.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\neuroclasses.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\neurocls-library.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\neurolibrary.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\nonstd.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\param.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\paramtabobj.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\printconvmap.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\sstring.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\sstringutils.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\statrick.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\syntparam.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\usertags.h
+# End Source File
+# End Group
+# End Target
+# End Project
Index: /cpp/gdk/defassign-f0_joint.h
===================================================================
--- /cpp/gdk/defassign-f0_joint.h	(revision 5)
+++ /cpp/gdk/defassign-f0_joint.h	(revision 5)
@@ -0,0 +1,42 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+
+
+
+// default assignments for Joint : 
+p1_refno=-1;
+p2_refno=-1;
+d.x=0;
+d.y=0;
+d.z=0;
+stif=1.0;
+rotstif=1.0;
+stamina=0.25;
+vis_style="joint";
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: /cpp/gdk/defassign-f0_neuro.h
===================================================================
--- /cpp/gdk/defassign-f0_neuro.h	(revision 5)
+++ /cpp/gdk/defassign-f0_neuro.h	(revision 5)
@@ -0,0 +1,36 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+
+
+
+
+
+
+
+// default assignments for Neuro : 
+part_refno=-1;
+joint_refno=-1;
+vis_style="neuro";
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: /cpp/gdk/defassign-f0_neuroconn.h
===================================================================
--- /cpp/gdk/defassign-f0_neuroconn.h	(revision 5)
+++ /cpp/gdk/defassign-f0_neuroconn.h	(revision 5)
@@ -0,0 +1,36 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+
+
+
+
+
+
+
+
+
+// default assignments for NeuroConn : 
+n1_refno=-1;
+n2_refno=-1;
+weight=1.0;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: /cpp/gdk/defassign-f0_part.h
===================================================================
--- /cpp/gdk/defassign-f0_part.h	(revision 5)
+++ /cpp/gdk/defassign-f0_part.h	(revision 5)
@@ -0,0 +1,40 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+
+// default assignments for Part : 
+mass=1.0;
+size=1.0;
+density=1.0;
+friction=0.4;
+ingest=0.25;
+assim=0.25;
+vis_style="part";
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: /cpp/gdk/defassign.m4
===================================================================
--- /cpp/gdk/defassign.m4	(revision 5)
+++ /cpp/gdk/defassign.m4	(revision 5)
@@ -0,0 +1,21 @@
+divert(-1)
+
+define(`NEUROPROP',`dnl')
+define(`NEUROCLASS',`dnl')
+define(`VISUALHINTS',`dnl')
+define(`ENDNEUROCLASS',`dnl')
+define(`SYMBOL',`dnl')
+
+define(`MAYBE_QUOTE',`ifelse($1,s,"$2",$2)')
+
+define(`GROUP',`dnl')
+define(`ENDCLASS',`dnl')
+define(`CLASS',`ifelse($2,USECLASS,
+`// default assignments for $1 : define(`PROP',`ifelse($'8`,,`dnl',$'9`=MAYBE_QUOTE($'5`,$'8`));')dnl'
+,
+`define(`PROP',`dnl')dnl'
+)')
+
+define(`XPROP',`PROP($@)')
+changecom
+divert
Index: /cpp/gdk/defgenoconv.cpp
===================================================================
--- /cpp/gdk/defgenoconv.cpp	(revision 5)
+++ /cpp/gdk/defgenoconv.cpp	(revision 5)
@@ -0,0 +1,68 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "defgenoconv.h"
+
+#include "gen-config.h"
+
+#ifdef USE_GENCONV_F10
+#include "conv_f1.h"
+#endif
+#ifdef USE_GENCONV_F20
+#include "conv_f2.h"
+#endif
+#ifdef USE_GENCONV_F32
+#include "conv_f3.h"
+#endif
+#ifdef USE_GENCONV_F40
+#include "conv_f4.h"
+#endif
+#ifdef USE_GENCONV_F41_TEST
+#include "conv_f4.h"
+#endif
+#ifdef USE_GENCONV_F50
+#include "conv_f5.h"
+#endif
+#ifdef USE_GENCONV_F60
+#include "geno_f6.h"
+#endif
+#ifdef USE_GENCONV_F70
+#include "conv_f7.h"
+#endif
+#ifdef USE_GENCONV_F81
+#include "conv_f8.h"
+#endif
+
+DefaultGenoConvManager::DefaultGenoConvManager()
+{
+#ifdef USE_GENCONV_F10
+addConverter(new GenoConv_F1());
+#endif
+#ifdef USE_GENCONV_F20
+addConverter(new GenoConv_F20());
+#endif
+#ifdef USE_GENCONV_F32
+addConverter(new GenoConv_F32());
+#endif
+#ifdef USE_GENCONV_F40
+addConverter(new GenoConv_F40());
+#endif
+#ifdef USE_GENCONV_F41_TEST
+addConverter(new GenoConv_F41_TestOnly());
+#endif
+#ifdef USE_GENCONV_F50
+addConverter(new GenoConv_F50);
+#endif
+#ifdef USE_GENCONV_F60
+addConverter(new GenoConv_F60);
+#endif
+#ifdef USE_GENCONV_F70
+addConverter(new GenoConv_F70);
+#endif
+#ifdef USE_GENCONV_F81
+addConverter(new GenoConv_F81);
+#endif
+
+param.updatetab();
+}
Index: /cpp/gdk/defgenoconv.h
===================================================================
--- /cpp/gdk/defgenoconv.h	(revision 5)
+++ /cpp/gdk/defgenoconv.h	(revision 5)
@@ -0,0 +1,19 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _DEFGENOCONV_H_
+#define _DEFGENOCONV_H_
+
+#include "genoconv.h"
+
+/// This GenoConvManager automatically registers the "standard" converters available in the GDK.
+/// All you have to do is create a single instance of this class somewhere in your application.
+/// @see genotest.cpp
+class DefaultGenoConvManager: public GenoConvManager
+{
+  public:
+DefaultGenoConvManager();
+};
+
+#endif
Index: /cpp/gdk/errmanager.cpp
===================================================================
--- /cpp/gdk/errmanager.cpp	(revision 5)
+++ /cpp/gdk/errmanager.cpp	(revision 5)
@@ -0,0 +1,108 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "errmanager.h"
+
+ErrorManager globalErrorManager;
+
+void FramMessage(const char *o,const char *m,const char *bl,int w)
+{
+globalErrorManager.send(o,m,bl,w);
+}
+
+void ErrorManager::send(int level,const char *o,const char *m,const char *bl,int w)
+{
+if (level>=handlers.size()) level=handlers.size()-1;
+bool blocked=0;
+for(int i=level;i>=0;i--)
+	{
+	ErrorHandlerBase *r=handlers(i);
+	if ((!blocked)||(r->options & ErrorHandlerBase::CannotBeBlocked))
+		r->handle(o,m,bl,w);
+	if (!(r->options & ErrorHandlerBase::DontBlock)) blocked=1;
+	}
+}
+
+int ErrorManager::add(ErrorHandlerBase *h)
+{
+h->mgr=this;
+handlers+=h;
+return handlers.size()-1;
+}
+
+void ErrorManager::remove(int i)
+{
+ErrorHandlerBase *h=handlers(i);
+h->mgr=0;
+handlers.remove(i);
+}
+
+void ErrorManager::remove(ErrorHandlerBase *h)
+{
+int i;
+if ((i=handlers.find(h))<0) return;
+remove(i);
+}
+
+void ErrorManager::removeAll()
+{
+while(handlers.size()>0)
+	remove(handlers.size()-1);
+}
+
+//////////////////////////////////
+
+void ErrorHandlerBase::send(const char *o,const char *m,const char *bl,int w)
+{
+if (!isEnabled()) return;
+int level=mgr->find(this);
+if (level>=0) mgr->send(level-1,o,m,bl,w);
+}
+
+void ErrorHandlerBase::FMprintf(const char *o,const char *m,int w,const char *bl, ...)
+{
+if (!isEnabled()) return;
+char buf[10000];
+va_list argptr;
+va_start(argptr,bl);
+vsnprintf(buf,10000,bl,argptr);
+va_end(argptr);
+send(o,m,buf,w);
+}
+
+
+void ErrorHandlerBase::enable()
+{
+if (isEnabled()) return;
+globalErrorManager.add(this);
+}
+
+void ErrorHandlerBase::disable()
+{
+if (!isEnabled()) return;
+globalErrorManager.remove(this);
+}
+
+/////////////////////////////////
+
+void ErrorHandler::handle(const char *o,const char *m,const char *bl,int w)
+{
+if (w>maxlevel) maxlevel=w;
+if (w>=FMLV_WARN) warncount++;
+if (w>=FMLV_ERROR) errcount++;
+
+if (w>=storlevel)
+	{
+	storcount++;
+	if (options & (StoreFirstMessage|StoreAllMessages))
+		{
+		if (!((options&StoreFirstMessage)&&(msgs.len()>0)))
+			{
+			if (msgs.len()>0) msgs+='\n';
+			msgs+=o; msgs+="::"; msgs+=m;
+			msgs+=" - "; msgs+=bl;
+			}
+		}
+	}
+}
Index: /cpp/gdk/errmanager.h
===================================================================
--- /cpp/gdk/errmanager.h	(revision 5)
+++ /cpp/gdk/errmanager.h	(revision 5)
@@ -0,0 +1,89 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _ERRMANAGER_H_
+#define _ERRMANAGER_H_
+
+#include "list.h"
+#include "sstring.h"
+#include "framsg.h"
+
+class ErrorHandlerBase;
+
+class ErrorManager
+{
+friend class ErrorHandlerBase;
+SListTempl<ErrorHandlerBase*> handlers;
+void send(int level,const char *o,const char *m,const char *bl,int w);
+  public:
+int find(ErrorHandlerBase *r) {return handlers.find(r);}
+int add(ErrorHandlerBase *r);
+void remove(int i);
+void remove(ErrorHandlerBase *r);
+void removeAll();
+void send(const char *o,const char *m,const char *bl,int w)
+	{send(handlers.size()-1,o,m,bl,w);}
+~ErrorManager() {removeAll();}
+};
+
+extern ErrorManager globalErrorManager;
+
+////////////////////////////////////////
+
+class ErrorHandlerBase
+{
+friend class ErrorManager;
+  protected:
+ErrorManager* mgr;
+int options;
+
+  public:
+
+enum HandlerOptions
+ { DontBlock=1, CannotBeBlocked=2, DontEnable=4 };
+
+void FMprintf(const char *o,const char *m,int w,const char *bl, ...);
+void send(const char *o,const char *m,const char *bl,int w);
+
+bool isEnabled() {return mgr?1:0;}
+void enable();
+void disable();
+
+ErrorHandlerBase(int opts=0):options(opts),mgr(0)
+	{if (!(options&DontEnable)) enable();}
+~ErrorHandlerBase()
+	{disable();}
+
+virtual void handle(const char *o,const char *m,const char *bl,int w) {}
+};
+
+///////////////////////////////////////////
+
+class ErrorHandler: public ErrorHandlerBase
+{
+  protected:
+int maxlevel,errcount,warncount,storlevel,storcount;
+SString msgs;
+
+  public:
+
+void reset() {maxlevel=FMLV_INFO-1; errcount=warncount=storcount=0; msgs=0;}
+
+enum Options2
+ { StoreFirstMessage=8, StoreAllMessages=16 };
+
+int getErrorCount()       {return errcount;}
+int getWarningCount()     {return warncount;}
+int getStoredCount()      {return storcount;}
+int getErrorLevel()       {return maxlevel;}
+const SString& getMessages() {return msgs;}
+
+ErrorHandler(int opts=0,int store=FMLV_ERROR):ErrorHandlerBase(opts),storlevel(store)
+	{reset();}
+
+void handle(const char *o,const char *m,const char *bl,int w);
+};
+
+#endif
+
Index: /cpp/gdk/extvalue.cpp
===================================================================
--- /cpp/gdk/extvalue.cpp	(revision 5)
+++ /cpp/gdk/extvalue.cpp	(revision 5)
@@ -0,0 +1,302 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "extvalue.h"
+#include "param.h"
+#include <math.h>
+
+SString ExtObject::toString()
+{
+if (isEmpty()) return SString("<empty object>");
+ParamInterface *p=getParamInterface();
+int tostr=p->findId("toString");
+if (tostr>=0)
+	{
+	return SString(p->getString(tostr));
+	}
+else
+	{
+	SString tmp("<");
+	tmp+=p->getName();
+	sprintf(tmp.directAppend(30)," object at %p>",object);
+	tmp.endAppend();
+	return tmp;
+	}
+}
+
+///////////////////////////////////////
+
+void ExtValue::set(const ExtValue& src)
+{
+switch(src.type)
+	{
+	case TString: sets(src.sdata()); break;
+	case TInt: seti(src.idata()); break;
+	case TDouble: setd(src.ddata()); break;
+	case TObj: seto(src.odata()); break;
+	}
+}
+
+void ExtValue::setEmpty()
+{
+switch(type)
+	{
+#ifdef EXTVALUEUNION
+	case TString: sdata().~SString(); break;
+	case TObj: odata().~ExtObject(); break;
+#else
+	case TString: delete s; break;
+	case TObj: delete o; break;
+#endif
+	}
+type=TUnknown;
+}
+
+static long longsign(long x)
+{
+if (x<0) return -1;
+if (x>0) return 1;
+return 0;
+}
+
+long ExtValue::compare(const ExtValue& src) const
+{
+if (type==TUnknown)
+	{
+	if (src.type==TDouble)
+		return (src.getDouble()!=0.0);
+	if (src.type==TString)
+		return 1;
+	return src.getInt()?1:0;
+	}
+else if (src.type==TUnknown)
+	{
+	if (type==TDouble)
+		return (getDouble()!=0.0);
+	if (type==TString)
+		return 1;
+	return getInt()?1:0;
+	}
+switch(type)
+	{
+	case TInt:
+	{
+	long t=src.getInt();
+	if (idata()>0)
+		{if (t>0) return longsign(idata()-t); else return +1;}
+	else
+		{if (t<=0) return longsign(idata()-t); else return -1;}
+	}
+	case TDouble:
+		{
+		double t=ddata()-src.getDouble();
+		if (t<0) return -1;
+		else if (t>0) return 1;
+		return 0;
+		}
+	case TString:
+	{
+	SString t=src.getString();
+	SString& t2=sdata();
+	const char* s1=(const char*)t2;
+	const char* s2=(const char*)t;
+	return longsign(strcmp(s1,s2));
+	}
+	case TObj: 
+	{
+	if (src.type==TObj)
+		return !(odata()==src.odata());
+	return 1;
+	}
+	}
+return 1;
+}
+
+int ExtValue::operator==(const ExtValue& src) const
+{
+if (type!=src.type) return 0;
+switch(type)
+	{
+	case TInt: return idata()==src.idata();
+	case TDouble: return ddata()==src.ddata();
+	case TString: return sdata()==src.sdata();
+	case TObj: return odata()==src.odata();
+	}
+return 1;
+}
+
+void ExtValue::operator+=(const ExtValue& src)
+{
+switch(type)
+	{
+	case TInt: idata()+=src.getInt(); break;
+	case TDouble: ddata()+=src.getDouble(); break;
+	case TString: sdata()+=src.getString(); break;
+	}
+}
+
+void ExtValue::operator-=(const ExtValue& src)
+{
+switch(type)
+	{
+	case TInt: idata()-=src.getInt(); break;
+	case TDouble: ddata()-=src.getDouble(); break;
+	}
+}
+
+void ExtValue::operator*=(const ExtValue& src)
+{
+switch(type)
+	{
+	case TInt: idata()*=src.getInt(); break;
+	case TDouble: ddata()*=src.getDouble(); break;
+	}
+}
+
+#include "framsg.h"
+/*#include "fpu_control.h"
+#include <signal.h>
+
+static int fpuexception;
+void mathhandler(int sig)
+{
+printf("fpu exception!\n");
+fpuexception=1;
+signal(SIGFPE,SIG_IGN);
+} */
+
+void ExtValue::operator/=(const ExtValue& src)
+{
+switch(type)
+	{
+	case TInt:
+	{ int a=src.getInt();
+//		idata()/=src.getInt();
+	if (a) idata()/=a;
+	else FMprintf("ExtValue","divide",FMLV_ERROR,"%s/0",(const char*)getString());
+	}
+		break;
+
+	case TDouble:
+// ugly ;-(
+#ifdef FPU_THROWS_EXCEPTIONS
+		try
+			{
+			ddata()/=src.getDouble();
+			}
+		catch(...)
+			{
+			FMprintf("ExtValue","divide",FMLV_ERROR,"%s/0.0",(const char*)getString());
+			}
+#else
+		{
+		double d=ddata();
+		d/=src.getDouble();
+		if (finite(d))
+			ddata()=d;
+		else
+			FMprintf("ExtValue","divide",FMLV_ERROR,"%s/0.0",(const char*)getString());
+		}
+#endif
+		break;
+	}
+}
+
+void ExtValue::operator%=(const ExtValue& src)
+{
+switch(type)
+	{
+	case TInt: idata()=idata()%src.getInt(); break;
+	case TDouble: ddata()=fmod(ddata(),src.getDouble()); break;
+	}
+}
+
+long ExtValue::getInt() const
+{
+switch(type)
+	{
+	case TInt: return idata();
+	case TDouble: return (int)ddata();
+	case TString:
+	{
+	const char* s=(const char*)sdata();
+	if ((s[0]=='0')&&(s[1]=='x'))
+		{
+		long val;
+		sscanf(s+2,"%lx",&val);
+		return val;
+		}
+	else
+		{
+		if (strchr(s,'e')||(strchr(s,'E')))
+			return atof(s);
+		else
+			return atol(s);
+		}
+	}
+	case TObj: return (long)odata().param;
+	}
+return 0;
+}
+double ExtValue::getDouble() const
+{
+switch(type)
+	{
+	case TDouble: return ddata();
+	case TInt: return (double)idata();
+	case TString:
+	{
+	const char* s=(const char*)sdata();
+	if ((s[0]=='0')&&(s[1]=='x'))
+		{
+		long val;
+		sscanf(s+2,"%lx",&val);
+		return val;
+		}
+	else
+		return atof(s);
+	}
+	case TObj: return (double)(long)odata().param;
+	}
+return 0.0;
+}
+SString ExtValue::getString() const
+{
+switch(type)
+	{
+	case TString: return sdata();
+	case TInt:
+		{
+		SString tmp;
+		sprintf(tmp.directAppend(20),"%d",idata());
+		tmp.endAppend();
+		return tmp;
+		}
+	case TDouble:
+		{
+		SString tmp;
+		sprintf(tmp.directAppend(20),"%g",ddata());
+		tmp.endAppend();
+		if ((!strchr(tmp,'.'))&&(!strchr(tmp,'e'))) tmp+=".0";
+		return tmp;
+		}
+	case TObj:
+		return odata().toString();
+	default:
+		return SString("null");
+	}
+}
+
+ExtObject ExtValue::getObject() const
+{
+if (type==TObj) return odata();
+return ExtObject();
+}
+
+ExtValue ExtValue::getExtType()
+{
+if (getType()!=TObj) return ExtValue((long)getType());
+ExtObject& o=odata();
+return ExtValue(SString(o.isEmpty()?"":o.getParamInterface()->getName()));
+}
Index: /cpp/gdk/extvalue.h
===================================================================
--- /cpp/gdk/extvalue.h	(revision 5)
+++ /cpp/gdk/extvalue.h	(revision 5)
@@ -0,0 +1,151 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _EXTVALUE_H_
+#define _EXTVALUE_H_
+
+#include "sstring.h"
+#include "param.h"
+
+#define EXTVALUEUNION
+#define EXTVALUEUNIONSIZE sizeof(SString)
+
+enum ExtPType
+{TUnknown=0,TInt,TDouble,TString,TObj};
+
+/**
+   destructable object
+ */
+class DestrBase
+{
+public:
+int refcount;
+DestrBase():refcount(0) {}
+virtual ~DestrBase() {}
+};
+
+/**
+   object reference.
+ */
+class ExtObject
+{
+int subtype;                    //< 0/1=Generic/DPC Object,  0/2=Standalone/Shared Param
+void incref() const {if (subtype&1) dbobject->refcount++;}
+void decref() const {if (subtype&1) if (!--dbobject->refcount) delete dbobject;}
+  public:
+union { void* object;           //< generic object, will use param
+DestrBase *dbobject;};  //< object with refcounting, will be deleted if refcount goes to 0
+union { Param* param;           //< if object!=0
+	ParamInterface *paraminterface;}; //< if object==0
+
+void copyFrom(const ExtObject& src)  {subtype=src.subtype;object=src.object;param=src.param;}
+
+void* operator new(size_t s, void* mem) {return mem;}
+#ifdef _MSC_VER
+void operator delete(void* mem,void* t) {}
+#endif
+void* operator new(size_t s) {return malloc(sizeof(ExtObject));}
+void operator delete(void* mem) {free(mem);}
+
+ParamInterface *getParamInterface() const  {if(subtype&2){param->select(object);return param;} return paraminterface;}
+const char* interfaceName() const {if (isEmpty()) return "Empty"; return getParamInterface()->getName();}
+void* getTarget() const {return (subtype&1)?dbobject:object;}
+void* getTarget(const char* classname) const {return strcmp(interfaceName(),classname)?0:getTarget();}
+int isEmpty() const {return !param;}
+ExtObject(const ExtObject& src)      {src.incref();copyFrom(src);}
+void operator=(const ExtObject& src) {src.incref();decref();copyFrom(src);}
+
+int operator==(const ExtObject& src) {if (object!=src.object) return 0; return (object==0)?(param==src.param):1;}
+
+SString toString();
+
+ExtObject(Param *p,void *o):subtype(2),object(o),param(p){}
+ExtObject(ParamInterface *p=0):subtype(0),object(0),paraminterface(p){}
+ExtObject(Param *p,DestrBase *o):subtype(1+2),dbobject(o),param(p){incref();}
+ExtObject(ParamInterface *p,DestrBase *o):subtype(1),dbobject(o),paraminterface(p){incref();}
+
+~ExtObject(){decref();}
+};
+
+
+class ExtValue
+{
+public:
+ExtPType type;
+#ifdef EXTVALUEUNION
+long data[(EXTVALUEUNIONSIZE+sizeof(long)-1)/sizeof(long)];
+long& idata() const {return (long&)data[0];};
+double& ddata() const {return *(double*)data;};
+ExtObject& odata() const {return *(ExtObject*)data;};
+SString& sdata() const {return *(SString*)data;};
+#else
+union {
+long i;
+double d;
+SString *s;
+ExtObject *o;
+};
+long& idata() const {return (long&)i;};
+double& ddata() const {return (double&)d;};
+ExtObject& odata() const {return *o;};
+SString& sdata() const {return *s;};
+#endif
+
+void* operator new(size_t s, void* mem) {return mem;}
+void* operator new(size_t s) {return ::operator new(s);}
+
+ExtValue():type(TUnknown){}
+~ExtValue() {setEmpty();}
+ExtValue(long v) {seti(v);}
+ExtValue(double v) {setd(v);}
+ExtValue(const SString &v) {sets(v);}
+ExtValue(const ExtObject &srco) {seto(srco);}
+long compare(const ExtValue& src) const;
+int operator==(const ExtValue& src) const;
+void operator+=(const ExtValue& src);
+void operator-=(const ExtValue& src);
+void operator*=(const ExtValue& src);
+void operator/=(const ExtValue& src);
+void operator%=(const ExtValue& src);
+void operator=(const ExtValue& src)
+	{setr(src);}
+ExtValue(const ExtValue& src)
+	:type(TUnknown) {set(src);}
+void setEmpty();
+ExtPType getType() {return type;}
+void *getObjectTarget(const char* classname) {return (type==TObj)?getObject().getTarget(classname):0;}
+void setInt(long v) {if (type!=TInt) setri(v); else idata()=v;}
+void setDouble(double v) {if (type!=TDouble) setrd(v); else ddata()=v;}
+void setString(const SString &v) {if (type!=TString) setrs(v); else sdata()=v;}
+void setObject(const ExtObject &src) {if (type!=TObj) setro(src); else odata()=src;}
+long getInt() const;
+double getDouble() const;
+SString getString() const;
+ExtObject getObject() const;
+
+ExtValue getExtType();
+
+  private: // setrx - release and set, setx - assume released
+void setr(const ExtValue& src){setEmpty();set(src);}
+void set(const ExtValue& src);
+void setri(long v) {setEmpty();seti(v);}
+void setrd(double v) {setEmpty();setd(v);}
+void seti(long v) {type=TInt;idata()=v;}
+void setd(double v) {type=TDouble;ddata()=v;}
+#ifdef EXTVALUEUNION
+void setrs(const SString &v) {setEmpty();sets(v);}
+void setro(const ExtObject &src) {setEmpty();seto(src);}
+void sets(const SString &v) {type=TString;new(data) SString(v);}
+void seto(const ExtObject &src) {type=TObj;new(data) ExtObject(src);}
+#else
+void setrs(const SString &v) {setEmpty();sets(v);}
+void setro(const ExtObject &src) {setEmpty();seto(src);}
+void sets(const SString &v) {type=TString;s=new SString(v);}
+void seto(const ExtObject &src) {type=TObj;o=new ExtObject(src);}
+#endif
+
+};
+
+
+#endif
Index: /cpp/gdk/f0-modeldef.m4
===================================================================
--- /cpp/gdk/f0-modeldef.m4	(revision 5)
+++ /cpp/gdk/f0-modeldef.m4	(revision 5)
@@ -0,0 +1,34 @@
+divert(-1)
+
+define(`Invisible',1)
+define(`DontShowClass',`2')
+define(`AtFirstPart',`4')
+define(`AtSecondPart',`8')
+define(`InTheMiddle',`12')
+define(`MuscleClass',`16')
+define(`ReceptorClass',`32')
+define(`V1BendMuscle',`64')
+define(`V1RotMuscle',`128')
+
+define(`CLASS',`ifelse($4,NOXML,`divert(-1)',`class:id=$3,name="$1"') define(`groupcounter',0)')
+define(`XPROP',ZPROP(X,$@))
+define(`PROP',ZPROP(-,$@))
+define(`ZPROP',`prop:id=$2,ifelse($1,X,`xtra=1,')name="$5",group="groupname_$3",flags=$4,type="$6 $7 $8 $9"')
+#define(`GROUP',`g:name="$1" define(`groupname_'groupcounter,$1)define(`groupcounter',m4_eval(groupcounter+1))')
+define(`GROUP',`define(`groupname_'groupcounter,$1)define(`groupcounter',eval(groupcounter+1))')
+define(`ENDCLASS',`divert')
+
+define(`NEUROCLASS',`neuro: id=$2,name="$3",info="$4",inputs=$5,output=$6,location=$7 divert(2)')
+define(`VISUALHINTS',`divert `,vhints'=eval($1) divert(2)')
+define(`SYMBOL',`divert ,symbol="$1" divert(2)')
+define(`NEUROPROP',`prop:id=$1,name="$4",type="$5 $6 $7 $8"')
+define(`ENDNEUROCLASS',`divert`'undivert(2)')
+
+changecom
+divert
+# f0 definition for Framsticks
+class:id=m,name="Model"
+prop:id=se,name="starting energy",group="x",flags=1024,type="f -999999 999999 0 "
+divert(1)
+# EOF
+divert
Index: /cpp/gdk/f0.def
===================================================================
--- /cpp/gdk/f0.def	(revision 5)
+++ /cpp/gdk/f0.def	(revision 5)
@@ -0,0 +1,172 @@
+CLASS(Part,f0_part,p)
+GROUP(Geometry)
+GROUP(Other properties)
+GROUP(Visual)
+PROP(x,0,1024,position.x,f,,,,p.x)
+PROP(y,0,1024,position.y,f,,,,p.y)
+PROP(z,0,1024,position.z,f,,,,p.z)
+XPROP(m,1,0,mass,f,0.1,999.0,1.0,mass)
+PROP(s,1,0,size,f,0.1,10.0,1.0,size)
+XPROP(dn,1,0,density,f,0.2,5.0,1.0,density)
+XPROP(fr,1,0,friction,f,0.0,4.0,0.4,friction)
+XPROP(ing,1,0,ingestion,f,0.0,1.0,0.25,ingest)
+XPROP(as,1,0,assimilation,f,0.0,1.0,0.25,assim)
+PROP(rx,0,0,rot.x,f,,,,rot.x)
+PROP(ry,0,1024,rot.y,f,,,,rot.y)
+PROP(rz,0,1024,rot.z,f,,,,rot.z)
+PROP(i,1,0,`info',s,,,,info)
+PROP(Vstyle,2,0,vis_style,s,0,-1,part,vis_style)
+ENDCLASS
+
+CLASS(Joint,f0_joint,j)
+GROUP(Connections)
+GROUP(Geometry)
+GROUP(Other properties)
+GROUP(Visual)
+PROP(p1,0,1024,`part1 ref#',d,-1,999999,-1,p1_refno)
+PROP(p2,0,1024,`part2 ref#',d,-1,999999,-1,p2_refno)
+PROP(rx,1,0,rotation.x,f,,,,rot.x)
+PROP(ry,1,1024,rotation.y,f,,,,rot.y)
+PROP(rz,1,1024,rotation.z,f,,,,rot.z)
+PROP(dx,1,0,delta.x,f,-2,2,0,d.x)
+PROP(dy,1,1024,delta.y,f,-2,2,0,d.y)
+PROP(dz,1,1024,delta.z,f,-2,2,0,d.z)
+XPROP(stif,2,0,stiffness,f,0.0,1.0,1.0,stif)
+XPROP(rotstif,2,0,rotation stiffness,f,0.0,1.0,1.0,rotstif)
+PROP(stam,2,0,stamina,f,0.0,1.0,0.25,stamina)
+PROP(i,2,0,`info',s,,,,info)
+PROP(Vstyle,3,0,vis_style,s,0,-1,joint,vis_style)
+ENDCLASS
+
+CLASS(Joint,f0_nodeltajoint,j,NOXML)
+GROUP(Connections)
+GROUP(Geometry)
+GROUP(Other properties)
+GROUP(Visual)
+PROP(p1,0,1024,`part1 ref#',d,-1,999999,-1,p1_refno)
+PROP(p2,0,1024,`part2 ref#',d,-1,999999,-1,p2_refno)
+XPROP(stif,2,0,stiffness,f,0.0,1.0,1.0,stif)
+XPROP(rotstif,2,0,rotation stiffness,f,0.0,1.0,1.0,rotstif)
+PROP(stam,2,0,stamina,f,0.0,1.0,0.25,stamina)
+PROP(i,2,0,`info',s,,,,info)
+PROP(Vstyle,3,0,vis_style,s,0,-1,joint,vis_style)
+ENDCLASS
+
+CLASS(Neuro,f0_neuro,n)
+GROUP(Connections)
+GROUP(Other)
+GROUP(Visual)
+PROP(p,0,0,`part ref#',d,-1,999999,-1,part_refno)
+PROP(j,0,0,`joint ref#',d,-1,999999,-1,joint_refno)
+PROP(d,1,0,item details,s,,,,details,GETSET)
+PROP(i,1,0,`info',s,,,,info)
+PROP(Vstyle,2,0,vis_style,s,0,-1,neuro,vis_style)
+PROP(getInputCount,0,1+2,`input count',d,,,,inputCount,GETONLY)
+PROP(getInputNeuroDef,0,1+2,`get input neuron',p oNeuroDef(d),,,,p_getInputNeuroDef,PROCEDURE)
+PROP(getInputNeuroIndex,0,1+2,`get input neuron index',p d(d),,,,p_getInputNeuroIndex,PROCEDURE)
+PROP(getInputWeight,0,1+2,`get input weight',p f(d),,,,p_getInputWeight,PROCEDURE)
+ENDCLASS
+
+CLASS(NeuroConn,f0_neuroconn,c)
+GROUP(Connection)
+GROUP(Other)
+PROP(n1,0,1024,`this neuro ref#',d,-1,999999,-1,n1_refno)
+PROP(n2,0,1024,`connected neuro ref#',d,-1,999999,-1,n2_refno)
+PROP(w,0,1024,weight,f,-999999,999999,1.0,weight)
+PROP(i,1,0,`info',s,,,,info)
+ENDCLASS
+
+NEUROCLASS(StdNeuron,N,Neuron,`Standard neuron',-1,1,0)
+VISUALHINTS(DontShowClass)
+NEUROPROP(in,1,0,Inertia,f,0.0,1.0,0.8,inertia)
+NEUROPROP(fo,1,0,Force,f,0.0,999.0,0.04,force)
+NEUROPROP(si,1,0,Sigmoid,f,-99999.0,99999.0,2.0,sigmo)
+NEUROPROP(s,2,0,State,f,-1.0,1.0,0.0,newstate)
+ENDNEUROCLASS
+
+NEUROCLASS(StdUNeuron,Nu,`Unipolar neuron [EXPERIMENTAL!]',`Works like standard neuron (N) but the output value is scaled to 0...+1 instead of -1...+1.\nHaving 0 as one of the saturation states should help in \"gate circuits\", where input signal is passed through or blocked depending on the other singal.',-1,1,0)
+NEUROPROP(in,1,0,Inertia,f,0.0,1.0,0.8,inertia)
+NEUROPROP(fo,1,0,Force,f,0.0,999.0,0.04,force)
+NEUROPROP(si,1,0,Sigmoid,f,-99999.0,99999.0,2.0,sigmo)
+NEUROPROP(s,2,0,State,f,-1.0,1.0,0.0,newstate)
+ENDNEUROCLASS
+
+NEUROCLASS(Gyro,G,Gyroscope,`Equilibrium sensor.\n0=the stick is horizontal\n+1/-1=the stick is vertical',0,1,2)
+VISUALHINTS(ReceptorClass)
+SYMBOL(`8,7,100,50,90,50,90,40,70,40,80,50,70,60,90,60,90,50,12,43,24,48,24,48,19,38,19,38,24,43,24,43,54,48,54,48,64,43,69,38,64,38,54,43,54,5,63,69,58,74,48,79,38,79,28,74,23,69,1,43,79,43,74,1,23,69,26,66,1,63,69,60,66,1,55,76,53,73,1,31,75,33,72')
+ENDNEUROCLASS
+
+NEUROCLASS(Touch,T,Touch,`Touch sensor.\n-1=no contact\n0=just touching\n>0=pressing, value depends on the force applied',0,1,1)
+VISUALHINTS(ReceptorClass)
+SYMBOL(`2,7,100,50,90,50,90,40,70,40,80,50,70,60,90,60,90,50,11,75,50,65,50,60,55,55,45,50,55,45,45,40,50,35,50,30,45,25,50,30,55,35,50')
+ENDNEUROCLASS
+
+NEUROCLASS(Smell,S,Smell,`Smell sensor. Aggregated \"smell of energy\" experienced from all energy objects (creatures and food pieces).\nClose objects have bigger influence than the distant ones: for each energy source, its partial feeling is proportional to its energy/(distance^2)',0,1,1)
+VISUALHINTS(ReceptorClass)
+SYMBOL(`5,7,100,50,90,50,90,40,70,40,80,50,70,60,90,60,90,50,3,10,40,15,45,15,55,10,60,5,20,30,25,35,30,45,30,55,25,65,20,70,4,15,35,20,40,22,50,20,60,15,65,5,75,50,50,50,45,45,40,50,45,55,50,50')
+ENDNEUROCLASS
+
+NEUROCLASS(Const,*,Constant,Constant value,0,1,0)
+VISUALHINTS(Invisible)
+SYMBOL(`3,6,100,50,90,50,90,40,70,40,70,60,90,60,90,50,1,85,50,75,50,1,80,45,80,55')
+ENDNEUROCLASS
+
+NEUROCLASS(BendMuscle,|,Bend muscle,,1,0,2)
+VISUALHINTS(DontShowClass+MuscleClass+V1BendMuscle+AtFirstPart)
+SYMBOL(`6,5,25,40,35,40,45,50,35,60,25,60,25,40,4,65,85,65,50,75,50,75,85,65,85,3,65,56,49,29,57,24,72,50,4,68,53,70,53,70,55,68,55,68,53,5,50,21,60,15,70,14,79,15,87,20,81,10,1,86,20,77,21')
+NEUROPROP(p,0,0,power,f,0.01,1.0,0.25,power)
+NEUROPROP(r,0,0,bending range,f,0.0,1.0,1.0,bendrange)
+ENDNEUROCLASS
+
+NEUROCLASS(RotMuscle,@,Rotation muscle,,1,0,2)
+VISUALHINTS(DontShowClass+MuscleClass+V1RotMuscle+AtFirstPart)
+SYMBOL(`5,5,25,40,35,40,45,50,35,60,25,60,25,40,4,65,85,65,50,75,50,75,85,65,85,1,69,10,77,17,10,59,15,57,17,57,22,60,26,69,27,78,26,82,21,82,16,79,12,69,10,80,6,3,65,50,65,20,75,20,75,50')
+NEUROPROP(p,0,0,power,f,0.01,1.0,1.0,power)
+ENDNEUROCLASS
+
+NEUROCLASS(Diff,D,Differentiate,Calculate the difference between the current and previous input value. Multiple inputs are aggregated with respect to their weights,-1,1,0)
+ENDNEUROCLASS
+
+NEUROCLASS(FuzzyNeuro,Fuzzy,Fuzzy system [EXPERIMENTAL!],Refer to publications to learn about this neuron,-1,1,0)
+SYMBOL(`5,2,30,65,37,37,44,65,3,37,65,44,37,51,37,58,65,2,51,65,58,37,65,65,6,100,50,70,50,70,25,25,10,25,90,70,75,70,50,1,70,65,25,65')
+NEUROPROP(ns,0,0,number of fuzzy sets,d,1,,,fuzzySetsNr)
+NEUROPROP(nr,0,0,number of rules,d,1,,,rulesNr)
+NEUROPROP(fs,0,0,fuzzy sets,s,0,-1,0,fuzzySetString)
+NEUROPROP(fr,0,0,fuzzy rules,s,0,-1,0,fuzzyRulesString)
+ENDNEUROCLASS
+
+NEUROCLASS(Sticky,Sti,Sticky [EXPERIMENTAL!],,1,0,1)
+VISUALHINTS(ReceptorClass)
+ENDNEUROCLASS
+
+NEUROCLASS(LinearMuscle,LMu,Linear muscle [EXPERIMENTAL!],,1,0,2)
+VISUALHINTS(MuscleClass)
+NEUROPROP(p,0,0,power,f,0.01,1.0,1.0,power)
+ENDNEUROCLASS
+
+NEUROCLASS(WaterDetect,Water,Water detector,`Output signal:\n0=on or above water surface\n1=under water (deeper than 1)\n0..1=in the transient area just below water surface',0,1,1)
+VISUALHINTS(ReceptorClass)
+ENDNEUROCLASS
+
+NEUROCLASS(Energy,Energy,Energy level,`The current energy level divided by the initial energy level.\nUsually falls from initial 1.0 down to 0.0 and then the creature dies. It can rise above 1.0 if enough food is ingested',0,1,0)
+VISUALHINTS(ReceptorClass)
+ENDNEUROCLASS
+
+NEUROCLASS(Channelize,Ch,Channelize,`Combines all input signals into a single multichannel output; Note: ChSel and ChMux are the only neurons which support multiple channels. Other neurons discard everything except the first channel.',-1,1,0)
+ENDNEUROCLASS
+
+NEUROCLASS(ChMux,ChMux,Channel multiplexer,`Outputs the selected channel from the second (multichannel) input. The first input is used as the selector value (-1=select first channel, .., 1=last channel)',2,1,0)
+ENDNEUROCLASS
+
+NEUROCLASS(ChSel,ChSel,Channel selector,`Outputs a single channel (selected by the \"ch\" parameter) from multichannel input',1,1,0)
+NEUROPROP(ch,0,0,channel,d,,,,ch)
+ENDNEUROCLASS
+
+NEUROCLASS(Random,Rnd,Random noise,`Generates random noise (subsequent random values in the range of -1..+1)',0,1,0)
+ENDNEUROCLASS
+
+NEUROCLASS(Sinus,Sin,Sinus generator,`Output frequency = f0+input',1,1,0)
+SYMBOL(`3,12,75,50,71,37,62,28,50,25,37,28,28,37,25,50,28,62,37,71,50,75,62,71,71,62,75,50,1,75,50,100,50,5,35,50,40,35,45,35,55,65,60,65,65,50')
+NEUROPROP(f0,0,0,base frequency,f,-1.0,1.0,0.06283185307,f0)
+NEUROPROP(t,0,0,time,f,0,6.283185307,0,t)
+ENDNEUROCLASS
Index: /cpp/gdk/f0classes.h
===================================================================
--- /cpp/gdk/f0classes.h	(revision 5)
+++ /cpp/gdk/f0classes.h	(revision 5)
@@ -0,0 +1,160 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+
+#define FIELDSTRUCT Part
+ParamEntry f0_part_paramtab[]=
+{
+ {"Geometry",3,14,"p" },
+ {"Other properties",},
+ {"Visual",},
+ {"x",0,1024,"position.x","f",FIELD(p.x),},
+ {"y",0,1024,"position.y","f",FIELD(p.y),},
+ {"z",0,1024,"position.z","f",FIELD(p.z),},
+ {"m",1,0,"mass","f 0.1 999.0 1.0",FIELD(mass),},
+ {"s",1,0,"size","f 0.1 10.0 1.0",FIELD(size),},
+ {"dn",1,0,"density","f 0.2 5.0 1.0",FIELD(density),},
+ {"fr",1,0,"friction","f 0.0 4.0 0.4",FIELD(friction),},
+ {"ing",1,0,"ingestion","f 0.0 1.0 0.25",FIELD(ingest),},
+ {"as",1,0,"assimilation","f 0.0 1.0 0.25",FIELD(assim),},
+ {"rx",0,0,"rot.x","f",FIELD(rot.x),},
+ {"ry",0,1024,"rot.y","f",FIELD(rot.y),},
+ {"rz",0,1024,"rot.z","f",FIELD(rot.z),},
+ {"i",1,0,"info","s",FIELD(info),},
+ {"Vstyle",2,0,"vis_style","s 0 -1 part",FIELD(vis_style),},
+ {0,0,0,}
+};
+ParamEntry f0_part_xtra_paramtab[]=
+{
+ {"Extra properties",1,5,"p"},
+ {"m",0,0,"mass","f 0.1 999.0 1.0",FIELD(mass),},
+ {"dn",0,0,"density","f 0.2 5.0 1.0",FIELD(density),},
+ {"fr",0,0,"friction","f 0.0 4.0 0.4",FIELD(friction),},
+ {"ing",0,0,"ingestion","f 0.0 1.0 0.25",FIELD(ingest),},
+ {"as",0,0,"assimilation","f 0.0 1.0 0.25",FIELD(assim),},
+ {0,0,0,}
+};
+#undef FIELDSTRUCT
+
+
+#define FIELDSTRUCT Joint
+ParamEntry f0_joint_paramtab[]=
+{
+ {"Connections",4,13,"j" },
+ {"Geometry",},
+ {"Other properties",},
+ {"Visual",},
+ {"p1",0,1024,"part1 ref#","d -1 999999 -1",FIELD(p1_refno),},
+ {"p2",0,1024,"part2 ref#","d -1 999999 -1",FIELD(p2_refno),},
+ {"rx",1,0,"rotation.x","f",FIELD(rot.x),},
+ {"ry",1,1024,"rotation.y","f",FIELD(rot.y),},
+ {"rz",1,1024,"rotation.z","f",FIELD(rot.z),},
+ {"dx",1,0,"delta.x","f -2 2 0",FIELD(d.x),},
+ {"dy",1,1024,"delta.y","f -2 2 0",FIELD(d.y),},
+ {"dz",1,1024,"delta.z","f -2 2 0",FIELD(d.z),},
+ {"stif",2,0,"stiffness","f 0.0 1.0 1.0",FIELD(stif),},
+ {"rotstif",2,0,"rotation stiffness","f 0.0 1.0 1.0",FIELD(rotstif),},
+ {"stam",2,0,"stamina","f 0.0 1.0 0.25",FIELD(stamina),},
+ {"i",2,0,"info","s",FIELD(info),},
+ {"Vstyle",3,0,"vis_style","s 0 -1 joint",FIELD(vis_style),},
+ {0,0,0,}
+};
+ParamEntry f0_joint_xtra_paramtab[]=
+{
+ {"Extra properties",1,2,"j"},
+ {"stif",0,0,"stiffness","f 0.0 1.0 1.0",FIELD(stif),},
+ {"rotstif",0,0,"rotation stiffness","f 0.0 1.0 1.0",FIELD(rotstif),},
+ {0,0,0,}
+};
+#undef FIELDSTRUCT
+
+
+#define FIELDSTRUCT Joint
+ParamEntry f0_nodeltajoint_paramtab[]=
+{
+ {"Connections",4,7,"j" },
+ {"Geometry",},
+ {"Other properties",},
+ {"Visual",},
+ {"p1",0,1024,"part1 ref#","d -1 999999 -1",FIELD(p1_refno),},
+ {"p2",0,1024,"part2 ref#","d -1 999999 -1",FIELD(p2_refno),},
+ {"stif",2,0,"stiffness","f 0.0 1.0 1.0",FIELD(stif),},
+ {"rotstif",2,0,"rotation stiffness","f 0.0 1.0 1.0",FIELD(rotstif),},
+ {"stam",2,0,"stamina","f 0.0 1.0 0.25",FIELD(stamina),},
+ {"i",2,0,"info","s",FIELD(info),},
+ {"Vstyle",3,0,"vis_style","s 0 -1 joint",FIELD(vis_style),},
+ {0,0,0,}
+};
+ParamEntry f0_nodeltajoint_xtra_paramtab[]=
+{
+ {"Extra properties",1,2,"j"},
+ {"stif",0,0,"stiffness","f 0.0 1.0 1.0",FIELD(stif),},
+ {"rotstif",0,0,"rotation stiffness","f 0.0 1.0 1.0",FIELD(rotstif),},
+ {0,0,0,}
+};
+#undef FIELDSTRUCT
+
+
+#define FIELDSTRUCT Neuro
+ParamEntry f0_neuro_paramtab[]=
+{
+ {"Connections",3,9,"n" },
+ {"Other",},
+ {"Visual",},
+ {"p",0,0,"part ref#","d -1 999999 -1",FIELD(part_refno),},
+ {"j",0,0,"joint ref#","d -1 999999 -1",FIELD(joint_refno),},
+ {"d",1,0,"item details","s",GETSET(details),},
+ {"i",1,0,"info","s",FIELD(info),},
+ {"Vstyle",2,0,"vis_style","s 0 -1 neuro",FIELD(vis_style),},
+ {"getInputCount",0,1+2,"input count","d",GETONLY(inputCount),},
+ {"getInputNeuroDef",0,1+2,"get input neuron","p oNeuroDef(d)",PROCEDURE(p_getInputNeuroDef),},
+ {"getInputNeuroIndex",0,1+2,"get input neuron index","p d(d)",PROCEDURE(p_getInputNeuroIndex),},
+ {"getInputWeight",0,1+2,"get input weight","p f(d)",PROCEDURE(p_getInputWeight),},
+ {0,0,0,}
+};
+ParamEntry f0_neuro_xtra_paramtab[]=
+{
+ {"Extra properties",1,0,"n"},
+ {0,0,0,}
+};
+#undef FIELDSTRUCT
+
+
+#define FIELDSTRUCT NeuroConn
+ParamEntry f0_neuroconn_paramtab[]=
+{
+ {"Connection",2,4,"c" },
+ {"Other",},
+ {"n1",0,1024,"this neuro ref#","d -1 999999 -1",FIELD(n1_refno),},
+ {"n2",0,1024,"connected neuro ref#","d -1 999999 -1",FIELD(n2_refno),},
+ {"w",0,1024,"weight","f -999999 999999 1.0",FIELD(weight),},
+ {"i",1,0,"info","s",FIELD(info),},
+ {0,0,0,}
+};
+ParamEntry f0_neuroconn_xtra_paramtab[]=
+{
+ {"Extra properties",1,0,"c"},
+ {0,0,0,}
+};
+#undef FIELDSTRUCT
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: /cpp/gdk/f0classes.m4
===================================================================
--- /cpp/gdk/f0classes.m4	(revision 5)
+++ /cpp/gdk/f0classes.m4	(revision 5)
@@ -0,0 +1,40 @@
+divert(-1)
+
+define(`NEUROPROP',`dnl')
+define(`NEUROCLASS',`dnl')
+define(`VISUALHINTS',`dnl')
+define(`ENDNEUROCLASS',`dnl')
+define(`SYMBOL',`dnl')
+
+define(`CLASS',
+`divert`'dnl
+#define FIELDSTRUCT $1
+ParamEntry $2_paramtab[]=
+{divert(3)dnl
+"$3" dnl
+divert(5)dnl
+ParamEntry $2_xtra_paramtab[]=
+{
+ {"Extra properties",1,divert(6),"$3"},
+divert(1)dnl
+define(`numgroups',0)dnl
+define(`numprops',0)dnl
+define(`numxprops',0)dnl
+')
+define(`PROP',`divert(4)dnl
+define(`numprops',incr(numprops))dnl
+ {"$1",$2,$3,"$4",ifelse($6,,"$5","$5 $6 $7 $8"),ifelse($10,,FIELD($9),$10($9)),},')
+define(`XPROP',dnl
+`PROP($@)define(`numxprops',incr(numxprops))dnl
+divert(6) {"$1",0,$3,"$4",ifelse($6,,"$5","$5 $6 $7 $8"),ifelse($10,,FIELD($9),$10($9)),},
+divert(4)')dnl
+define(`GROUP',` {"$1",divert(3)},define(`numgroups',incr(numgroups))')
+define(`ENDCLASS',` {0,0,0,}
+};
+divert(2)numgroups,numprops,divert`'dnl
+undivert(1)undivert(2)undivert(3)undivert(4)undivert(5)numxprops`'undivert(6) {0,0,0,}
+};
+#undef FIELDSTRUCT
+')
+changecom
+divert
Index: /cpp/gdk/f0def.xml
===================================================================
--- /cpp/gdk/f0def.xml	(revision 5)
+++ /cpp/gdk/f0def.xml	(revision 5)
@@ -0,0 +1,165 @@
+<!DOCTYPE F0CLASSES>
+<F0CLASSES>
+
+ <CLASS ID="p" NAME="Part">
+  <GROUP NAME="Geometry" />
+  <GROUP NAME="Other properties" />
+  <GROUP NAME="Visual" />
+  <PROP ID="x" NAME="position.x" GROUP="0" FLAGS="1024" TYPE="f" />
+  <PROP ID="y" NAME="position.y" GROUP="0" FLAGS="1024" TYPE="f" />
+  <PROP ID="z" NAME="position.z" GROUP="0" FLAGS="1024" TYPE="f" />
+  <PROP ID="m" XTRA="1" NAME="mass" GROUP="1" FLAGS="0" TYPE="f" MIN="0.1" MAX="999.0" DEF="1.0" />
+  <PROP ID="s" NAME="size" GROUP="1" FLAGS="0" TYPE="f" MIN="0.1" MAX="10.0" DEF="1.0" />
+  <PROP ID="dn" XTRA="1" NAME="density" GROUP="1" FLAGS="0" TYPE="f" MIN="0.2" MAX="5.0" DEF="1.0" />
+  <PROP ID="fr" XTRA="1" NAME="friction" GROUP="1" FLAGS="0" TYPE="f" MIN="0.0" MAX="4.0" DEF="0.4" />
+  <PROP ID="ing" XTRA="1" NAME="ingestion" GROUP="1" FLAGS="0" TYPE="f" MIN="0.0" MAX="1.0" DEF="0.25" />
+  <PROP ID="as" XTRA="1" NAME="assimilation" GROUP="1" FLAGS="0" TYPE="f" MIN="0.0" MAX="1.0" DEF="0.25" />
+  <PROP ID="rx" NAME="rot.x" GROUP="0" FLAGS="0" TYPE="f" />
+  <PROP ID="ry" NAME="rot.y" GROUP="0" FLAGS="1024" TYPE="f" />
+  <PROP ID="rz" NAME="rot.z" GROUP="0" FLAGS="1024" TYPE="f" />
+  <PROP ID="i" NAME="info" GROUP="1" FLAGS="0" TYPE="s" />
+  <PROP ID="Vstyle" NAME="vis_style" GROUP="2" FLAGS="0" TYPE="s" MIN="0" MAX="-1" DEF="part" />
+ </CLASS>
+
+ <CLASS ID="j" NAME="Joint">
+  <GROUP NAME="Connections" />
+  <GROUP NAME="Geometry" />
+  <GROUP NAME="Other properties" />
+  <GROUP NAME="Visual" />
+  <PROP ID="p1" NAME="part1 ref#" GROUP="0" FLAGS="1024" TYPE="d" MIN="-1" MAX="999999" DEF="-1" />
+  <PROP ID="p2" NAME="part2 ref#" GROUP="0" FLAGS="1024" TYPE="d" MIN="-1" MAX="999999" DEF="-1" />
+  <PROP ID="rx" NAME="rotation.x" GROUP="1" FLAGS="0" TYPE="f" />
+  <PROP ID="ry" NAME="rotation.y" GROUP="1" FLAGS="1024" TYPE="f" />
+  <PROP ID="rz" NAME="rotation.z" GROUP="1" FLAGS="1024" TYPE="f" />
+  <PROP ID="dx" NAME="delta.x" GROUP="1" FLAGS="0" TYPE="f" MIN="-2" MAX="2" DEF="0" />
+  <PROP ID="dy" NAME="delta.y" GROUP="1" FLAGS="1024" TYPE="f" MIN="-2" MAX="2" DEF="0" />
+  <PROP ID="dz" NAME="delta.z" GROUP="1" FLAGS="1024" TYPE="f" MIN="-2" MAX="2" DEF="0" />
+  <PROP ID="stif" XTRA="1" NAME="stiffness" GROUP="2" FLAGS="0" TYPE="f" MIN="0.0" MAX="1.0" DEF="1.0" />
+  <PROP ID="rotstif" XTRA="1" NAME="rotation stiffness" GROUP="2" FLAGS="0" TYPE="f" MIN="0.0" MAX="1.0" DEF="1.0" />
+  <PROP ID="stam" NAME="stamina" GROUP="2" FLAGS="0" TYPE="f" MIN="0.0" MAX="1.0" DEF="0.25" />
+  <PROP ID="i" NAME="info" GROUP="2" FLAGS="0" TYPE="s" />
+  <PROP ID="Vstyle" NAME="vis_style" GROUP="3" FLAGS="0" TYPE="s" MIN="0" MAX="-1" DEF="joint" />
+ </CLASS>
+
+
+
+ <CLASS ID="n" NAME="Neuro">
+  <GROUP NAME="Connections" />
+  <GROUP NAME="Other" />
+  <GROUP NAME="Visual" />
+  <PROP ID="p" NAME="part ref#" GROUP="0" FLAGS="0" TYPE="d" MIN="-1" MAX="999999" DEF="-1" />
+  <PROP ID="j" NAME="joint ref#" GROUP="0" FLAGS="0" TYPE="d" MIN="-1" MAX="999999" DEF="-1" />
+  <PROP ID="d" NAME="item details" GROUP="1" FLAGS="0" TYPE="s" />
+  <PROP ID="i" NAME="info" GROUP="1" FLAGS="0" TYPE="s" />
+  <PROP ID="Vstyle" NAME="vis_style" GROUP="2" FLAGS="0" TYPE="s" MIN="0" MAX="-1" DEF="neuro" />
+  <PROP ID="getInputCount" NAME="input count" GROUP="0" FLAGS="1+2" TYPE="d" />
+  <PROP ID="getInputNeuroDef" NAME="get input neuron" GROUP="0" FLAGS="1+2" TYPE="p oNeuroDef(d)" />
+  <PROP ID="getInputNeuroIndex" NAME="get input neuron index" GROUP="0" FLAGS="1+2" TYPE="p d(d)" />
+  <PROP ID="getInputWeight" NAME="get input weight" GROUP="0" FLAGS="1+2" TYPE="p f(d)" />
+ </CLASS>
+
+ <CLASS ID="c" NAME="NeuroConn">
+  <GROUP NAME="Connection" />
+  <GROUP NAME="Other" />
+  <PROP ID="n1" NAME="this neuro ref#" GROUP="0" FLAGS="1024" TYPE="d" MIN="-1" MAX="999999" DEF="-1" />
+  <PROP ID="n2" NAME="connected neuro ref#" GROUP="0" FLAGS="1024" TYPE="d" MIN="-1" MAX="999999" DEF="-1" />
+  <PROP ID="w" NAME="weight" GROUP="0" FLAGS="1024" TYPE="f" MIN="-999999" MAX="999999" DEF="1.0" />
+  <PROP ID="i" NAME="info" GROUP="1" FLAGS="0" TYPE="s" />
+ </CLASS>
+
+ <NEUROCLASS ID="N" NAME="Neuron" DESCRIPTION="Standard neuron" INPUTS="-1" OUTPUT="1" LOCATION="0"  VISUALHINTS="2"  >
+
+  <NEUROPROP ID="in" NAME="Inertia" TYPE="f" MIN="0.0" MAX="1.0" DEF="0.8" />
+  <NEUROPROP ID="fo" NAME="Force" TYPE="f" MIN="0.0" MAX="999.0" DEF="0.04" />
+  <NEUROPROP ID="si" NAME="Sigmoid" TYPE="f" MIN="-99999.0" MAX="99999.0" DEF="2.0" />
+  <NEUROPROP ID="s" NAME="State" TYPE="f" MIN="-1.0" MAX="1.0" DEF="0.0" />
+ </NEUROCLASS>
+
+ <NEUROCLASS ID="Nu" NAME="Unipolar neuron [EXPERIMENTAL!]" DESCRIPTION="Works like standard neuron (N) but the output value is scaled to 0...+1 instead of -1...+1.\nHaving 0 as one of the saturation states should help in \"gate circuits\", where input signal is passed through or blocked depending on the other singal." INPUTS="-1" OUTPUT="1" LOCATION="0"  >
+  <NEUROPROP ID="in" NAME="Inertia" TYPE="f" MIN="0.0" MAX="1.0" DEF="0.8" />
+  <NEUROPROP ID="fo" NAME="Force" TYPE="f" MIN="0.0" MAX="999.0" DEF="0.04" />
+  <NEUROPROP ID="si" NAME="Sigmoid" TYPE="f" MIN="-99999.0" MAX="99999.0" DEF="2.0" />
+  <NEUROPROP ID="s" NAME="State" TYPE="f" MIN="-1.0" MAX="1.0" DEF="0.0" />
+ </NEUROCLASS>
+
+ <NEUROCLASS ID="G" NAME="Gyroscope" DESCRIPTION="Equilibrium sensor.\n0=the stick is horizontal\n+1/-1=the stick is vertical" INPUTS="0" OUTPUT="1" LOCATION="2"  VISUALHINTS="32"  SYMBOL="8,7,100,50,90,50,90,40,70,40,80,50,70,60,90,60,90,50,12,43,24,48,24,48,19,38,19,38,24,43,24,43,54,48,54,48,64,43,69,38,64,38,54,43,54,5,63,69,58,74,48,79,38,79,28,74,23,69,1,43,79,43,74,1,23,69,26,66,1,63,69,60,66,1,55,76,53,73,1,31,75,33,72"  >
+
+
+ </NEUROCLASS>
+
+ <NEUROCLASS ID="T" NAME="Touch" DESCRIPTION="Touch sensor.\n-1=no contact\n0=just touching\n>0=pressing, value depends on the force applied" INPUTS="0" OUTPUT="1" LOCATION="1"  VISUALHINTS="32"  SYMBOL="2,7,100,50,90,50,90,40,70,40,80,50,70,60,90,60,90,50,11,75,50,65,50,60,55,55,45,50,55,45,45,40,50,35,50,30,45,25,50,30,55,35,50"  >
+
+
+ </NEUROCLASS>
+
+ <NEUROCLASS ID="S" NAME="Smell" DESCRIPTION="Smell sensor. Aggregated \"smell of energy\" experienced from all energy objects (creatures and food pieces).\nClose objects have bigger influence than the distant ones: for each energy source, its partial feeling is proportional to its energy/(distance^2)" INPUTS="0" OUTPUT="1" LOCATION="1"  VISUALHINTS="32"  SYMBOL="5,7,100,50,90,50,90,40,70,40,80,50,70,60,90,60,90,50,3,10,40,15,45,15,55,10,60,5,20,30,25,35,30,45,30,55,25,65,20,70,4,15,35,20,40,22,50,20,60,15,65,5,75,50,50,50,45,45,40,50,45,55,50,50"  >
+
+
+ </NEUROCLASS>
+
+ <NEUROCLASS ID="*" NAME="Constant" DESCRIPTION="Constant value" INPUTS="0" OUTPUT="1" LOCATION="0"  VISUALHINTS="1"  SYMBOL="3,6,100,50,90,50,90,40,70,40,70,60,90,60,90,50,1,85,50,75,50,1,80,45,80,55"  >
+
+
+ </NEUROCLASS>
+
+ <NEUROCLASS ID="|" NAME="Bend muscle" DESCRIPTION="" INPUTS="1" OUTPUT="0" LOCATION="2"  VISUALHINTS="86"  SYMBOL="6,5,25,40,35,40,45,50,35,60,25,60,25,40,4,65,85,65,50,75,50,75,85,65,85,3,65,56,49,29,57,24,72,50,4,68,53,70,53,70,55,68,55,68,53,5,50,21,60,15,70,14,79,15,87,20,81,10,1,86,20,77,21"  >
+
+
+  <NEUROPROP ID="p" NAME="power" TYPE="f" MIN="0.01" MAX="1.0" DEF="0.25" />
+  <NEUROPROP ID="r" NAME="bending range" TYPE="f" MIN="0.0" MAX="1.0" DEF="1.0" />
+ </NEUROCLASS>
+
+ <NEUROCLASS ID="@" NAME="Rotation muscle" DESCRIPTION="" INPUTS="1" OUTPUT="0" LOCATION="2"  VISUALHINTS="150"  SYMBOL="5,5,25,40,35,40,45,50,35,60,25,60,25,40,4,65,85,65,50,75,50,75,85,65,85,1,69,10,77,17,10,59,15,57,17,57,22,60,26,69,27,78,26,82,21,82,16,79,12,69,10,80,6,3,65,50,65,20,75,20,75,50"  >
+
+
+  <NEUROPROP ID="p" NAME="power" TYPE="f" MIN="0.01" MAX="1.0" DEF="1.0" />
+ </NEUROCLASS>
+
+ <NEUROCLASS ID="D" NAME="Differentiate" DESCRIPTION="Calculate the difference between the current and previous input value. Multiple inputs are aggregated with respect to their weights" INPUTS="-1" OUTPUT="1" LOCATION="0"  >
+ </NEUROCLASS>
+
+ <NEUROCLASS ID="Fuzzy" NAME="Fuzzy system [EXPERIMENTAL!]" DESCRIPTION="Refer to publications to learn about this neuron" INPUTS="-1" OUTPUT="1" LOCATION="0"  SYMBOL="5,2,30,65,37,37,44,65,3,37,65,44,37,51,37,58,65,2,51,65,58,37,65,65,6,100,50,70,50,70,25,25,10,25,90,70,75,70,50,1,70,65,25,65"  >
+
+  <NEUROPROP ID="ns" NAME="number of fuzzy sets" TYPE="d" MIN="1" MAX="" DEF="" />
+  <NEUROPROP ID="nr" NAME="number of rules" TYPE="d" MIN="1" MAX="" DEF="" />
+  <NEUROPROP ID="fs" NAME="fuzzy sets" TYPE="s" MIN="0" MAX="-1" DEF="0" />
+  <NEUROPROP ID="fr" NAME="fuzzy rules" TYPE="s" MIN="0" MAX="-1" DEF="0" />
+ </NEUROCLASS>
+
+ <NEUROCLASS ID="Sti" NAME="Sticky [EXPERIMENTAL!]" DESCRIPTION="" INPUTS="1" OUTPUT="0" LOCATION="1"  VISUALHINTS="32"  >
+
+ </NEUROCLASS>
+
+ <NEUROCLASS ID="LMu" NAME="Linear muscle [EXPERIMENTAL!]" DESCRIPTION="" INPUTS="1" OUTPUT="0" LOCATION="2"  VISUALHINTS="16"  >
+
+  <NEUROPROP ID="p" NAME="power" TYPE="f" MIN="0.01" MAX="1.0" DEF="1.0" />
+ </NEUROCLASS>
+
+ <NEUROCLASS ID="Water" NAME="Water detector" DESCRIPTION="Output signal:\n0=on or above water surface\n1=under water (deeper than 1)\n0..1=in the transient area just below water surface" INPUTS="0" OUTPUT="1" LOCATION="1"  VISUALHINTS="32"  >
+
+ </NEUROCLASS>
+
+ <NEUROCLASS ID="Energy" NAME="Energy level" DESCRIPTION="The current energy level divided by the initial energy level.\nUsually falls from initial 1.0 down to 0.0 and then the creature dies. It can rise above 1.0 if enough food is ingested" INPUTS="0" OUTPUT="1" LOCATION="0"  VISUALHINTS="32"  >
+
+ </NEUROCLASS>
+
+ <NEUROCLASS ID="Ch" NAME="Channelize" DESCRIPTION="Combines all input signals into a single multichannel output; Note: ChSel and ChMux are the only neurons which support multiple channels. Other neurons discard everything except the first channel." INPUTS="-1" OUTPUT="1" LOCATION="0"  >
+ </NEUROCLASS>
+
+ <NEUROCLASS ID="ChMux" NAME="Channel multiplexer" DESCRIPTION="Outputs the selected channel from the second (multichannel) input. The first input is used as the selector value (-1=select first channel, .., 1=last channel)" INPUTS="2" OUTPUT="1" LOCATION="0"  >
+ </NEUROCLASS>
+
+ <NEUROCLASS ID="ChSel" NAME="Channel selector" DESCRIPTION="Outputs a single channel (selected by the \"ch\" parameter) from multichannel input" INPUTS="1" OUTPUT="1" LOCATION="0"  >
+  <NEUROPROP ID="ch" NAME="channel" TYPE="d" MIN="" MAX="" DEF="" />
+ </NEUROCLASS>
+
+ <NEUROCLASS ID="Rnd" NAME="Random noise" DESCRIPTION="Generates random noise (subsequent random values in the range of -1..+1)" INPUTS="0" OUTPUT="1" LOCATION="0"  >
+ </NEUROCLASS>
+
+ <NEUROCLASS ID="Sin" NAME="Sinus generator" DESCRIPTION="Output frequency = f0+input" INPUTS="1" OUTPUT="1" LOCATION="0"  SYMBOL="3,12,75,50,71,37,62,28,50,25,37,28,28,37,25,50,28,62,37,71,50,75,62,71,71,62,75,50,1,75,50,100,50,5,35,50,40,35,45,35,55,65,60,65,65,50"  >
+
+  <NEUROPROP ID="f0" NAME="base frequency" TYPE="f" MIN="-1.0" MAX="1.0" DEF="0.06283185307" />
+  <NEUROPROP ID="t" NAME="time" TYPE="f" MIN="0" MAX="6.283185307" DEF="0" />
+ </NEUROCLASS>
+
+</F0CLASSES>
Index: /cpp/gdk/f0defxml.m4
===================================================================
--- /cpp/gdk/f0defxml.m4	(revision 5)
+++ /cpp/gdk/f0defxml.m4	(revision 5)
@@ -0,0 +1,32 @@
+divert(-1)
+
+define(`Invisible',1)
+define(`DontShowClass',`2')
+define(`AtFirstPart',`4')
+define(`AtSecondPart',`8')
+define(`InTheMiddle',`12')
+define(`MuscleClass',`16')
+define(`ReceptorClass',`32')
+define(`V1BendMuscle',`64')
+define(`V1RotMuscle',`128')
+
+define(`CLASS',`ifelse($4,NOXML,`divert(-1)',` <`CLASS' ID="$3" NAME="$1">')')
+define(`XPROP',ZPROP(X,$@))
+define(`PROP',ZPROP(-,$@))
+define(`ZPROP',
+`  <`PROP' ID="$2" ifelse($1,X,`XTRA="1" ')NAME="$5" `GROUP'="$3" FLAGS="$4" TYPE="$6" ifelse($7,,,MIN="$7" MAX="$8" DEF="$9" )/>')
+define(`GROUP',`  <`GROUP' NAME="$1" />')
+define(`ENDCLASS',` </`CLASS'>divert')
+
+define(`NEUROCLASS',` <`NEUROCLASS' ID="$2" NAME="$3" DESCRIPTION="$4" INPUTS="$5" OUTPUT="$6" LOCATION="$7" divert(2) >')
+define(`VISUALHINTS',`divert `VISUALHINTS'="eval($1)" divert(2)')
+define(`SYMBOL',`divert `SYMBOL'="$1" divert(2)')
+define(`NEUROPROP',`  <`NEUROPROP' ID="$1" NAME="$4" TYPE="$5" MIN="$6" MAX="$7" DEF="$8" />')
+define(`ENDNEUROCLASS',`divert`'undivert(2) </`NEUROCLASS'>')
+
+changecom
+divert<!DOCTYPE F0CLASSES>
+<F0CLASSES>
+divert(1)
+</F0CLASSES>
+divert
Index: /cpp/gdk/framsg.cpp
===================================================================
--- /cpp/gdk/framsg.cpp	(revision 5)
+++ /cpp/gdk/framsg.cpp	(revision 5)
@@ -0,0 +1,24 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "nonstd.h"
+#include "framsg.h"
+#include <stdio.h>
+
+void FMprintf(const char *o,const char *m,int w,const char *bl, ...)
+{
+   char buf[10000];
+   va_list argptr;
+   va_start(argptr,bl);
+   vsnprintf(buf,10000,bl,argptr);
+   va_end(argptr);
+   FramMessage(o,m,buf,w);
+}
+
+void FMprintf(const char *o,const char *m,int w,const char *bl,va_list va)
+{
+   char buf[10000];
+   vsnprintf(buf,10000,bl,va);
+   FramMessage(o,m,buf,w);
+}
Index: /cpp/gdk/framsg.h
===================================================================
--- /cpp/gdk/framsg.h	(revision 5)
+++ /cpp/gdk/framsg.h	(revision 5)
@@ -0,0 +1,30 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _FRAMSG_H_
+#define _FRAMSG_H_
+
+#include <stdarg.h>
+
+void FMprintf(const char *o,const char *m,int w,const char *bl, ...);
+void FMprintf(const char *o,const char *m,int w,const char *bl,va_list va);
+void FramMessage(const char *o,const char *m,const char *bl,int w);
+
+#define FMLV_DEBUG -1
+#define FMLV_INFO 0
+#define FMLV_WARN 1
+#define FMLV_ERROR 2
+#define FMLV_CRITICAL 3
+
+/*
+w: weight (importance) of a message
+-1:debugging information, not needed for final users
+0: information
+1: warning or corrected error
+2: uncorrected error. can cause malfunction
+3: serious error, causes side effects. user should save what can be
+   saved and restart the application
+*/
+
+#endif
Index: /cpp/gdk/gdktest.cpp
===================================================================
--- /cpp/gdk/gdktest.cpp	(revision 5)
+++ /cpp/gdk/gdktest.cpp	(revision 5)
@@ -0,0 +1,332 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+#include "model.h"
+#include "defgenoconv.h"
+#include "stdouterr.h"
+
+/**
+ @file
+ Sample code: Accessing model elements
+*/
+
+StdoutErrorHandler err; //redirect model-related errors to stdout
+DefaultGenoConvManager gcm; //without this object the application would only handle "format 0" genotypes
+
+void printNiceBanner(const char* title)
+{
+printf("    ########################################\n"
+       "   ##                                      ##\n"
+       "  ##    %-32s    ##\n"
+       "   ##                                      ##\n"
+       "    ########################################\n",title);
+}
+void printProperties(ParamInterface &pi)
+{
+printf(" #        id                      type  name        group (%d properties)\n",pi.getPropCount());
+for (int i=0;i<pi.getPropCount();i++)
+	{
+	printf("%2d. %8s = %-20s %-3s %-10s  %-10s\n",i,pi.id(i),(const char*)pi.get(i),pi.type(i),pi.name(i),pi.grname(pi.group(i)));
+	}
+}
+
+void changeOneProperty(ParamInterface &pi)
+{
+if (pi.getPropCount()<=0) return;
+int i=rand() % pi.getPropCount();
+double maxprop=1,minprop=0,def;
+pi.getMinMax(i,minprop,maxprop,def);
+printf("      Change property #%d to random value from range [%g..%g]\n",i,minprop,maxprop);
+printf("      Current value of '%s' (%s) is '%s'\n",pi.id(i),pi.name(i),(const char*)pi.get(i));
+char t[100];
+sprintf(t,"%g",minprop+(rnd01)*(maxprop-minprop));
+printf("      Setting new value... [ using ParamInterface::set() ]\n");
+pi.set(i,t);
+printf("      The value is now '%s'\n",(const char*)pi.get(i));
+}
+
+void moreAboutPart(Part* p)
+{
+printf("Here is the full listing of properties as they are printed in f0\n"
+       " (please compare with f0 genotype).\n"
+       "Some properties have special meaning (eg. geometry and connections groups)\n"
+       "and should be handled with care, because they influence other elements of the model.\n\n"
+       " [this data is provided by Part::properties() ]\n");
+printProperties(p->properties());
+printf("\nHowever, there is a subset of properties which may be modified more freely.\n"
+       "Properties on this list are related only to this part and can be changed\n"
+       "without much consideration. They are guaranteed to be always valid; any inconsistencies\n"
+       "will be silently repaired.\n"
+       "\n [this data is provided by Part::extraProperties() ]\n");
+printProperties(p->extraProperties());
+printf("\nThis set of properties can vary from release to release,\n"
+       "but can be safely accessed by using extraProperties() call.\n"
+	   "This method accesses the full set of properies (even those\n"
+	   "which appear in future releases).\n"
+       "Now we will try to change some of properties:\n\n");
+p->getModel().open();
+changeOneProperty(p->extraProperties());
+p->getModel().close();
+printf("\nLet's see f0... (check out part #%d !)\n\n%s\n", p->refno, (const char*)p->getModel().getF0Geno().getGene());
+}
+
+void playWithAbsolute(Joint *j)
+{
+printf("\nAbsolute Joints adapt to its Parts' positions.\n"
+       "We can move a Part, and it does not influence the second part, nor the Joint.\n"
+       "Let's move the first Part along y axis by -0.1...\n");
+j->getModel().open();
+j->part1->p.y-=0.1;
+j->getModel().close();
+printf("The Part's position is changed, but everything else stays intact:\n\n%s\n",
+       (const char*)j->getModel().getF0Geno().getGene());
+}
+
+void playWithDelta(Joint *j)
+{
+printf("\nDelta fields (dx,dy,dz) describe relative location of the second part.\n"
+       "This joint will change the second Part's positions to preserve delta distance.\n"
+       "Let's move the first Part (#%d) along y axis (+0.1) and change delta.z (dz) by 0.1.\n",j->part1->refno);
+j->getModel().open();
+j->part1->p.y+=0.1;
+j->d.z+=0.1;
+j->getModel().close();
+printf("Position of the second Part referenced by this joint (part #%d) is now changed:\n\n%s\n",
+       j->part2->refno, (const char*)j->getModel().getF0Geno().getGene());
+printf("If no delta fields are defined, they will be computed automatically.\n"
+       "You can always delete existing delta values by using Joint::resetDelta().\n"
+       "Now we will change the second Part's z position by -0.2 and call resetDelta()...\n");
+j->getModel().open();
+j->part2->p.z-=0.2;
+j->resetDelta();
+j->getModel().close();
+printf("As you can see, Joint's delta fields have altered:\n\n%s\n", (const char*)j->getModel().getF0Geno().getGene());
+}
+
+void switchDelta(Joint *j)
+{
+int option=! j->isDelta();
+printf("How would this joint look like with delta option %s?\n[ by calling Joint::useDelta(%d) ]\n",option?"enabled":"disabled",option);
+j->getModel().open();
+j->useDelta( ! j->isDelta() );
+j->getModel().close();
+printf("f0 is now:\n\n%s\n...so this is %s joint.\n",
+       (const char*)j->getModel().getF0Geno().getGene(), option?"a delta":"an absolute");
+
+}
+
+void moreAboutJoint(Joint* j)
+{
+printf("Similarly as with Part, the full list of properties comes first:\n\n");
+printProperties(j->properties());
+printf("\nActually, there are two kinds of Joints: delta and absolute.\n"
+       "For this object, Joint::isDelta() returns %d, so this is the %s Joint.\n",
+       j->isDelta(),j->isDelta()?"delta":"absolute");
+if (j->isDelta())
+	{
+	playWithDelta(j);
+	switchDelta(j);
+	playWithAbsolute(j);
+	}
+else
+	{
+	playWithAbsolute(j);
+	switchDelta(j);
+	playWithDelta(j);
+	}
+
+printf("Part references and delta fields are the 'core' properties of the Joint.\n"
+       "The other properties are available from Joint::extraProperties()\n"
+       "and at the moment are defined as follows:\n\n");
+printProperties(j->extraProperties());
+printf("\nThey can be changed just like Part's extra properties:\n");
+j->getModel().open();
+changeOneProperty(j->extraProperties());
+j->getModel().close();
+printf("And after that we have this genotype:\n\n%s\n", (const char*)j->getModel().getF0Geno().getGene());
+}
+
+
+
+void moreAboutNeuro(Neuro* n)
+{
+printf("Basic features of Neuro object are similar to those of Part and Joint.\n"
+       "We can request a property list:\n\n");
+printProperties(n->properties());
+printf("\n...and extra properties (which are designed to be always valid and easy to change):\n\n");
+printProperties(n->extraProperties());
+printf("\nAs usual, we will change something:\n");
+n->getModel().open();
+changeOneProperty(n->extraProperties());
+n->getModel().close();
+printf("Each neuron can have any number of inputs = weighted connections\n with other neurons.\n"
+       "According to Neuro::getInputCount(), this one has %d inputs.\n",n->getInputCount());
+printf("Standard API is provided for accessing those inputs (getInput(int)),\n"
+       "adding inputs (addInput(Neuro*)) and removing them (removeInput(int)).\n\n");
+
+printf("\nThe most unusual thing is 'item details' field (d).\n"
+       "It is something like separate object with its own set of properties.\n"
+       "Currently the value of 'd' is '%s'.\n",(const char*)n->getDetails());
+
+{
+NeuroClass* cl=n->getClass();
+if (!cl)
+	printf("It should contain the class name but the meaning of '%s' is unknown\n",(const char*)n->getDetails());
+else
+{
+
+printf("'%s' is the class name (NeuroItem::getClassName() == '%s') and means '%s'.\n",
+       (const char*)cl->getName(),(const char*)cl->getName(),(const char*)cl->getLongName());
+printf("Neuro::getClass() gives you information about basic characteristic\n"
+       "of the class, that can be analyzed automatically.\n");
+printf("For the current object we can get know, that this object likes to have ");
+if (cl->getPreferredInputs()<0) printf("any number of inputs");
+  else if (cl->getPreferredInputs()==0) printf("no inputs");
+  else printf("%d inputs",cl->getPreferredInputs());
+printf(" (getPreferredInputs()) ");
+printf(cl->getPreferredOutput()?"and provides meaningful output signal (getPreferredOutput==1).\n":"and doesn't provide useful output signal (getPreferredOutput==0).\n");
+
+SyntParam p=n->classProperties();
+if (p.getPropCount()>0)
+	{
+	printf("The class defines its own properties:\n\n [ data provided by Neuro::classProperties() ]\n");
+	printProperties(p);
+	printf("and they can be changed:\n");
+	n->getModel().open();
+	changeOneProperty(p);
+	p.update();
+	n->getModel().close();
+	printf("After that, 'item details' contains the new object: '%s'.\n",(const char*)n->getDetails());
+	}
+else
+	printf("(This class does not have its own properties\n"
+	       " - Neuro::classProperties().getPropCount()==0)\n");
+}
+}
+
+printf("The class of this object can be changed using Neuro::setClassName()\n"
+       "The following classes are available:\n"
+       " [ data provided by Neuro::getClassInfo()->getProperties() ]\n\n");
+printf(" #  class  description       properties\n");
+for (int i=0;i<n->getClassCount();i++)
+	{
+	NeuroClass* cl=n->getClass(i);
+	Param p=cl->getProperties();
+	printf("%2d.%6s  %-20s  %2d\n",i,(const char*)cl->getName(),(const char*)cl->getLongName(),p.getPropCount());
+	}
+int cl=rand() % n->getClassCount();
+printf("\nLet's change the NeuroItem's class to '%s'...\n",(const char*)n->getClassName(cl));
+n->getModel().open();
+n->setClass(n->getClass(cl));
+{
+SyntParam p=n->classProperties();
+if (p.getPropCount()>0)
+	{
+	printProperties(p);
+	changeOneProperty(p);
+	p.update();
+	}
+}
+
+if (n->getInputCount()>0)
+{
+printf("input info 0 = \"%s\"\n",(const char*)n->getInputInfo(0));
+printf("input info 0 abc = \"%s\"\n",(const char*)n->getInputInfo(0,"abc"));
+	n->setInputInfo(0,"test",44);
+	n->setInputInfo(0,"abc","yeah");
+}
+
+n->getModel().close();
+printf("The final object description will be then: '%s'\nAnd the full f0 genotype:\n\n%s\n",
+       (const char*)n->getDetails(), (const char*)n->getModel().getF0Geno().getGene());
+
+
+}
+
+int main(int argc,char*argv[])
+{
+srand(time(0));
+printNiceBanner("Welcome to GDK test application!");
+
+//Geno g(argc>1?argv[1]:"X[|G:1.23]");
+Geno g(argc>1?argv[1]:"//0\np:\nn:\nc:0,0,i=\"abc=7\"\n");
+printf("\nSource genotype: '%s'\n",(const char*)g.getGene());
+printf("                  ( format %c %s)\n",
+       g.getFormat(), (const char*)g.getComment());
+
+Model m(g);//.getConverted('0'));
+
+if (!m.isValid())
+	{
+	printf("Cannot build Model from this genotype!\n");
+	return 2;	
+	}
+printf("Converted to f0:\n%s\n",(const char*)m.getF0Geno().getGene());
+
+printf("Model contains: %d part(s)\n"
+       "                %d joint(s)\n"
+       "                %d neuron(s)\n",m.getPartCount(),m.getJointCount(),m.getNeuroCount());
+
+printf("\nInvestigating details...\n");
+
+if (m.getPartCount()>0)
+	{
+	int p=rand()%m.getPartCount();
+	printNiceBanner("P A R T    O B J E C T");
+	printf("            (part # %d)\n",p);
+	moreAboutPart(m.getPart(p));
+	}
+
+if (m.getJointCount()>0)
+	{
+	int j=rand()%m.getJointCount();
+	printNiceBanner("J O I N T    O B J E C T");
+	printf("            (joint # %d)\n",j);
+	moreAboutJoint(m.getJoint(j));
+	}
+
+if (m.getNeuroCount()>0)
+	{
+	int n=rand()%m.getNeuroCount();
+	printNiceBanner("N E U R O    O B J E C T");
+	printf("            (neuro # %d)\n",n);
+	moreAboutNeuro(m.getNeuro(n));
+	}
+
+#ifdef MODEL_V1_COMPATIBLE
+printNiceBanner("Old Neuro/NeuroItem view");
+int nc=m.old_getNeuroCount();
+printf("Model::old_getNeuroCount() = %d\n",nc);
+for (int i=0;i<nc;i++)
+	{
+	Neuro *n=m.old_getNeuro(i);
+	printf("neuron #%d: p=%d, j=%d, force=%g, inertia=%g, sigmoid=%g\n",
+	       i,n->part_refno,n->joint_refno,
+	       n->force,n->inertia,n->sigmo);
+	int nicount=n->getItemCount();
+	printf("    %d items\n",nicount);
+	for (int j=0;j<nicount;j++)
+		{
+		NeuroItem *ni=n->getNeuroItem(j);
+		printf("        item #%d - '%s', conn=%d, weight=%g\n",
+		       j,(const char*)ni->getDetails(),ni->conn_refno,ni->weight);
+		}
+	}
+printf("end.\n");
+#endif
+
+printf("\n######### THE END ###########\n\n"
+       "Hints:\n"
+       "  1. You can redirect output: gdktest >filename.txt\n"
+       "  2. Each run can yield different results because some\n"
+       "     values are randomly generated.\n"
+       "  3. Application will use custom genotype passed as\n"
+       "     a commandline parameter: gdktest X\n"
+       "\n");
+return 0;
+}
Index: /cpp/gdk/gdktest.dsp
===================================================================
--- /cpp/gdk/gdktest.dsp	(revision 5)
+++ /cpp/gdk/gdktest.dsp	(revision 5)
@@ -0,0 +1,287 @@
+# Microsoft Developer Studio Project File - Name="gdktest" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=gdktest - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "gdktest.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "gdktest.mak" CFG="gdktest - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "gdktest - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ""
+# PROP Intermediate_Dir ""
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /W3 /Gm /GR /GX /ZI /Od /D "_Windows" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "EASYMAPDEBUG" /D "NOCREATUREOBJECT" /FD /GZ /c
+# SUBTRACT CPP /nologo /YX /Yc /Yu
+# ADD BASE RSC /l 0x415 /d "_DEBUG"
+# ADD RSC /l 0x415 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# Begin Target
+
+# Name "gdktest - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\3d.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\advlist.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\callbacks.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\conv_f1.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\defgenoconv.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\errmanager.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\extvalue.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\framsg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\gdktest.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\geno.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\genoconv.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\list.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\model.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modelparts.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\multimap.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\multirange.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\neurolibrary.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\param.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\paramobj.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\paramtabobj.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sstring.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sstringutils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\stdouterr.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\syntparam.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\virtfile.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\3d.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\advlist.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\callbacks.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\conv_f1.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\defassign-f0_joint.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\defassign-f0_neuro.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\defassign-f0_part.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\defgenoconv.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\extvalue.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\f0classes.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\framsg.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\gen-config.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\geno.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\genoconv.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\list.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\model.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\modelparts.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\multimap.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\multirange.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\neuroclasses.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\neurocls-library.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\neurolibrary.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\nonstd.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\param.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\paramtabobj.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\printconvmap.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\sstring.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\sstringutils.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\statrick.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\syntparam.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\usertags.h
+# End Source File
+# End Group
+# End Target
+# End Project
Index: /cpp/gdk/gen-config.h
===================================================================
--- /cpp/gdk/gen-config.h	(revision 5)
+++ /cpp/gdk/gen-config.h	(revision 5)
@@ -0,0 +1,28 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+// This file is a part of Framsticks GDK library. See LICENSE.TXT for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+/**
+ gen-config.h
+
+ USE_GENCONV_xxx - configure converters
+ USE_GENMAN_xxx - configure genman
+
+ */
+
+#define USE_GENCONV_F10
+//#define USE_GENCONV_F21
+//#define USE_GENCONV_F30
+//#define USE_GENCONV_F40
+//#define USE_GENCONV_F41_TEST
+//#define USE_GENCONV_F50
+
+//#define USE_GENMAN_F0
+//#define USE_GENMAN_F1
+//#define USE_GENMAN_F2
+//#define USE_GENMAN_F3
+//#define USE_GENMAN_F4
+//#define USE_GENMAN_F5
Index: /cpp/gdk/geno.cpp
===================================================================
--- /cpp/gdk/geno.cpp	(revision 5)
+++ /cpp/gdk/geno.cpp	(revision 5)
@@ -0,0 +1,248 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "geno.h"
+#include "model.h"
+
+void Geno::init(const SString& genstring,int genformat,const SString& genname,const SString& comment)
+{
+owner=0;
+f0gen=0;
+mapinshift=0;
+mapoutshift=0;
+isvalid=-1;
+SString gencopy(genstring);
+if (genformat==-1)
+	{ // unknown format
+	genformat='1';
+	if (genstring.charAt(0)=='/')
+		{
+		int end;
+		SString newcomment;
+		switch(genstring.charAt(1))
+			{
+			case '/':
+				genformat=genstring.charAt(2);
+				if ((end=genstring.indexOf('\n'))>=0)
+					{
+					newcomment=genstring.substr(2,end-2);
+					gencopy=genstring.substr(end+1);
+					mapinshift=end+1;
+					}
+				else
+					{
+					gencopy=0;
+					mapinshift=genstring.len();
+					}
+				break;
+			case '*':
+				genformat=genstring.charAt(2);
+				if ((end=genstring.indexOf("*/"))>=0)
+					{
+					newcomment=genstring.substr(2,end-2);
+					gencopy=genstring.substr(end+2);
+					mapinshift=end+2;
+					}
+				else
+					{
+					gencopy=0;
+					mapinshift=genstring.len();
+					}
+				break;
+			}
+		if (newcomment.len()>0)
+			{
+			SString token; int pos=0;
+			if (newcomment.getNextToken(pos,token,';'))
+			if (newcomment.getNextToken(pos,token,';'))
+				{
+				if (token.len()) txt=token;
+			if (newcomment.getNextToken(pos,token,';'))
+				if (token.len()) name=token;
+				}
+			}
+		}
+	}
+
+gen=gencopy;
+format=genformat;
+if (!name.len()) name=genname;
+if (!txt.len()) txt=comment;
+multiline=(strchr((const char*)gen,'\n')!=0);
+// mapoutshift...?
+}
+
+void Geno::freeF0()
+{
+if (f0gen) {delete f0gen; f0gen=0;}
+}
+
+Geno::Geno(const char *genstring,int genformat,const char *genname,const char *comment)
+{
+init(SString(genstring),genformat,SString(genname),SString(comment));
+}
+
+Geno::Geno(const SString& genstring,int genformat,const SString& genname,const SString& comment)
+{
+init(genstring,genformat,genname,comment);
+}
+
+Geno::Geno(const Geno& src)
+	:gen(src.gen),name(src.name),format(src.format),txt(src.txt),isvalid(src.isvalid),
+	 mapinshift(src.mapinshift),mapoutshift(src.mapinshift),multiline(src.multiline),
+	 f0gen(0),owner(0)
+{f0gen=src.f0gen?new Geno(*src.f0gen):0;}
+
+void Geno::operator=(const Geno& src)
+{
+freeF0();
+gen=src.gen;
+name=src.name;
+format=src.format;
+txt=src.txt;
+isvalid=src.isvalid;
+mapinshift=src.mapinshift;
+mapoutshift=src.mapinshift;
+multiline=src.multiline;
+f0gen=src.f0gen?new Geno(*src.f0gen):0;
+owner=0;
+}
+
+Geno::Geno(const SString& src)
+{
+init(src,-1,SString::empty,SString::empty);
+}
+
+void Geno::setGene(const SString& g,int newformat)
+{
+gen=g;
+isvalid=-1;
+freeF0();
+if (newformat>=0) format=newformat;
+}
+
+void Geno::setString(const SString& g)
+{
+freeF0();
+init(g,-1,SString::empty,SString::empty);
+}
+
+void Geno::setName(const SString& n)
+{
+name=n;
+}
+
+void Geno::setComment(const SString& c)
+{
+txt=c;
+}
+
+SString Geno::toString(void)
+{
+SString out;
+int comment=0;
+if ((format!='1')||(comment=(txt.len()||name.len())))
+	{
+	if (multiline)
+		out+="//";
+	else
+		out+="/*";
+	out+=format;
+	if (comment)
+		{
+		if (txt.len()) {out+=";";out+=txt;}
+		if (name.len()){out+=";";out+=name;}
+		}
+	if (multiline)
+		out+="\n";
+	else
+		out+="*/";
+	}
+out+=gen;
+return out;
+}
+
+SString Geno::shortString(void)
+{
+SString out;
+if (format!='1')
+	{
+	if (multiline)
+		out+="//";
+	else
+		out+="/*";
+	out+=format;
+	if (multiline)
+		out+="\n";
+	else
+		out+="*/";
+	}
+out+=gen;
+return out;
+}
+
+int Geno::mapGenToString(int genpos) const
+{
+if (genpos>gen.len()) return -2;
+if (genpos<0) return -1;
+return mapinshift+genpos;
+}
+
+int Geno::mapStringToGen(int stringpos) const
+{
+stringpos-=mapinshift;
+if (stringpos>gen.len()) return -2;
+if (stringpos<0) return -1;
+return stringpos;
+}
+
+SString Geno::getGene(void) const {return gen;}
+SString Geno::getName(void) const {return name;}
+int Geno::getFormat(void) const {return format;}
+SString Geno::getComment(void) const {return txt;}
+
+void Geno::validate()
+{
+if (isvalid>=0) return;
+if (gen.len()==0) { isvalid=0; return; }
+if (getFormat()=='0')
+	{
+	Model mod(*this);
+	isvalid=mod.isValid();
+	}
+else
+	{
+	Geno f0geno=getConverted('0');
+	f0geno.validate();
+	isvalid=f0geno.isvalid;
+	}
+}
+
+int Geno::isValid(void)
+{
+if (isvalid<0) validate();
+return isvalid;
+}
+
+Geno Geno::getConverted(int otherformat,MultiMap *m)
+{
+if (otherformat==getFormat()) return *this;
+#ifndef NO_GENOCONVMANAGER
+if ((otherformat=='0')&&(!m))
+	{
+	if (!f0gen)
+		f0gen=new Geno(GenoConvManager::globalConvert(*this,otherformat));
+	return *f0gen;
+	}
+else
+	return GenoConvManager::globalConvert(*this,otherformat,m);
+#else
+return (otherformat==getFormat())?*this:Geno(0,0,0,"GenConvManager not available");
+#endif
+}
+
+Geno::~Geno()
+{
+if (f0gen) delete f0gen;
+}
Index: /cpp/gdk/geno.h
===================================================================
--- /cpp/gdk/geno.h	(revision 5)
+++ /cpp/gdk/geno.h	(revision 5)
@@ -0,0 +1,104 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _GENO_H_
+#define _GENO_H_
+
+#include "sstring.h"
+#include "extvalue.h"
+
+class MultiMap;
+
+/// basic information about a single genotype.
+class Geno: public DestrBase
+{
+SString gen;
+SString name;
+char format;
+SString txt;
+int isvalid; ///< <0 -> unknown   >=0 -> value for "isValid"
+
+Geno *f0gen;
+
+int mapinshift; /// # of characters in the initial comment
+int mapoutshift; /// # of characters in the output comment
+int multiline;
+
+void init(const SString& genstring,int genformat,const SString& genname,const SString& comment);
+void validate(void);
+
+void freeF0();
+
+int isInvalid() {return isvalid==0;}
+
+friend class Model;
+friend class GenoConvManager;
+	
+public:
+/// create a genotype object from primitives
+/// @param genstring pure genotype, without any comments
+/// @param genformat genotype format
+/// @param comment information about genotype (for genetic operators and "history")
+Geno(const char *genstring=0,int genformat=-1,const char *genname=0,const char *comment=0);
+
+/// create a genotype object from primitives
+/// @param genstring pure genotype, wihtout any comments
+/// @param genformat genotype format
+/// @param name genotype name, new name will generated if needed
+/// @param comment information about genotype (for genetic operators and "history")
+Geno(const SString& genstring,int genformat,const SString& genname,const SString& comment);
+
+/// create object from full string, containing optional format and comment information
+Geno(const SString & fullstring);
+
+/// clone
+Geno(const Geno& src);
+
+void operator=(const Geno& src);
+
+~Geno();
+
+void setValid(int v) {isvalid=v;}
+int getValid() {return isvalid;}
+
+/// return string representation, with format comment at the beginning
+SString toString(void);
+SString shortString(void);
+
+void setString(const SString& genewithcomments);
+
+/** @param newformat=-1 -> don't change */
+void setGene(const SString& g, int newformat=-1);
+SString getGene(void) const;
+
+SString getName(void) const;
+void setName(const SString&);
+int getFormat(void) const;
+
+SString getComment(void) const;
+void setComment(const SString&);
+
+/// invalid genotype cannot be used to build a creature
+int isValid(void);
+
+/// make converted version of the genotype.
+Geno getConverted(int otherformat,MultiMap *m=0);
+
+/// @return -1 = before first char in the string
+/// @return -2 = after last char in the string
+int mapGenToString(int genpos) const;
+/// @return -1 = before first char in the genotype
+/// @return -2 = after last char in the genotype
+int mapStringToGen(int stringpos) const;
+
+int operator==(const Geno &g) {return (format==g.format)&&(gen==g.gen);}
+
+void* owner;
+};
+
+#ifndef NO_GENOCONVMANAGER
+#include "genoconv.h"
+#endif
+
+#endif
Index: /cpp/gdk/genoconv.cpp
===================================================================
--- /cpp/gdk/genoconv.cpp	(revision 5)
+++ /cpp/gdk/genoconv.cpp	(revision 5)
@@ -0,0 +1,204 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "nonstd.h"
+
+#include <stdlib.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#include <errno.h>
+
+#include "genoconv.h"
+#include "multimap.h"
+
+///////////////////////////////////////////////////////////////////////////
+
+GenoConvParam::GenoConvParam(GenoConvManager *g):Param(0),gcm(g)
+{
+updatetab();
+}
+
+void GenoConvParam::freetab()
+{
+if (tab) free(tab);
+tab=0;
+}
+
+const char *GenoConvParam::id(int i)
+{
+if (i>=gcm->converters.size()) return 0;
+static char t[20];
+sprintf(t,"genkonw%d",i);
+return t;
+}
+
+void GenoConvParam::updatetab()
+{
+int i;
+GenoConverter *gk;
+ParamEntry *pe;
+int ile=gcm->converters.size();
+freetab();
+tab=(ParamEntry*)calloc(2+ile,sizeof(ParamEntry));
+tab[0].id="Genetics: Conversions";
+tab[0].group=1;
+tab[0].flags=ile;
+tab[0].name="gkparam:";
+for (i=0,pe=tab+1;gk=(GenoConverter *)gcm->converters(i);pe++,i++)
+	{
+	pe->id="?";
+	pe->group=0;
+	pe->flags=0;
+	pe->name=gk->name;
+	pe->type="d 0 1";
+	pe->help=gk->info;
+	}
+pe->id=0;
+}
+
+GenoConvParam::~GenoConvParam()
+{
+freetab();
+}
+
+void *GenoConvParam::getTarget(int i)
+{
+GenoConverter *gk=(GenoConverter *)gcm->converters(i);
+return &gk->enabled;
+}
+
+GenoConvManager::GenoConvManager()
+	:param(this)
+{
+if (!globalobject) globalobject=this;
+}
+
+GenoConvManager::~GenoConvManager()
+{
+GenoConverter *gc;
+for (converters.start();gc=(GenoConverter*)converters();) delete gc;
+if (globalobject==this) globalobject=0;
+}
+
+GenoConvManager *GenoConvManager::globalobject=0;
+
+void GenoConvManager::addConverter(GenoConverter *gc)
+{
+converters+=gc;
+param.updatetab();
+}
+void GenoConvManager::removeConverter(GenoConverter *gc)
+{
+converters-=gc;
+param.updatetab();
+}
+
+/// write path into 'path'
+/// return the last path element (return >= path)
+/// null -> path not found
+/// @param mapavailable will receive 1 if conversion map is supported by all converters in path
+/// (can be NULL if you don't need this information)
+
+char *GenoConvManager::getPath(char in,char out,char *path,int maxlen,int *mapavailable)
+{
+if (!maxlen) return 0;
+GenoConverter *gk;
+int i=0;
+for (;gk=(GenoConverter*)converters(i);i++)
+	{
+	if ((gk->enabled)&&(gk->in_format == in))
+		{
+		*path=i;
+		if (gk->out_format == out)
+			{
+			if (mapavailable)
+				*mapavailable=gk->mapsupport;
+			return path;
+			}
+		else
+			{
+			int mapavail;
+			char *ret=getPath(gk->out_format,out,path+1,maxlen-1,&mapavail);
+			if (ret)
+				{
+				if (mapavailable)
+					*mapavailable=gk->mapsupport && mapavail;
+				return ret;
+				}
+			}
+		}
+	}
+return 0;
+}
+
+char *GenoConvManager::getFormatPath(char in,char out,char *path,int maxlen,int *mapavailable)
+{
+char *ret=getPath(in,out,path,maxlen,mapavailable);
+if (ret)
+	{
+	for (char*t=path;t<=ret;t++)
+		*t=((GenoConverter*)converters(*t))->out_format;
+	}
+return ret;
+}
+
+Geno GenoConvManager::convert(Geno &in,char format,MultiMap *map)
+{
+if (in.getFormat()==format) return in;
+static char path[10];
+int dep;
+char *ret;
+if (in.isInvalid()) { return Geno("",0,"","invalid genotype cannot be converted"); }
+int mapavail;
+for (dep=1;dep<sizeof(path);dep++) // sogenannte iteracyjne poglebianie...
+	if (ret=getPath(in.getFormat(),format,path,dep,&mapavail)) break;
+if (!ret) { return Geno("",0,"","converter not found"); }
+if (!map) mapavail=0;
+char *t=path;
+SString tmp;
+tmp=in.getGene();
+MultiMap lastmap,tmpmap;
+int firstmap=1;
+for (;t<=ret;t++)
+	{
+	GenoConverter *gk=(GenoConverter*)converters(*t);
+	tmp=gk->convert(tmp,mapavail?&tmpmap:0);
+	if (!tmp.len())
+		{
+		char t[100];
+		sprintf(t,"f%c->f%c conversion failed (%s)",gk->in_format,gk->out_format,gk->name);
+		return Geno(0,0,0,t);
+		}
+	if (mapavail)
+		{
+		if (firstmap)
+			{
+			lastmap=tmpmap;
+			firstmap=0;
+			}
+		else
+			{
+			MultiMap m;
+			m.addCombined(lastmap,tmpmap);
+			lastmap=m;
+			}
+		tmpmap.clear();
+		}
+	}
+if (map)
+	*map=lastmap;
+return Geno(tmp, format, in.getName(), in.getComment());
+}
+
+Geno GenoConvManager::globalConvert(Geno &in,char format,MultiMap *map)
+{
+if (globalobject) return globalobject->convert(in,format,map);
+if (format==in.getFormat()) return in;
+return Geno(0,0,0,"GenConvManager not initialized");
+}
+
+/////////////////////////////////
Index: /cpp/gdk/genoconv.h
===================================================================
--- /cpp/gdk/genoconv.h	(revision 5)
+++ /cpp/gdk/genoconv.h	(revision 5)
@@ -0,0 +1,95 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _GENCONV_H_
+#define _GENCONV_H_
+
+#include "geno.h"
+#include "param.h"
+#include "list.h"
+#include "sstring.h"
+
+
+class GenoConvManager;
+
+class GenoConvParam: public Param
+{
+GenoConvManager *gcm;
+void freetab();
+public:
+GenoConvParam(GenoConvManager *g);
+~GenoConvParam();
+void *getTarget(int);
+const char* id(int i);
+void updatetab();
+};
+
+class MultiMap;
+
+/// Base class for all Geno Converters.
+/// In constructor you have to set public fields
+/// indicating your identity and supported formats.
+/// Each converter serves one in-out format pair.
+/// Instance of your converter should be registered
+/// in GenoConvManager.
+class GenoConverter
+{
+public:
+const char *name;	//< converter name (short)
+char in_format,		//< input format, eg. '1'
+	out_format;	//< output format, eg. '0'
+const char *info;	//< detailed info about converter, format or copyright
+long enabled;	//< don't touch this! (used by configuration module)
+long mapsupport; //< set to 1 if your converter supports genotype mapping
+
+/// You have to reimplement this method.
+/// If your converter cannot do its job, return empty string
+/// (return SString();), any other return value is assumed
+/// to be output genotype.
+/// @param map if not null, mapping informaton is requested, converter should add conversion map to this object
+virtual SString convert(SString &i,MultiMap *map) {return SString();}
+
+virtual ~GenoConverter() {}
+/// Don't forget to set public fields in your constructor
+GenoConverter():name(""),in_format(-1),out_format('0'),info(""),enabled(1),mapsupport(0) {}
+};
+
+/// This class gathers abilities of all converters and can
+/// convert a genotype to any other one, provided there is
+/// a path of GenoConverters between them.
+/// In most cases you don't use this class directly,
+/// Geno::getConverted(int) provides full converting functionality.
+/// Explicit GenoConvManager object is only needed for registering
+/// your GenoConverter.
+/// Use DefaultGenoConvManager to register the standard genotype converters automatically.
+class GenoConvManager
+{
+friend class GenoConvParam;
+SList converters;
+static GenoConvManager *globalobject;
+public:
+GenoConvManager();
+~GenoConvManager();
+class GenoConvParam param;
+/// select an object for use as global GenoConvManager
+void useManager(GenoConvManager *m) {globalobject=m;}
+/// get global converter
+static GenoConvManager *getGlobalObject() {return globalobject;}
+/// make a genotype in other format. genotype will be invalid
+/// if GenoConvManager cannot convert it.
+Geno convert(Geno &in,char format,MultiMap *map=0);
+/// static conversion function (uses global GenoConvManager)
+static Geno globalConvert(Geno &in,char format,MultiMap *map=0);
+/// register GenoConverter
+void addConverter(GenoConverter *conv);
+/// unregister GenoConverter
+void removeConverter(GenoConverter *conv);
+
+char *getPath(char in,char out,char *path,int maxlen,int *mapavailable=0);
+char *getFormatPath(char in,char out,char *path,int maxlen,int *mapavailable=0);
+};
+
+#endif
+
+
Index: /cpp/gdk/genotest.cpp
===================================================================
--- /cpp/gdk/genotest.cpp	(revision 5)
+++ /cpp/gdk/genotest.cpp	(revision 5)
@@ -0,0 +1,36 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "geno.h"
+#include "stdiofile.h"
+#include "sstringutils.h"
+#include "defgenoconv.h"
+
+/**
+ @file
+ Sample code: Testing genotype validity
+
+ \include genotest.cpp
+*/
+
+DefaultGenoConvManager gcm; //without this object the application would only handle "format 0" genotypes
+
+int main(int argc,char*argv[])
+{
+if (argc<=1)
+	{
+	puts("no genotype");
+	return 10;
+	}
+SString gen(argv[1]);
+if (!strcmp(gen,"-"))
+	{
+	gen=0;
+	StdioFILEDontClose in(stdin);
+	loadSString(&in,gen);
+	}
+Geno g(gen);
+puts(g.isValid()?"valid":"invalid");
+return !g.isValid();
+}
Index: /cpp/gdk/genotest.dsp
===================================================================
--- /cpp/gdk/genotest.dsp	(revision 5)
+++ /cpp/gdk/genotest.dsp	(revision 5)
@@ -0,0 +1,287 @@
+# Microsoft Developer Studio Project File - Name="genotest" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=genotest - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "genotest.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "genotest.mak" CFG="genotest - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "genotest - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ""
+# PROP Intermediate_Dir ""
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /W3 /Gm /GR /GX /ZI /Od /D "_Windows" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "EASYMAPDEBUG" /D "NOCREATUREOBJECT" /FD /GZ /c
+# SUBTRACT CPP /nologo /YX /Yc /Yu
+# ADD BASE RSC /l 0x415 /d "_DEBUG"
+# ADD RSC /l 0x415 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# Begin Target
+
+# Name "genotest - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\3d.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\advlist.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\callbacks.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\conv_f1.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\defgenoconv.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\errmanager.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\extvalue.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\framsg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\geno.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\genoconv.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\genotest.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\list.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\model.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modelparts.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\multimap.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\multirange.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\neurolibrary.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\param.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\paramobj.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\paramtabobj.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sstring.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sstringutils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\stdouterr.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\syntparam.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\virtfile.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\3d.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\advlist.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\callbacks.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\conv_f1.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\defassign-f0_joint.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\defassign-f0_neuro.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\defassign-f0_part.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\defgenoconv.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\extvalue.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\f0classes.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\framsg.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\gen-config.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\geno.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\genoconv.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\list.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\model.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\modelparts.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\multimap.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\multirange.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\neuroclasses.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\neurocls-library.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\neurolibrary.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\nonstd.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\param.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\paramtabobj.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\printconvmap.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\sstring.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\sstringutils.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\statrick.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\syntparam.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\usertags.h
+# End Source File
+# End Group
+# End Target
+# End Project
Index: /cpp/gdk/genotypeloader.cpp
===================================================================
--- /cpp/gdk/genotypeloader.cpp	(revision 5)
+++ /cpp/gdk/genotypeloader.cpp	(revision 5)
@@ -0,0 +1,35 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "genotypeloader.h"
+
+#define FIELDSTRUCT MiniGenotype
+ParamEntry minigenotype_paramtab[]=
+ {
+ {"Genotype",1,3,"org",},
+ {"name",0,0,"Name","s 0 40",FIELD(name),},
+ {"genotype",0,0,"Genotype","s 1",FIELD(genotype),},
+ {"info",0,0,"Info","s 1",FIELD(info),},
+ {0,0,0,},
+};
+#undef FIELDSTRUCT
+
+MiniGenotypeLoader::MiniGenotypeLoader():genotype_param(minigenotype_paramtab,&genotype_object) {init();}
+MiniGenotypeLoader::MiniGenotypeLoader(VirtFILE *f):MultiParamLoader(f),genotype_param(minigenotype_paramtab,&genotype_object) {init();}
+MiniGenotypeLoader::MiniGenotypeLoader(const char* filename):MultiParamLoader(filename),genotype_param(minigenotype_paramtab,&genotype_object) {init();}
+
+void MiniGenotypeLoader::init()
+{
+addClass(&genotype_param);
+breakOn(MultiParamLoader::OnError + MultiParamLoader::AfterObject);
+}
+
+MiniGenotype* MiniGenotypeLoader::loadNextGenotype()
+{
+genotype_object.clear();
+if ((go()==AfterObject)&&(getClass()==&genotype_param))
+	return &genotype_object;
+else
+	return 0;
+}
Index: /cpp/gdk/genotypeloader.h
===================================================================
--- /cpp/gdk/genotypeloader.h	(revision 5)
+++ /cpp/gdk/genotypeloader.h	(revision 5)
@@ -0,0 +1,70 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _GENOTYPELOADER_H_
+#define _GENOTYPELOADER_H_
+
+#include "sstring.h"
+#include "multiparamload.h"
+
+/** Helper class, mostly useful with MultiParamLoader
+    or its specialized version: MiniGenotypeLoader.
+    MiniGenotype stores 3 essential fields of the Genotype (name, gene and info)
+ */
+class MiniGenotype
+{
+public:
+SString name,genotype,info;
+void clear() {name=""; genotype=""; info="";}
+};
+
+
+/** Defines the association between "org:" object (found in genotype files)
+    and the MiniGenotype fields. MiniGenotypeLoader uses this definition
+    but you can also use it to make MultiParamLoader load genotype
+ */
+extern ParamEntry minigenotype_paramtab[];
+
+
+/** In most simple cases this is the class you would use to load a series of genotypes from
+    the Framsticks genotype file.
+
+    Usage pattern: (see loadertest.cpp for the working code)
+
+    1.Initialize
+
+    2.while(genotype=loadNextGenotype()) doSomethingWith(genotype);
+
+    3.Done!
+
+    MiniGenotypeLoader is simply the MultiParamLoader configured to load one kind of data: "org:" objects.
+    The instance of this class can also be reconfigured to recognize more objects by using MultiParamLoader
+    methods, or you can use it as a guide for creating your own specialized class.
+ */
+class MiniGenotypeLoader: public MultiParamLoader
+{
+MiniGenotype genotype_object;
+Param genotype_param;
+bool initialized;
+void init();
+public:
+MiniGenotypeLoader();
+MiniGenotypeLoader(VirtFILE *f);
+MiniGenotypeLoader(const char* filename);
+
+/** @returns genotype object if one was loaded or NULL otherwise.
+
+    Returned MiniGenotype pointer always references the the same object (MiniGenotypeLoader::genotype_object)
+    which means you may need to copy the data from it before calling loadNextGenotype() again.
+    In the default configuration (simple MiniGenotypeLoader) NULL is always final and should be used
+    to finish processing.
+
+    If the loader is configured to load other objects or stop on other conditions, NULL will also mean
+    every condition other than "GenotypeLoaded". In such cases you need MultiParamLoader::getStatus(),
+    MultiParamLoader::finished() and other methods to determine the real cause of NULL.
+ */
+MiniGenotype* loadNextGenotype();
+};
+
+#endif
Index: /cpp/gdk/list.cpp
===================================================================
--- /cpp/gdk/list.cpp	(revision 5)
+++ /cpp/gdk/list.cpp	(revision 5)
@@ -0,0 +1,13 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "list.h"
+//#include "nonstd.h"
+
+#ifdef SLISTSTATS
+SListStats SList::stats;
+#endif
Index: /cpp/gdk/list.h
===================================================================
--- /cpp/gdk/list.h	(revision 5)
+++ /cpp/gdk/list.h	(revision 5)
@@ -0,0 +1,171 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _LIST_H_
+#define _LIST_H_
+
+#include <stdlib.h>
+#include <string.h>
+#include "nonstd.h"
+
+//#define SLISTSTATS
+
+#ifdef SLISTSTATS
+#include <stdio.h>
+class SListStats
+{
+  public:
+int objects, allocations, copied, totalmem, usedmem;
+SListStats():objects(0),allocations(0),copied(0),totalmem(0),usedmem() {}
+~SListStats()
+	{
+	printf("------------------------\n"
+	       " SListStats:\n"
+	       " objects     = %ld\n"
+	       " allocations = %ld\n"
+	       " copied      = %ld\n"
+	       " total mem   = %ld\n"
+	       " usage       = %ld %%\n"
+	       "------------------------\n",
+	       objects,allocations,copied,totalmem,(usedmem*100)/totalmem);
+	}
+};
+#endif
+
+
+template<class T> class SListTempl
+{
+protected:
+int have,used,pos; // ile,zaj,poz
+T *mem;
+void resize(int x)
+	{
+	if (mem || x)
+		{
+		mem=(T*)realloc(mem,x*sizeof(T));
+#ifdef SLISTSTATS
+		SListStats::stats.allocations++;
+		SListStats::stats.copied+=sizeof(T)*min(x,have);
+#endif	
+		}
+	have=x;
+	}
+
+public:
+
+SListTempl(const SListTempl<T>& src):have(0),used(0),mem(0),pos(0)
+	{(*this)=src;}
+SListTempl():have(0),used(0),mem(0),pos(0)
+	{}
+~SListTempl()
+	{
+#ifdef SLISTSTATS
+	SListStats::stats.objects++;
+	SListStats::stats.totalmem+=sizeof(T)*have;
+	SListStats::stats.usedmem+=sizeof(T)*used;
+#endif
+	hardclear();
+	}
+
+void needSize(int s)
+	{ if (s>have) resize(s+3+s/8); }
+void operator+=(const T& e) ///< append one element
+ {append(e);}
+void operator-=(const T& e) ///< remove one element
+ {int i; if ((i=find(e))>=0) remove(i);}
+void remove(int i,int n=1) ///< remove n elements from position i
+	{
+	if ((i>=size())||(i<0)) return;
+	if (i>(size()-n)) n=size()-i;
+	if (pos>=i) pos-=n;
+	memmove(mem+i,mem+i+n,sizeof(T)*(used-n-i));
+	used-=n;
+	}
+void operator-=(int i) {remove(i);} ///< remove element from position i
+T& operator()(int i) const ///< return element at position i
+	{return mem[i];}
+bool hasMore() {return pos<size();}
+T& operator()() ///< return next element
+	{ return mem[pos++];}
+int operator==(const SListTempl<T>& l) const ///< compare list
+ {
+ if (size() != l.size()) return 0;
+ for (int i=0;i<size();i++) if (l.mem[i] != mem[i]) return 0;
+ return 1;
+ }
+int find(const T& e) const ///< return position of element, or -1 if not found
+	{ for (int i=0;i<size();i++) if (mem[i]==e) return i;   return -1; }
+int start() {return pos=0;} ///< start iteration throgh list
+void append(const T& data) ///< add 1 element
+	{needSize(size()+1); mem[used++]=data;}
+void append(const T* data,int n) ///< add n elements
+	{
+	needSize(size()+n);
+	memcpy(mem+used,data,sizeof(T)*n);
+	used+=n;
+	}
+void insert(int p,T* data,int n) ///< insert n elements at position p
+	{
+	if (p>size()) p=size();
+	needSize(size()+n);
+	memmove(mem+p+n,mem+p,sizeof(T)*(size()-p));
+	memcpy(mem+p,data,sizeof(T)*n);
+	if (pos>p) pos+=n;
+	}
+void insert(int p,const T& data) ///< insert 1 element at position p
+	{
+	if (p>size()) p=size();
+	needSize(size()+1);
+	memmove(mem+p+1,mem+p,sizeof(T)*(size()-p));
+	if (pos>p) pos++;
+	mem[p]=data;
+	used++;
+	}
+void set(int p,const T& d)
+	{ needSize(p+1); mem[p]=d; if (used<(p+1)) used=p+1;}
+void setSize(int s)
+	{ needSize(s); used=s;}
+T& get(int i) const {return operator()(i);}
+T& get() {return operator()();}
+void clear() {used=0;} ///< remove all elements
+void hardclear() {resize(0); used=0;} ///< remove all elements and free mem
+int size() const {return used;} ///< list size 
+int operator!() {return used;} ///< list size
+void operator=(const SListTempl<T>&src) ///duplicate
+ {
+ setSize(src.size());
+ memcpy(mem, src.mem, src.size()*sizeof(T));
+ }
+void operator+=(const SListTempl<T>&src) ///< append src contents
+ {
+ needSize(size()+src.size());
+ memcpy(mem+used, src.mem, src.size()*sizeof(T));
+ used+=src.used;
+ }
+void trim(int newsiz)
+	{if (newsiz<used) used=newsiz;}
+};
+
+#define FOREACH(type,var,list) for(type var=(type)list.start();var=(type)list();)
+
+// usage example: FOREACH(char*,t,thelist) printf("t=%s\n",t);
+
+template<class T> class PtrListTempl: public SListTempl<T>
+{
+   public:
+T operator()() ///< return next element
+     {if (this->pos>=this->size()) return 0; else return 
+this->mem[this->pos++];}
+
+T operator()(int i) const ///< return element at position i
+     {if (i>=this->size()) return 0; else return this->mem[i];}
+
+T get(int i) const {return operator()(i);}
+T get() {return operator()();}
+};
+
+
+typedef PtrListTempl<void*> SList;
+
+#endif
Index: /cpp/gdk/loadertest.cpp
===================================================================
--- /cpp/gdk/loadertest.cpp	(revision 5)
+++ /cpp/gdk/loadertest.cpp	(revision 5)
@@ -0,0 +1,41 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "genotypeloader.h"
+
+/**
+ @file
+ Sample code: Loading genotypes from Framsticks files
+
+ \include loadertest.cpp
+*/
+
+int main(int argc,char*argv[])
+{
+puts("This example shows how to load genotypes from the standard Framsticks genotype file");
+if (argc<2)
+	{
+	puts("(Please give the file name as command line argument)");
+	return 1;
+	}
+
+long count=0,totalsize=0;
+MiniGenotypeLoader loader(argv[1]);
+// using char* constructor (passing the file name to open)
+MiniGenotype *loaded;
+while(loaded=loader.loadNextGenotype())
+	{ // if loaded != NULL then the "org:" object data was
+	 // loaded into MiniGenotype object
+	count++;
+	totalsize+=loaded->genotype.len();
+	printf("%d. %s\t(%d characters)\n",count,(const char*)loaded->name,loaded->genotype.len());
+	}
+// the loop repeats until loaded==NULL, which could be beacause of error
+if (loader.getStatus()==MiniGenotypeLoader::OnError)
+	printf("Error: %s",(const char*)loader.getError());
+// (otherwise it was the end of the file)
+
+printf("\ntotal: %d items, %d characters\n",count,totalsize);
+return 0;
+}
Index: /cpp/gdk/loadertest.dsp
===================================================================
--- /cpp/gdk/loadertest.dsp	(revision 5)
+++ /cpp/gdk/loadertest.dsp	(revision 5)
@@ -0,0 +1,255 @@
+# Microsoft Developer Studio Project File - Name="loadertest" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=loadertest - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "loadertest.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "loadertest.mak" CFG="loadertest - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "loadertest - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ""
+# PROP Intermediate_Dir ""
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /W3 /Gm /GR /GX /ZI /Od /D "_Windows" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "EASYMAPDEBUG" /D "NOCREATUREOBJECT" /FD /GZ /c
+# SUBTRACT CPP /nologo /YX /Yc /Yu
+# ADD BASE RSC /l 0x415 /d "_DEBUG"
+# ADD RSC /l 0x415 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# Begin Target
+
+# Name "loadertest - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\errmanager.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\extvalue.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\framsg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\genotypeloader.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\list.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\loadertest.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\multiparamload.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\param.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\paramobj.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\paramtabobj.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sstring.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sstringutils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=".\stdiofile-autoinit.cpp"
+# End Source File
+# Begin Source File
+
+SOURCE=.\stdiofile.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\stdouterr.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\syntparam.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\virtfile.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\3d.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\advlist.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\callbacks.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\conv_f1.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\defassign-f0_joint.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\defassign-f0_neuro.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\defassign-f0_part.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\defgenoconv.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\extvalue.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\f0classes.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\framsg.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\gen-config.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\geno.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\genoconv.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\list.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\model.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\modelparts.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\multimap.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\multirange.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\neuroclasses.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\neurocls-library.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\neurolibrary.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\nonstd.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\param.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\paramtabobj.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\printconvmap.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\sstring.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\sstringutils.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\statrick.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\syntparam.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\usertags.h
+# End Source File
+# End Group
+# End Target
+# End Project
Index: /cpp/gdk/model.cpp
===================================================================
--- /cpp/gdk/model.cpp	(revision 5)
+++ /cpp/gdk/model.cpp	(revision 5)
@@ -0,0 +1,1269 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "nonstd.h"
+#include "model.h"
+#include "framsg.h"
+#include "multimap.h"
+#include "errmanager.h"
+
+#include <math.h>
+
+#define FIELDSTRUCT Model
+ParamEntry f0_model_paramtab[]=
+{
+{"Model",1,2,"m",},
+{"se",2,0,"startenergy","f",FIELD(startenergy),},
+{"Vstyle",2,0,"vis_style","s",FIELD(vis_style),},
+{0,0,0,},
+};
+#undef FIELDSTRUCT
+
+Model::Model()
+{
+autobuildmaps=0;
+init();
+}
+
+void Model::init()
+{
+partmappingchanged=0;
+buildstatus=empty;
+modelfromgenotype=0;
+startenergy=1.0;
+checklevel=1;
+#ifdef MODEL_V1_COMPATIBLE
+oldneurocount=-1; // == unknown
+oldconnections=0;
+#endif
+map=0;
+f0map=0;
+f0genoknown=1;
+}
+
+void Model::moveElementsFrom(Model &source)
+{
+int i;
+open();
+for (i=0;i<source.getPartCount();i++)
+	addPart(source.getPart(i));
+for (i=0;i<source.getJointCount();i++)
+	addJoint(source.getJoint(i));
+for (i=0;i<source.getNeuroCount();i++)
+	addNeuro(source.getNeuro(i));
+source.parts.clear(); source.joints.clear(); source.neurons.clear();
+source.clear();
+}
+
+void Model::internalCopy(const Model &mod)
+{
+geno=mod.geno;
+f0genoknown=0;
+startenergy=mod.startenergy;
+if (mod.getStatus()==valid)
+	{
+	modelfromgenotype=mod.modelfromgenotype;
+	{for (int i=0;i<mod.getPartCount();i++)
+		addPart(new Part(*mod.getPart(i)));}
+	{for (int i=0;i<mod.getJointCount();i++)
+		{
+		Joint *oldj=mod.getJoint(i);
+		Joint *j=new Joint(*oldj);
+		addJoint(j);
+		j->attachToParts(oldj->part1->refno,oldj->part2->refno);
+		}}
+	{for (int i=0;i<mod.getNeuroCount();i++)
+		{
+		Neuro *oldn=mod.getNeuro(i);
+		Neuro *n=new Neuro(*oldn);
+		addNeuro(n);
+		if (oldn->part_refno>=0) n->attachToPart(oldn->part_refno);
+		else n->attachToJoint(oldn->joint_refno);
+		}}
+	for (int i=0;i<mod.getNeuroCount();i++)
+		{
+		Neuro *oldn=mod.getNeuro(i);
+		Neuro *n=getNeuro(i);
+		for (int ni=0;ni < oldn->getInputCount();ni++)
+			{
+			float w;
+			Neuro *oldinput=oldn->getInput(ni,w);
+			SString info=n->getInputInfo(ni);
+			n->addInput(getNeuro(oldinput->refno),w,&info);
+			}
+		}
+	}
+}
+
+
+Model::Model(const Geno &src,int buildmaps)
+	:autobuildmaps(buildmaps)
+{init(src);}
+
+void Model::operator=(const Model &mod)
+{
+clear();
+open();
+internalCopy(mod);
+buildstatus=mod.buildstatus;
+}
+
+Model::Model(const Model &mod,int buildmaps)
+	:autobuildmaps(buildmaps)
+{
+init();
+open();
+internalCopy(mod);
+buildstatus=mod.buildstatus;
+}
+
+void Model::init(const Geno &src)
+{
+init();
+modelfromgenotype=1;
+geno=src;
+build();
+}
+
+void Model::resetAllDelta()
+{
+for (int i=0;i<getJointCount();i++)
+	getJoint(i)->resetDelta();
+}
+
+void Model::useAllDelta(bool yesno)
+{
+for (int i=0;i<getJointCount();i++)
+	getJoint(i)->useDelta(yesno);
+}
+
+Model::~Model()
+{
+delmodel_list.action((long)this);
+clear();
+}
+
+void Model::clear()
+{
+Part *p;
+for (parts.start();p=(Part*)parts();) delete p;
+Joint* j;
+for (joints.start();j=(Joint*)joints();) delete j;
+Neuro *n;
+for (neurons.start();n=(Neuro*)neurons();) delete n;
+parts.clear(); joints.clear(); neurons.clear();
+delMap();
+delF0Map();
+init();
+geno=Geno();
+f0geno=Geno();
+}
+
+Part *Model::addPart(Part *p)
+{
+p->owner=this;
+p->refno=parts.size();
+parts+=p;
+return p;
+}
+
+Joint *Model::addJoint(Joint *j)
+{
+j->owner=this;
+j->refno=joints.size();
+joints+=j;
+return j;
+}
+
+Neuro *Model::addNeuro(Neuro *n)
+{
+n->owner=this; 
+n->refno=neurons.size();
+neurons+=n;
+return n;
+}
+
+void Model::removeNeuros(SList &nlist)
+{
+FOREACH(Neuro*,nu,nlist)
+	{
+	int i=findNeuro(nu);
+	if (i>=0) removeNeuro(i);
+	}
+}
+
+void Model::removePart(int partindex,int removeattachedjoints,int removeattachedneurons)
+{
+Part *p=getPart(partindex);
+if (removeattachedjoints)
+	{
+	SList jlist;
+	findJoints(jlist,p);
+	FOREACH(Joint*,j,jlist)
+		{
+		int i=findJoint(j);
+		if (i>=0) removeJoint(i,removeattachedneurons);
+		}
+	}
+if (removeattachedneurons)
+	{
+	SList nlist;
+	findNeuros(nlist,0,p);
+	removeNeuros(nlist);
+	}
+parts-=partindex;
+delete p;
+}
+
+void Model::removeJoint(int jointindex,int removeattachedneurons)
+{
+Joint *j=getJoint(jointindex);
+if (removeattachedneurons)
+	{
+	SList nlist;
+	findNeuros(nlist,0,0,j);
+	removeNeuros(nlist);
+	}
+joints-=jointindex;
+delete j;
+}
+
+void Model::removeNeuro(int neuroindex,bool removereferences)
+{
+Neuro* thisN=getNeuro(neuroindex);
+
+if (removereferences)
+	{
+	Neuro* n;
+// remove all references to thisN
+	for (int i=0;n=(Neuro*)neurons(i);i++)
+		{
+		Neuro *inp;
+		for (int j=0;inp=n->getInput(j);j++)
+			if (inp==thisN)
+				{
+				n->removeInput(j);
+				j--;
+				}
+		}
+	}
+
+neurons-=neuroindex;
+delete thisN;
+}
+
+MultiMap& Model::getMap()
+{
+if (!map) map=new MultiMap();
+return *map;
+}
+
+void Model::delMap()
+{
+if (map) {delete map; map=0;}
+}
+void Model::delF0Map()
+{
+if (f0map) {delete f0map; f0map=0;}
+}
+
+void Model::makeGenToGenMap(MultiMap& result,const MultiMap& gen1tomodel,const MultiMap& gen2tomodel)
+{
+result.clear();
+MultiMap m;
+m.addReversed(gen2tomodel);
+result.addCombined(gen1tomodel,m);
+}
+
+void Model::getCurrentToF0Map(MultiMap& result)
+{
+result.clear();
+if (!map) return;
+const MultiMap& f0m=getF0Map();
+makeGenToGenMap(result,*map,f0m);
+}
+
+void Model::rebuild(int buildm)
+{
+autobuildmaps=buildm;
+clear();
+build();
+}
+
+void Model::initMap()
+{
+if (!map) map=new MultiMap();
+else map->clear();
+}
+
+void Model::initF0Map()
+{
+if (!f0map) f0map=new MultiMap();
+else f0map->clear();
+}
+
+void Model::build()
+{
+f0errorposition=-1;
+f0warnposition=-1;
+MultiMap *convmap=autobuildmaps?new MultiMap():0;
+f0geno=(geno.getFormat()=='0')? geno : geno.getConverted('0',convmap);
+f0genoknown=1;
+if (f0geno.isInvalid())
+	{
+	buildstatus=invalid;
+	if (convmap) delete convmap;
+	return;
+	}
+SString f0txt=f0geno.getGene();
+buildstatus=building; // was: open();
+if (autobuildmaps)
+	{
+	partmappingchanged=0;
+	initMap();
+	initF0Map();
+	}
+int pos=0,lnum=1,lastpos=0;
+SString line;
+MultiRange frommap;
+ErrorHandler err(ErrorHandler::DontBlock);
+for (;f0txt.getNextToken(pos,line,'\n');lnum++)
+	{
+	if (autobuildmaps)
+		{
+		frommap.clear();
+		frommap.add(lastpos,pos-1);
+		}
+	err.reset();
+	if (singleStepBuild(line,autobuildmaps?(&frommap):0)==-1)
+		{
+		buildstatus=invalid;
+		FMprintf("Model","build",FMLV_ERROR,
+			 geno.getName().len()?"illegal f0 code at line %d (%s)":"illegal f0 code at line %d",
+			 lnum,(const char*)geno.getName());
+		f0errorposition=lastpos;
+		if (convmap) delete convmap;
+		return;
+		}
+	if (err.getWarningCount())
+		{if (f0warnposition<0) f0warnposition=lastpos;}
+	lastpos=pos;
+	}
+err.disable();
+close();
+if (convmap)
+	{
+	*f0map=*map;
+	if (geno.getFormat()!='0')
+		{
+		MultiMap tmp;
+		tmp.addCombined(*convmap,getMap());
+		*map=tmp;
+		}
+	delete convmap;
+	}
+}
+
+const MultiMap& Model::getF0Map()
+{
+if (!f0map)
+	{
+	f0map=new MultiMap();
+	makeGeno(f0geno,f0map);
+	f0genoknown=1;
+	}
+return *f0map;
+}
+
+Geno Model::rawGeno()
+{
+Geno tmpgen;
+makeGeno(tmpgen);
+return tmpgen;
+}
+
+void Model::makeGeno(Geno &g,MultiMap *map)
+{
+if ((buildstatus!=valid)&&(buildstatus!=building))
+	{
+	g=Geno(0,0,0,"invalid model");
+	return;
+	}
+
+SString gen;
+
+static Param modelparam(f0_model_paramtab);
+static Param partparam(f0_part_paramtab);
+static Param jointparam(f0_joint_paramtab);
+static Param neuroparam(f0_neuro_paramtab);
+static Param connparam(f0_neuroconn_paramtab);
+
+static Part defaultpart;
+static Joint defaultjoint;
+static Neuro defaultneuro;
+static Model defaultmodel;
+static NeuroConn defaultconn;
+//static NeuroItem defaultneuroitem;
+
+Part *p;
+Joint *j;
+Neuro *n;
+int i;
+int len;
+int a,b;
+//NeuroItem *ni;
+
+if (startenergy!=defaultmodel.startenergy)
+	{
+	modelparam.select(this);
+	gen+="m:";
+	modelparam.save2(gen,&defaultmodel);
+	}
+
+for (i=0;p=(Part*)parts(i);i++)
+	{
+	partparam.select(p);
+	len=gen.len();
+	gen+="p:";
+	partparam.save2(gen,&defaultpart);
+	if (map)
+		map->add(len,gen.len()-1,partToMap(i));
+	}
+for (i=0;j=(Joint*)joints(i);i++)
+	{
+	jointparam.select(j);
+	len=gen.len();
+	jointparam.setParamTab(j->usedelta?f0_joint_paramtab:f0_nodeltajoint_paramtab);
+	gen+="j:";
+	jointparam.save2(gen,&defaultjoint);
+	if (map)
+		map->add(len,gen.len()-1,jointToMap(i));
+	}
+for (i=0;n=(Neuro*)neurons(i);i++)
+	{
+	neuroparam.select(n);
+	len=gen.len();
+	gen+="n:";
+	neuroparam.save2(gen,&defaultneuro);
+	if (map)
+		map->add(len,gen.len()-1,neuroToMap(i));
+	}
+for (a=0;a<neurons.size();a++)
+	{ // inputs
+	n=(Neuro*)neurons(a);
+//	if ((n->getInputCount()==1)&&(n->getInput(0).refno <= n->refno))
+//		continue; // already done with Neuro::conn_refno
+
+	for (b=0;b<n->getInputCount();b++)
+		{
+		float w;
+		NeuroConn nc;
+		Neuro* n2=n->getInput(b,w);
+//		if (((n2.parentcount==1)&&(n2.parent)&&(n2.parent->refno < n2.refno)) ^ 
+//		    (n2.neuro_refno>=0))
+//			printf("!!!! bad Neuro::neuro_refno ?!\n");
+
+//		if ((n2.parentcount==1)&&(n2.parent)&&(n2.parent->refno < n2.refno))
+//		if (n2.neuro_refno>=0)
+//			continue; // already done with Neuro::neuro_refno
+
+		nc.n1_refno=n->refno; nc.n2_refno=n2->refno;
+		nc.weight=w;
+		SString **s=n->inputInfo(b);
+		if ((s)&&(*s))
+		nc.info=**s;
+		connparam.select(&nc);
+		len=gen.len();
+		gen+="c:";
+		connparam.save2(gen,&defaultconn);
+		if (map)
+			map->add(len,gen.len()-1,neuroToMap(n->refno));
+		}
+	}
+g=Geno(gen,'0');
+}
+
+//////////////
+
+void Model::open()
+{
+if (buildstatus==building) return;
+buildstatus=building;
+modelfromgenotype=0;
+partmappingchanged=0;
+f0genoknown=0;
+delMap();
+}
+
+void Model::checkpoint()
+{}
+
+void Model::setGeno(const Geno& newgeno)
+{
+geno=newgeno;
+}
+
+void Model::clearMap()
+{
+Part *p; Joint *j; Neuro *n;
+int i;
+delMap();
+delF0Map();
+for (i=0;p=(Part*)parts(i);i++)
+	p->clearMapping();
+for (i=0;j=(Joint*)joints(i);i++)
+	j->clearMapping();
+for (i=0;n=(Neuro*)neurons(i);i++)
+	n->clearMapping();
+}
+
+int Model::close()
+{
+if (buildstatus!=building)
+	FMprintf("Model","close",FMLV_WARN,"unexpected close() - no open()");
+if (internalcheck(1)>0)
+	{
+	buildstatus=valid;
+
+	if (partmappingchanged)
+		{
+		getMap();
+		Part *p; Joint *j; Neuro *n;
+		int i;
+		for (i=0;p=(Part*)parts(i);i++)
+			if (p->getMapping())
+				map->add(*p->getMapping(),partToMap(i));
+		for (i=0;j=(Joint*)joints(i);i++)
+			if (j->getMapping())
+				map->add(*j->getMapping(),jointToMap(i));
+		for (i=0;n=(Neuro*)neurons(i);i++)
+			if (n->getMapping())
+				map->add(*n->getMapping(),neuroToMap(i));
+		}
+	}
+else 
+	buildstatus=invalid;
+
+return (buildstatus==valid);
+}
+
+int Model::validate()
+{
+return internalcheck(0);
+}
+
+Pt3D Model::whereDelta(const Part& start,const Pt3D& rot, const Pt3D& delta)
+{
+Orient roto;
+roto=rot;
+Orient o;
+roto.transform(o,start.o);
+//o.x=start.o/roto.x;
+//o.y=start.o/roto.y;
+//o.z=start.o/roto.z;
+return o.transform(delta)+start.p;
+}
+
+int Model::singleStepBuild(const SString &line,const MultiRange* srcrange)
+{
+int pos=0; const char*t=(const char*)line;
+for (;*t;t++,pos++)
+	if (!strchr(" \r\t",*t)) break;
+if (*t=='#') return 0;
+if (!*t) return 0;
+if (!strncmp(t,"p:",2))
+	{
+	static Param partparam(f0_part_paramtab);
+	Part *p=new Part();
+	partparam.select(p);
+	pos+=2;
+	partparam.load2(line,pos);
+	p->o.rotate(p->rot);
+	parts+=p;
+	p->owner=this;
+	if (srcrange) p->setMapping(*srcrange);
+	return getPartCount()-1;
+	}
+if (!strncmp(t,"m:",2))
+	{
+	static Param modelparam(f0_model_paramtab);
+	modelparam.select(this);
+	pos+=2;
+	modelparam.load2(line,pos);
+	return 0;
+	}
+else if (!strncmp(t,"j:",2))
+	{
+	static Param jointparam(f0_joint_paramtab);
+	Joint *j=new Joint();
+	jointparam.select(j);
+	pos+=2;
+	j->owner=this;
+	jointparam.load2(line,pos);
+	if ((j->p1_refno>=0)&&(j->p1_refno<getPartCount())&&
+	   (j->p2_refno>=0)&&(j->p2_refno<getPartCount()))
+		{
+		addJoint(j);
+		if (j->d.x < (JOINT_DELTA_MARKER-1.0))
+			j->useDelta(1);
+		j->attachToParts(j->p1_refno,j->p2_refno);
+		if (srcrange) j->setMapping(*srcrange);
+		return j->refno;
+		}
+	else
+		{
+		delete j;
+		FMprintf("Model","build",FMLV_ERROR,
+			 "invalid part reference for joint #%d",getJointCount()-1);
+		return -1;
+		}
+	}
+else if (!strncmp(t,"n:",2)) // neuro (or the old neuro object as the special case)
+	{
+	static Param neuroparam(f0_neuro_paramtab);
+	Neuro *nu=new Neuro();
+	neuroparam.select(nu);
+	pos+=2;
+	neuroparam.load2(line,pos);
+#ifdef MODEL_V1_COMPATIBLE
+	if (nu->neuro_refno>=0) // parent specified...
+		{
+		if (nu->neuro_refno >= getNeuroCount()) // and it's illegal
+			{
+			delete nu;
+			return -1;
+			}
+		Neuro *parentNU=getNeuro(nu->neuro_refno);
+		parentNU->addInput(nu,nu->weight);
+		// default class for parented units: n-n link
+		//if (nu->moredata.len()==0) nu->moredata="-";
+		}
+	else
+#endif
+		{
+		// default class for unparented units: standard neuron
+		if (nu->getClassName().len()==0) nu->setClassName("N");
+		}
+/*
+	if (nu->conn_refno>=0) // input specified...
+		{
+		if (nu->conn_refno >= getNeuroCount()) // and it's illegal
+			{
+			delete nu;
+			return -1;
+			}
+		Neuro *inputNU=getNeuro(nu->conn_refno);
+		nu->addInput(inputNU,nu->weight);
+		}
+*/
+#ifdef MODEL_V1_COMPATIBLE
+	nu->weight=1.0;
+#endif
+	nu->owner=this;
+	// attach to part/joint
+	if (nu->part_refno>=0)
+		nu->attachToPart(nu->part_refno);
+	if (nu->joint_refno>=0)
+		nu->attachToJoint(nu->joint_refno);
+	if (srcrange) nu->setMapping(*srcrange);
+	// todo: check part/joint ref# 
+#ifdef MODEL_V1_COMPATIBLE
+	if (hasOldNeuroLayout())
+		{
+		int count=old_getNeuroCount();
+		neurons.insert(count,nu);
+		oldneurocount=count+1;
+		return oldneurocount-1;
+		}
+	else
+#endif
+		{
+		neurons+=nu;
+		return neurons.size()-1;
+		}
+	}
+else if (!strncmp(t,"c:",2)) // add input
+	{
+	static Param ncparam(f0_neuroconn_paramtab);
+	NeuroConn c;
+	ncparam.select(&c);
+	pos+=2;
+	ncparam.load2(line,pos);
+	if ((c.n1_refno>=0)&&(c.n1_refno<getNeuroCount())&&(c.n2_refno>=0)&&(c.n2_refno<getNeuroCount()))
+		{
+		Neuro *na=getNeuro(c.n1_refno);
+		Neuro *nb=getNeuro(c.n2_refno);
+		na->addInput(nb,c.weight,&c.info);
+		if (srcrange)
+			na->addMapping(*srcrange);
+		return 0;
+		}
+	FMprintf("Model","build",FMLV_ERROR,
+		 "invalid neuron connection #%d <- #%d",c.n1_refno,c.n2_refno);
+	return -1;
+	}
+#ifdef MODEL_V1_COMPATIBLE
+else if (!strncmp(t,"ni:",3)) // old neuroitem
+	{
+	// we always use old layout for "ni:"
+	static Param neuroitemparam(f0_neuroitem_paramtab);
+	Neuro *nu=new Neuro();
+	neuroitemparam.select(nu);
+	pos+=3;
+	neuroitemparam.load2(line,pos);
+	// illegal parent?
+	if ((nu->neuro_refno<0)||(nu->neuro_refno>=old_getNeuroCount()))
+		{
+		delete nu;
+		return -1;
+		}
+	Neuro *parentN=getNeuro(nu->neuro_refno);
+	// copy part/joint refno from parent, if possible
+	if ((nu->part_refno<0)&&(parentN->part_refno>=0))
+		nu->part_refno=parentN->part_refno;
+	if ((nu->joint_refno<0)&&(parentN->joint_refno>=0))
+		nu->joint_refno=parentN->joint_refno;
+	nu->owner=this;
+	// attach to part/joint
+	if (nu->part_refno>=0)
+		nu->attachToPart(nu->part_refno);
+	if (nu->joint_refno>=0)
+		nu->attachToJoint(nu->joint_refno);
+	if (srcrange)
+		nu->setMapping(*srcrange);
+	// special case: old muscles
+	// PARENT neuron will be set up to be the CHILD of the current one (!)
+	if (nu->isOldEffector())
+		{
+		nu->neuro_refno=parentN->refno;
+		neurons+=nu;
+		nu->owner=this;
+		nu->addInput(parentN,nu->weight); // (!)
+		nu->weight=1.0;
+		parentN->invalidateOldItems();
+		return 0; // !!! -> ...getItemCount()-1;
+		}
+	parentN->addInput(nu,nu->weight);
+	neurons+=nu;
+	parentN->invalidateOldItems();
+	if (nu->getClassName().len()==0)
+		{
+		nu->setClassName("-");
+		// for compatibility, "ni" can define a n-n connection
+		// referring to non-existent neuron (which will be hopefully defined later)
+		// internal check will add the proper input to this unit
+		// if conn_refno >=0 and input count==0
+		oldconnections=1;
+		if (srcrange)
+			parentN->addMapping(*srcrange);
+		}
+	else
+		nu->weight=1.0;
+	return 0; // !!! -> ...getItemCount()-1;
+	}
+#endif
+else return -1;
+}
+
+#ifdef MODEL_V1_COMPATIBLE
+int Model::addOldConnectionsInputs()
+{
+if (!oldconnections) return 1;
+Neuro* n;
+for (int i=0;i<neurons.size();i++)
+	{
+	n=(Neuro*)neurons(i);
+	if (n->conn_refno>=0)
+		if (n->isNNConnection())
+			if (n->conn_refno < old_getNeuroCount())
+				{ // good reference
+				Neuro* parent=n->parent; // nn connection has exactly one parent
+				int inp=parent->findInput(n);
+				Neuro* target=getNeuro(n->conn_refno);
+				parent->setInput(inp,target,n->weight);
+				removeNeuro(i,0); // no need to remove references
+				i--;
+				}
+			else
+				{
+				FMprintf("Model","internalCheck",FMLV_ERROR,
+					 "illegal N-N connection #%d (reference to #%d) (%s)",
+					 i,n->conn_refno,(const char*)geno.getName());
+				return 0;
+				}
+	}
+oldconnections=0;
+return 1;
+}
+#endif
+
+/////////////
+
+/** change the sequence of neuro units 
+    and fix references in "-" objects (n-n connections)  */
+void Model::moveNeuro(int oldpos,int newpos)
+{
+if (oldpos==newpos) return; // nop!
+Neuro *n=getNeuro(oldpos);
+neurons-=oldpos;
+neurons.insert(newpos,n);
+ // conn_refno could be broken -> fix it
+#ifdef MODEL_V1_COMPATIBLE
+for (int i=0;i<neurons.size();i++)
+	{
+	Neuro *n2=getNeuro(i);
+	if (n2->isNNConnection())
+		if (n2->conn_refno == oldpos) n2->conn_refno=newpos;
+		else
+		{ if (n2->conn_refno > oldpos) n2->conn_refno--;
+		  if (n2->conn_refno >= newpos) n2->conn_refno++; }
+	}
+invalidateOldNeuroCount();
+#endif
+}
+
+#ifdef MODEL_V1_COMPATIBLE
+/** move all old neurons (class "N") to the front of the neurons list.
+    @return number of old neurons
+  */
+int Model::reorderToOldLayout()
+{
+Neuro *n;
+int neurocount=0;
+for (int i=0;i<neurons.size();i++)
+	{
+	n=(Neuro*)neurons(i);
+	if (n->isOldNeuron())
+		{
+		moveNeuro(i,neurocount);
+		neurocount++;
+		i=neurocount-1;
+		}
+	}
+return neurocount;
+}
+#endif
+////////////
+
+void Model::updateNeuroRefno()
+{
+for (int i=0;i<neurons.size();i++)
+	{
+	Neuro* n=(Neuro*)neurons(i);
+	n->refno=i;
+	}
+}
+
+#define VALIDMINMAX(var,template,field) \
+if (var -> field < getMin ## template () . field) \
+	{ var->field= getMin ## template () . field; \
+	FMprintf("Model","internalCheck",FMLV_WARN,# field " too small in " # template "#%d (adjusted)",i);} \
+else if (var -> field > getMax ## template () . field) \
+	{ var->field= getMax ## template ()  . field; \
+	FMprintf("Model","internalCheck",FMLV_WARN,# field " too big in " # template "#%d (adjusted)",i);}
+
+#define LINKFLAG 0x8000000
+
+void Model::updateRefno()
+{
+int i;
+for (i=0;i<getPartCount();i++) getPart(i)->refno=i;
+for (i=0;i<getJointCount();i++) getJoint(i)->refno=i;
+for (i=0;i<getNeuroCount();i++) getNeuro(i)->refno=i;
+}
+
+int Model::internalcheck(int final)
+{
+Part *p;
+Joint *j;
+Neuro *n;
+int i,k;
+int ret=1;
+if ((parts.size()==0)&&(neurons.size()==0)) return 0;
+if (parts.size()==0)
+	size=Pt3D_0;
+else
+	{
+Pt3D bbmin=((Part*)parts(0))->p, bbmax=bbmin;
+for (i=0;i<parts.size();i++)
+	{
+	p=(Part*)parts(i);
+	p->owner=this;
+	p->refno=i;
+	if (checklevel>0)
+		p->mass=0.0;
+//	VALIDMINMAX(p,part,mass);
+	VALIDMINMAX(p,Part,size);
+	VALIDMINMAX(p,Part,density);
+	VALIDMINMAX(p,Part,friction);
+	VALIDMINMAX(p,Part,ingest);
+	VALIDMINMAX(p,Part,assim);
+	p->flags&=~LINKFLAG; // for delta joint cycle detection
+	if (p->p.x-p->size < bbmin.x) bbmin.x=p->p.x-p->size;
+	if (p->p.y-p->size < bbmin.y) bbmin.y=p->p.y-p->size;
+	if (p->p.z-p->size < bbmin.z) bbmin.z=p->p.z-p->size;
+	if (p->p.x+p->size > bbmax.x) bbmax.x=p->p.x+p->size;
+	if (p->p.y+p->size > bbmax.y) bbmax.y=p->p.y+p->size;
+	if (p->p.z+p->size > bbmax.z) bbmax.z=p->p.z+p->size;
+	}
+size=bbmax-bbmin;
+for (i=0;i<joints.size();i++)
+	{
+	j=(Joint*)joints(i);
+	VALIDMINMAX(j,Joint,stamina);
+	VALIDMINMAX(j,Joint,stif);
+	VALIDMINMAX(j,Joint,rotstif);
+	j->refno=i;
+	j->owner=this;
+	if (j->part1 && j->part2 && (j->part1 != j->part2))
+		{
+		j->p1_refno=j->part1->refno;
+		j->p2_refno=j->part2->refno;
+		if (checklevel>0)
+			{
+			j->part1->mass+=1.0;
+			j->part2->mass+=1.0;
+			}
+		if ((j->usedelta)&&(j->d.x < (JOINT_DELTA_MARKER-1.0)))
+			{ // delta positioning -> calc. orient.
+			if (j->part2->flags & LINKFLAG)
+				{
+				ret=0;
+				FMprintf("Model","internalCheck",FMLV_ERROR,
+					 "delta joint cycle detected at joint#%d (%s)",
+					 i,(const char*)geno.getName());
+				}
+			j->o=j->rot;
+			j->part1->o.transform(j->part2->o,j->o);
+//			j->part2->o.x=j->part1->o/j->o.x;
+//			j->part2->o.y=j->part1->o/j->o.y;
+//			j->part2->o.z=j->part1->o/j->o.z;
+			j->part2->p=j->part2->o.transform(j->d)+j->part1->p;
+			j->part2->flags|=LINKFLAG; j->part1->flags|=LINKFLAG; // for delta joint cycle detection
+			}
+		else
+			{ // abs.positioning -> calc. delta
+			if (final)
+			{
+			// calc orient delta
+//			Orient tmpo(j->part2->o);
+//			tmpo*=j->part1->o;
+			Orient tmpo;
+			j->part1->o.revTransform(tmpo,j->part2->o);
+			tmpo.getAngles(j->rot);
+			j->o=j->rot;
+			// calc position delta
+			Pt3D tmpp(j->part2->p);
+			tmpp-=j->part1->p;
+			j->d=j->part2->o.revTransform(tmpp);
+			}
+			}
+		if (final) if (j->d()>getMaxJoint().d.x)
+			{
+			ret=0;
+			FMprintf("Model","internalCheck",FMLV_ERROR,"delta too big in joint #%d (%s)",
+				 i,(const char*)geno.getName());
+			}
+		}
+	else
+		{
+		FMprintf("Model","internalCheck",FMLV_ERROR,"illegal part references in joint #%d (%s)",
+			 i,(const char*)geno.getName());
+		ret=0;
+		}
+	}
+	}
+#ifdef MODEL_V1_COMPATIBLE
+if (!addOldConnectionsInputs())
+	return 0;
+#endif
+
+updateNeuroRefno(); // valid refno is important for n-n connections check (later)
+
+for (i=0;i<neurons.size();i++)
+	{
+	n=(Neuro*)neurons(i);
+	VALIDMINMAX(n,Neuro,state);
+#ifdef MODEL_V1_COMPATIBLE
+	VALIDMINMAX(n,Neuro,inertia);
+	VALIDMINMAX(n,Neuro,force);
+	VALIDMINMAX(n,Neuro,sigmo);
+	n->conn_refno=-1;
+	n->weight=1.0;
+	n->neuro_refno=-1;
+#endif
+	n->part_refno=(n->part)?n->part->refno:-1;
+	n->joint_refno=(n->joint)?n->joint->refno:-1;
+	}
+
+if (parts.size()&&(checklevel>0))
+	{
+	for (i=0;i<parts.size();i++)
+		{
+		p=(Part*)parts(i);
+		if (p->mass<=0.001)
+			p->mass=1.0;
+		p->flags&=~LINKFLAG;
+		}
+	getPart(0)->flags|=LINKFLAG;
+	int change=1;
+	while(change)
+		{
+		change=0;
+		for (i=0;i<joints.size();i++)
+			{
+			j=(Joint*)joints(i);
+			if (j->part1->flags&LINKFLAG)
+				{
+				if (!(j->part2->flags&LINKFLAG))
+					{
+					change=1;
+					j->part2->flags|=LINKFLAG;
+					}
+				}
+			else
+			if (j->part2->flags&LINKFLAG)
+				{
+				if (!(j->part1->flags&LINKFLAG))
+					{
+					change=1;
+					j->part1->flags|=LINKFLAG;
+					}
+				}
+			}
+		}
+	for (i=0;i<parts.size();i++)
+		{
+		p=(Part*)parts(i);
+		if (!(p->flags&LINKFLAG))
+			{
+			FMprintf("Model","internalCheck",FMLV_ERROR,"not all parts connected (eg.#0-#%d) (%s)",
+				 i,(const char*)geno.getName());
+			ret=0;
+			break;
+			}
+		}
+	}
+
+for (i=0;i<joints.size();i++)
+	{
+	j=(Joint*)joints(i);
+	if (j->p1_refno==j->p2_refno)
+		{
+		FMprintf("Model","internalCheck",FMLV_ERROR,"illegal self connection, joint #%d (%s)",
+			 i,(const char*)geno.getName());
+		ret=0;
+		break;
+		}
+	for (k=i+1;k<joints.size();k++)
+		{
+		Joint* j2=(Joint*)joints(k);
+		if (((j->p1_refno==j2->p1_refno)&&(j->p2_refno==j2->p2_refno))
+		    || ((j->p1_refno==j2->p2_refno)&&(j->p2_refno==j2->p1_refno)))
+			{
+			FMprintf("Model","internalCheck",FMLV_ERROR,"illegal duplicate joints #%d and #%d (%s)",
+				 i,k,(const char*)geno.getName());
+			ret=0;
+			break;
+			}
+		}
+	}
+return ret;
+}
+
+/////////////
+
+int Model::getErrorPosition(bool includingwarnings)
+{
+return includingwarnings?
+	((f0errorposition>=0) ? f0errorposition : f0warnposition)
+	:
+	f0errorposition;
+}
+
+const Geno& Model::getGeno() const
+{
+return geno;
+}
+
+const Geno& Model::getF0Geno()
+{
+static Geno invalidgeno("",'0',"","invalid");
+if (buildstatus==building)
+	FMprintf("Model","getGeno",FMLV_WARN,"model was not completed - missing close()");
+if (buildstatus!=valid)
+	return invalidgeno;
+if (!f0genoknown)
+	{
+	if (autobuildmaps)
+		{
+		initF0Map();
+		makeGeno(f0geno,f0map);
+		}
+	else
+		{
+		delF0Map();
+		makeGeno(f0geno);
+		}
+	f0genoknown=1;
+	}
+return f0geno;
+}
+
+int Model::getPartCount() const
+{
+return parts.size();
+}
+
+Part* Model::getPart(int i) const
+{
+return ((Part*)parts(i));
+}
+
+int Model::getJointCount() const
+{
+return joints.size();
+}
+
+Joint* Model::getJoint(int i) const
+{
+return ((Joint*)joints(i));
+}
+
+int Model::findJoints(SList& result,const Part* part)
+{
+Joint *j;
+int n0=result.size();
+if (part)
+   for(int i=0;j=(Joint*)joints(i);i++)
+     if ((j->part1 == part) || (j->part2 == part)) result+=(void*)j;
+return result.size()-n0;
+}
+
+int Model::findNeuro(Neuro* n)
+{return neurons.find(n);}
+
+int Model::findPart(Part* p)
+{return parts.find(p);}
+
+int Model::findJoint(Joint* j)
+{return joints.find(j);}
+
+int Model::findJoint(Part *p1, Part *p2)
+{
+Joint* j;
+for(int i=0;j=getJoint(i);i++)
+	if ((j->part1==p1)&&(j->part2==p2)) return i;
+return -1;
+}
+
+
+////////////////////
+
+#ifdef MODEL_V1_COMPATIBLE
+void Model::calcOldNeuroCount()
+{
+if (oldneurocount>=0) return;
+oldneurocount=reorderToOldLayout();
+}
+
+int Model::old_getNeuroCount()
+{ calcOldNeuroCount();
+ return oldneurocount;}
+
+Neuro* Model::old_getNeuro(int i) 
+{calcOldNeuroCount();
+return (i<oldneurocount)? (Neuro*)getNeuro(i) : (Neuro*)0;
+}
+
+int Model::old_findNeuro(Neuro* n)
+{calcOldNeuroCount();
+return findNeuro(n);}
+
+Neuro *Model::old_addNewNeuro()
+{
+int count=old_getNeuroCount();
+Neuro *nu=addNewNeuro();
+nu->setClassName("N");
+moveNeuro(nu->refno,oldneurocount);
+oldneurocount=count+1;
+return (Neuro*)nu;
+}
+#endif
+
+///////////////////////
+
+int Model::getNeuroCount() const
+{return neurons.size();}
+
+Neuro* Model::getNeuro(int i) const
+{return (Neuro*)neurons(i);}
+
+int Model::getConnectionCount() const
+{
+int n=0;
+for(int i=0;i<getNeuroCount();i++)
+	n+=getNeuro(i)->getInputCount();
+return n;
+}
+
+int Model::findNeuros(SList& result,
+			  const char* classname,const Part* part,const Joint* joint)
+{
+Neuro *nu;
+SString cn(classname);
+int n0=result.size();
+for(int i=0;nu=(Neuro*)neurons(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;
+}
+
+///////////////////
+
+void Model::disturb(double amount)
+{
+int i;
+if (amount<=0) return;
+for(i=0;i<parts.size();i++)
+	{
+	Part *p=getPart(i);
+	p->p.x+=(rnd01-0.5)*amount;
+	p->p.y+=(rnd01-0.5)*amount;
+	p->p.z+=(rnd01-0.5)*amount;
+	}
+for(i=0;i<joints.size();i++)
+	{
+	Joint *j=getJoint(i);
+	Pt3D tmpp(j->part2->p);
+	tmpp-=j->part1->p;
+	j->d=j->part2->o.revTransform(tmpp);
+	}
+}
+
+//////////////////////
+
+class MinPart: public Part {public: MinPart() {Param par(f0_part_paramtab,this);par.setMin();}};
+class MaxPart: public Part {public: MaxPart() {Param par(f0_part_paramtab,this);par.setMax();}};
+class MinJoint: public Joint {public: MinJoint() {Param par(f0_joint_paramtab,this);par.setMin();}};
+class MaxJoint: public Joint {public: MaxJoint() {Param par(f0_joint_paramtab,this);par.setMax();}};
+class MinNeuro: public Neuro {public: MinNeuro() {Param par(f0_neuro_paramtab,this);par.setMin();}};
+class MaxNeuro: public Neuro {public: MaxNeuro() {Param par(f0_neuro_paramtab,this);par.setMax();}};
+
+const Part& Model::getMinPart() {static MinPart part; return part;}
+const Part& Model::getMaxPart() {static MaxPart part; return part;}
+const Part& Model::getDefPart() {static Part part; return part;}
+const Joint& Model::getMinJoint() {static MinJoint joint; return joint;}
+const Joint& Model::getMaxJoint() {static MaxJoint joint; return joint;}
+const Joint& Model::getDefJoint() {static Joint joint; return joint;}
+const Neuro& Model::getMinNeuro() {static MinNeuro neuro; return neuro;}
+const Neuro& Model::getMaxNeuro() {static MaxNeuro neuro; return neuro;}
+const Neuro& Model::getDefNeuro() {static Neuro neuro; return neuro;}
Index: /cpp/gdk/model.def
===================================================================
--- /cpp/gdk/model.def	(revision 5)
+++ /cpp/gdk/model.def	(revision 5)
@@ -0,0 +1,167 @@
+
+# f0 definition for Framsticks
+class:id=m,name="Model"
+prop:id=se,name="starting energy",group="x",flags=1024,type="f -999999 999999 0 "
+
+class:id=p,name="Part" 
+
+
+
+prop:id=x,name="position.x",group="Geometry",flags=1024,type="f   "
+prop:id=y,name="position.y",group="Geometry",flags=1024,type="f   "
+prop:id=z,name="position.z",group="Geometry",flags=1024,type="f   "
+prop:id=m,xtra=1,name="mass",group="Other properties",flags=0,type="f 0.1 999.0 1.0"
+prop:id=s,name="size",group="Other properties",flags=0,type="f 0.1 10.0 1.0"
+prop:id=dn,xtra=1,name="density",group="Other properties",flags=0,type="f 0.2 5.0 1.0"
+prop:id=fr,xtra=1,name="friction",group="Other properties",flags=0,type="f 0.0 4.0 0.4"
+prop:id=ing,xtra=1,name="ingestion",group="Other properties",flags=0,type="f 0.0 1.0 0.25"
+prop:id=as,xtra=1,name="assimilation",group="Other properties",flags=0,type="f 0.0 1.0 0.25"
+prop:id=rx,name="rot.x",group="Geometry",flags=0,type="f   "
+prop:id=ry,name="rot.y",group="Geometry",flags=1024,type="f   "
+prop:id=rz,name="rot.z",group="Geometry",flags=1024,type="f   "
+prop:id=i,name="info",group="Other properties",flags=0,type="s   "
+prop:id=Vstyle,name="vis_style",group="Visual",flags=0,type="s 0 -1 part"
+
+
+class:id=j,name="Joint" 
+
+
+
+
+prop:id=p1,name="part1 ref#",group="Connections",flags=1024,type="d -1 999999 -1"
+prop:id=p2,name="part2 ref#",group="Connections",flags=1024,type="d -1 999999 -1"
+prop:id=rx,name="rotation.x",group="Geometry",flags=0,type="f   "
+prop:id=ry,name="rotation.y",group="Geometry",flags=1024,type="f   "
+prop:id=rz,name="rotation.z",group="Geometry",flags=1024,type="f   "
+prop:id=dx,name="delta.x",group="Geometry",flags=0,type="f -2 2 0"
+prop:id=dy,name="delta.y",group="Geometry",flags=1024,type="f -2 2 0"
+prop:id=dz,name="delta.z",group="Geometry",flags=1024,type="f -2 2 0"
+prop:id=stif,xtra=1,name="stiffness",group="Other properties",flags=0,type="f 0.0 1.0 1.0"
+prop:id=rotstif,xtra=1,name="rotation stiffness",group="Other properties",flags=0,type="f 0.0 1.0 1.0"
+prop:id=stam,name="stamina",group="Other properties",flags=0,type="f 0.0 1.0 0.25"
+prop:id=i,name="info",group="Other properties",flags=0,type="s   "
+prop:id=Vstyle,name="vis_style",group="Visual",flags=0,type="s 0 -1 joint"
+
+
+
+
+class:id=n,name="Neuro" 
+
+
+
+prop:id=p,name="part ref#",group="Connections",flags=0,type="d -1 999999 -1"
+prop:id=j,name="joint ref#",group="Connections",flags=0,type="d -1 999999 -1"
+prop:id=d,name="item details",group="Other",flags=0,type="s   "
+prop:id=i,name="info",group="Other",flags=0,type="s   "
+prop:id=Vstyle,name="vis_style",group="Visual",flags=0,type="s 0 -1 neuro"
+prop:id=getInputCount,name="input count",group="Connections",flags=1+2,type="d   "
+prop:id=getInputNeuroDef,name="get input neuron",group="Connections",flags=1+2,type="p oNeuroDef(d)   "
+prop:id=getInputNeuroIndex,name="get input neuron index",group="Connections",flags=1+2,type="p d(d)   "
+prop:id=getInputWeight,name="get input weight",group="Connections",flags=1+2,type="p f(d)   "
+
+
+class:id=c,name="NeuroConn" 
+
+
+prop:id=n1,name="this neuro ref#",group="Connection",flags=1024,type="d -1 999999 -1"
+prop:id=n2,name="connected neuro ref#",group="Connection",flags=1024,type="d -1 999999 -1"
+prop:id=w,name="weight",group="Connection",flags=1024,type="f -999999 999999 1.0"
+prop:id=i,name="info",group="Other",flags=0,type="s   "
+
+
+neuro: id=N,name="Neuron",info="Standard neuron",inputs=-1,output=1,location=0  ,vhints=2 
+
+prop:id=in,name="Inertia",type="f 0.0 1.0 0.8"
+prop:id=fo,name="Force",type="f 0.0 999.0 0.04"
+prop:id=si,name="Sigmoid",type="f -99999.0 99999.0 2.0"
+prop:id=s,name="State",type="f -1.0 1.0 0.0"
+
+
+neuro: id=Nu,name="Unipolar neuron [EXPERIMENTAL!]",info="Works like standard neuron (N) but the output value is scaled to 0...+1 instead of -1...+1.\nHaving 0 as one of the saturation states should help in \"gate circuits\", where input signal is passed through or blocked depending on the other singal.",inputs=-1,output=1,location=0 
+prop:id=in,name="Inertia",type="f 0.0 1.0 0.8"
+prop:id=fo,name="Force",type="f 0.0 999.0 0.04"
+prop:id=si,name="Sigmoid",type="f -99999.0 99999.0 2.0"
+prop:id=s,name="State",type="f -1.0 1.0 0.0"
+
+
+neuro: id=G,name="Gyroscope",info="Equilibrium sensor.\n0=the stick is horizontal\n+1/-1=the stick is vertical",inputs=0,output=1,location=2  ,vhints=32  ,symbol="8,7,100,50,90,50,90,40,70,40,80,50,70,60,90,60,90,50,12,43,24,48,24,48,19,38,19,38,24,43,24,43,54,48,54,48,64,43,69,38,64,38,54,43,54,5,63,69,58,74,48,79,38,79,28,74,23,69,1,43,79,43,74,1,23,69,26,66,1,63,69,60,66,1,55,76,53,73,1,31,75,33,72" 
+
+
+
+
+neuro: id=T,name="Touch",info="Touch sensor.\n-1=no contact\n0=just touching\n>0=pressing, value depends on the force applied",inputs=0,output=1,location=1  ,vhints=32  ,symbol="2,7,100,50,90,50,90,40,70,40,80,50,70,60,90,60,90,50,11,75,50,65,50,60,55,55,45,50,55,45,45,40,50,35,50,30,45,25,50,30,55,35,50" 
+
+
+
+
+neuro: id=S,name="Smell",info="Smell sensor. Aggregated \"smell of energy\" experienced from all energy objects (creatures and food pieces).\nClose objects have bigger influence than the distant ones: for each energy source, its partial feeling is proportional to its energy/(distance^2)",inputs=0,output=1,location=1  ,vhints=32  ,symbol="5,7,100,50,90,50,90,40,70,40,80,50,70,60,90,60,90,50,3,10,40,15,45,15,55,10,60,5,20,30,25,35,30,45,30,55,25,65,20,70,4,15,35,20,40,22,50,20,60,15,65,5,75,50,50,50,45,45,40,50,45,55,50,50" 
+
+
+
+
+neuro: id=*,name="Constant",info="Constant value",inputs=0,output=1,location=0  ,vhints=1  ,symbol="3,6,100,50,90,50,90,40,70,40,70,60,90,60,90,50,1,85,50,75,50,1,80,45,80,55" 
+
+
+
+
+neuro: id=|,name="Bend muscle",info="",inputs=1,output=0,location=2  ,vhints=86  ,symbol="6,5,25,40,35,40,45,50,35,60,25,60,25,40,4,65,85,65,50,75,50,75,85,65,85,3,65,56,49,29,57,24,72,50,4,68,53,70,53,70,55,68,55,68,53,5,50,21,60,15,70,14,79,15,87,20,81,10,1,86,20,77,21" 
+
+
+prop:id=p,name="power",type="f 0.01 1.0 0.25"
+prop:id=r,name="bending range",type="f 0.0 1.0 1.0"
+
+
+neuro: id=@,name="Rotation muscle",info="",inputs=1,output=0,location=2  ,vhints=150  ,symbol="5,5,25,40,35,40,45,50,35,60,25,60,25,40,4,65,85,65,50,75,50,75,85,65,85,1,69,10,77,17,10,59,15,57,17,57,22,60,26,69,27,78,26,82,21,82,16,79,12,69,10,80,6,3,65,50,65,20,75,20,75,50" 
+
+
+prop:id=p,name="power",type="f 0.01 1.0 1.0"
+
+
+neuro: id=D,name="Differentiate",info="Calculate the difference between the current and previous input value. Multiple inputs are aggregated with respect to their weights",inputs=-1,output=1,location=0 
+
+
+neuro: id=Fuzzy,name="Fuzzy system [EXPERIMENTAL!]",info="Refer to publications to learn about this neuron",inputs=-1,output=1,location=0  ,symbol="5,2,30,65,37,37,44,65,3,37,65,44,37,51,37,58,65,2,51,65,58,37,65,65,6,100,50,70,50,70,25,25,10,25,90,70,75,70,50,1,70,65,25,65" 
+
+prop:id=ns,name="number of fuzzy sets",type="d 1  "
+prop:id=nr,name="number of rules",type="d 1  "
+prop:id=fs,name="fuzzy sets",type="s 0 -1 0"
+prop:id=fr,name="fuzzy rules",type="s 0 -1 0"
+
+
+neuro: id=Sti,name="Sticky [EXPERIMENTAL!]",info="",inputs=1,output=0,location=1  ,vhints=32 
+
+
+
+neuro: id=LMu,name="Linear muscle [EXPERIMENTAL!]",info="",inputs=1,output=0,location=2  ,vhints=16 
+
+prop:id=p,name="power",type="f 0.01 1.0 1.0"
+
+
+neuro: id=Water,name="Water detector",info="Output signal:\n0=on or above water surface\n1=under water (deeper than 1)\n0..1=in the transient area just below water surface",inputs=0,output=1,location=1  ,vhints=32 
+
+
+
+neuro: id=Energy,name="Energy level",info="The current energy level divided by the initial energy level.\nUsually falls from initial 1.0 down to 0.0 and then the creature dies. It can rise above 1.0 if enough food is ingested",inputs=0,output=1,location=0  ,vhints=32 
+
+
+
+neuro: id=Ch,name="Channelize",info="Combines all input signals into a single multichannel output; Note: ChSel and ChMux are the only neurons which support multiple channels. Other neurons discard everything except the first channel.",inputs=-1,output=1,location=0 
+
+
+neuro: id=ChMux,name="Channel multiplexer",info="Outputs the selected channel from the second (multichannel) input. The first input is used as the selector value (-1=select first channel, .., 1=last channel)",inputs=2,output=1,location=0 
+
+
+neuro: id=ChSel,name="Channel selector",info="Outputs a single channel (selected by the \"ch\" parameter) from multichannel input",inputs=1,output=1,location=0 
+prop:id=ch,name="channel",type="d   "
+
+
+neuro: id=Rnd,name="Random noise",info="Generates random noise (subsequent random values in the range of -1..+1)",inputs=0,output=1,location=0 
+
+
+neuro: id=Sin,name="Sinus generator",info="Output frequency = f0+input",inputs=1,output=1,location=0  ,symbol="3,12,75,50,71,37,62,28,50,25,37,28,28,37,25,50,28,62,37,71,50,75,62,71,71,62,75,50,1,75,50,100,50,5,35,50,40,35,45,35,55,65,60,65,65,50" 
+
+prop:id=f0,name="base frequency",type="f -1.0 1.0 0.06283185307"
+prop:id=t,name="time",type="f 0 6.283185307 0"
+
+
+# EOF
Index: /cpp/gdk/model.h
===================================================================
--- /cpp/gdk/model.h	(revision 5)
+++ /cpp/gdk/model.h	(revision 5)
@@ -0,0 +1,421 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _MODEL_H_
+#define _MODEL_H_
+
+#include <stdlib.h>
+#include <math.h>
+#include <stdio.h>
+
+#include "modelparts.h"
+#include "advlist.h"
+#include "usertags.h"
+
+extern ParamEntry f0_model_paramtab[];
+
+//#define EASYMAPDEBUG
+
+enum ModelBuildStatus {empty,building,invalid,valid};
+
+class MultiMap;
+
+class VisualModel;
+
+/**
+    "Model" is the skeleton of the framsticks creature.
+    This object can be used for 2 purposes:
+     - you can build a creature from any supported framsticks genotype
+    format
+     - or generate low level f0 genotype from existing construct.
+
+    In both cases you have access to geometry and neuron net data.
+    Using this standard class assures compatibility and good
+    integration with core framsticks engine.
+
+    Model contains 3 kinds of objects:
+    - Parts (class Part).
+    - Joints (class Joint). Each Joint is connected with 2 Parts. (@see Joint::attachToParts()).
+    - Neurons (class Neuro). Neuron can have 0 or more inputs - other neurons. (@see Neuro::addInput()).
+      Each Neuron can be located on the physical structure, i.e. it can ba attached to Part or Joint
+      (@see Neuro::attachToPart(), Neuro::attachToJoint()).
+
+\f[(dot)
+digraph Model
+ {
+  Joint1; Joint2;
+  node [ shape=box ]
+  Part1; Part2; Part3;
+  Joint1 -> Part1; Joint1 -> Part2; Joint2 -> Part2; Joint2 -> Part3
+  node [ shape=diamond ]
+  Neuro1 -> Neuro2; Neuro1 -> Neuro3; Neuro2 -> Neuro2; Neuro3 -> Neuro2;
+  Neuro1 -> Part1; Neuro2 -> Joint2;
+ }
+\f]
+*/
+
+class Model: public DestrBase
+{
+  protected:
+Geno geno,f0geno;
+char modelfromgenotype;
+char f0genoknown;
+/// make model map in build()
+char autobuildmaps;
+/// valid if build from f0 genotype
+int f0errorposition;
+/// valid if build from f0 genotype
+int f0warnposition;
+
+ModelBuildStatus buildstatus;
+/// NULL if the map is not (yet) created
+MultiMap *map,*f0map;
+
+SList parts,joints,neurons;
+char partmappingchanged;
+
+#ifdef MODEL_V1_COMPATIBLE
+/** NeuroCount value.
+    compatibility_neurocount = -1 if its value is unknown and the layout is not compatible
+    @see reorderToOldLayout()
+*/
+int oldneurocount;
+char oldconnections;
+
+/** calculate oldNeuroCount */
+void calcOldNeuroCount();
+/** some new calls can invalidate old compatibility data */
+void invalidateOldNeuroCount() {oldneurocount=-1;}
+/**
+   for compatibility with old NeuroClass the layout of Neurons
+   is changed when old 'Neuro' accessing methods are in use.
+   Neurons:
+   0 .. compatibility_neurocount-1                : old Neurons (class "N")
+   compatibility_neurocount .. neurons.size()-1   : other units
+*/
+int reorderToOldLayout();
+
+/** check if compatibility should be preserved */
+int hasOldNeuroLayout() {return oldneurocount>=0;}
+
+/** add inputs to the old "-" units.
+    @return 1=ok, 0=invalid input detected  */
+int addOldConnectionsInputs();
+#endif
+
+void internalCopy(const Model &mod);
+
+/// make the model from current genotype
+void build();
+
+/// make f0 genotype from current construction
+void makeGeno(Geno &,MultiMap *map=0);
+
+friend class NeuroNetFactory;
+friend class VisualModel;
+friend class GLVisualModel;
+friend class Creature;
+friend class PartBase;
+
+int checklevel;
+
+void updateNeuroRefno(); // set Neuro::refno for all neurons
+int internalcheck(int final);
+
+void moveNeuro(int oldpos,int newpos);
+
+void init(const Geno &srcgen);
+void init();
+
+void delMap();
+void delF0Map();
+void initMap();
+void initF0Map();
+
+public:
+/** get current model state.
+\f[(dot)
+digraph M
+ {
+ node [fontsize=12]
+ edge [fontsize=10]
+ building [label="building = can be modified"]
+ valid -> building [label="open()"]
+ building -> valid [label="close()"]
+ invalid -> building [label="open()"]
+ building -> invalid [label="close() [failed]"]
+ empty -> building [label="open()"]
+ }
+\f]
+*/
+ModelBuildStatus getStatus() const {return buildstatus;}
+int isValid() const {return buildstatus==valid;}
+int getErrorPosition(bool includingwarnings=false);
+
+void updateRefno(); // set ::refno for all elements
+
+/// The bounding box size. Valid if the model is valid. Read only.
+Pt3D size;
+
+SString vis_style;
+double startenergy;
+Callback delmodel_list;
+ModelUserTags userdata;
+
+/// Create empty model with invalid empty genotype
+Model();
+
+/** Create a model based on provided genotype
+   @param buildmaps if not 0, generate mapping information for the model.
+   default is 0, because mapping uses additional time and memory.
+   @see getMap()
+ */
+Model(const Geno &src,int buildmaps=0);
+Model(const Model &mod,int buildmaps=0);
+/** duplicate the model.
+    the resulting object's status is 'building' (opened).
+    @see getStatus()
+ */
+void operator=(const Model &source);
+
+/** move all elements from 'source' into our model object.
+    'source' becomes empty after this operation.
+    the model will be opened if it is not already open.
+    @see addElementsFrom(const Model &source);
+ */
+void moveElementsFrom(Model &source);
+
+/** copy all elements from 'source' into our model object
+    without affecting the 'source'.
+    the model will be opened if it is not already open.
+    @see moveElementsFrom(Model &source);
+ */
+void addElementsFrom(const Model &source)
+{Model m(source); moveElementsFrom(m);}
+
+void operator+=(const Model &source)
+{addElementsFrom(source);}
+
+~Model();
+
+/** @return source genotype.
+    @warn source genotype will not automatically change 
+    when the model is modified. this behaviour is inconsistent
+    with the previous release. use getF0Geno() if you need
+    the updated genotype.
+    @see getF0Geno(), setGeno()
+*/
+const Geno &getGeno() const;
+
+/// change source genotype
+void setGeno(const Geno& newgeno);
+
+/** @return f0 genotype - generated from current model state
+    don't use between open()-close()
+*/
+const Geno &getF0Geno();
+
+/** @return mapping from source genotype (0-based position in text) to model elements reference numbers.
+    the map can be empty if the mapping hasn't been requested earlier (in constructor)
+    or the converters don't support mapping.
+    if you create or modify the model using singleStepBuild() or direct manipulation
+    the map will be not changed or created automatically - it is your responsibility.
+    @see Model(const Geno &src,int buildmaps=0), singleStepBuild(), PartBase::addMapping()
+    @see clearMap()
+    @see convmap
+
+*/
+MultiMap &getMap();
+
+/** @return mapping from f0 genotype (0-based position in text) to model elements reference numbers
+ */
+const MultiMap &getF0Map();
+
+/** discard all mapping information for this model.
+    getMap().clear() also works, but it doesn't remove mappings from model elements.
+    if there are any, the will be incorporated into model map during close().
+    @see close(), getMap(), PartBase::clearMapping()
+ */
+void clearMap();
+
+/** generate mapping from the current genotype to the f0 genotype.
+    this works only if both current and f0 maps are already known.
+    @see convmap
+*/
+void getCurrentToF0Map(MultiMap& m);
+
+void setValidationLevel(int level)
+	{checklevel=level;}
+
+/// calculate location of the new part connected to the existing one
+/// using delta option
+Pt3D whereDelta(const Part& start,const Pt3D& rot, const Pt3D& delta);
+
+/// create the whole model from scratch, using current genotype
+void rebuild(int buildmaps);
+
+/// setGeno(newgeno); rebuild();
+void rebuild(const Geno& newgeno,int buildmaps) {setGeno(newgeno);rebuild(buildmaps);}
+
+/// reuse current model object but discard all model data
+void clear();
+
+/** execute single line of <B>f0</B> genotype.
+    return value is non-negative reference number of the created item,
+    or negative value. reference number can be used to access
+    the item using getPart(int), getJoint(int) and getNeuroItem(int) methods.
+    @param srcrange source genotype range which will be mapped to this element
+*/
+int singleStepBuild(const SString &singleline,const MultiRange* srcrange=0);
+
+/// separate build stages (for future use)
+void checkpoint();
+
+/// call resetDelta() on all joints
+void resetAllDelta();
+
+/// call useDelta() on all joints
+void useAllDelta(bool yesno);
+
+/// final validity check of the model, all model data has to be available at this point.
+/// if the model was modified, the genotype will be also updated.
+/// it also calls "validate" with all side effects.
+/// @return > 0 means "valid"
+int close();
+
+/// enable model building.
+/// you should use it if you need to create new model, modify the model after close
+/// or modify the model created from the genotype.
+/// between open() and close() the model is not fully usable, 
+void open();
+
+/// current model written as f0 genotype while building
+/// (not cached, not validated, probably unusable and bad if used before close(). but good for debugging.)
+Geno rawGeno();
+
+/// partial validity check - you can use this call
+/// anytime between open - close.
+/// this function will check (and repair)
+/// - part-joint-neuro connections
+/// - model geometry (if "delta option" was used)
+/// - physical/biological limits
+/// @return 1 = valid
+/// @return 0 = invalid
+/// validate doesn't make the model fully usable (for simulation)
+/// you still need to use close if you have changed anything
+int validate();
+
+int getPartCount() const;
+/// you can access parts 0 .. getPartCount()-1.
+Part *getPart(int i) const;
+
+int getJointCount() const;
+/// you can access joints 0 .. getJointCount()-1.
+Joint *getJoint(int i) const;
+
+int getNeuroCount() const;
+int getConnectionCount() const;
+/// you can access neurons 0 .. getNeuroCount()-1.
+Neuro *getNeuro(int i) const;
+
+#ifdef MODEL_V1_COMPATIBLE
+/* compatibility calls for accessing old Neuro objects */
+
+/// @deprecated Neuro class will be removed soon
+/// @see compat
+int old_getNeuroCount();
+/// you can access neurons 0 .. getNeuroCount()-1.
+/// @deprecated Neuro class will be removed soon
+Neuro *old_getNeuro(int i);
+/// @see addNewNeuro, addNeuro
+/// @deprecated Neuro class will be removed soon
+Neuro *old_addNewNeuro();
+/// @return neuro index or -1 if not found
+/// @deprecated Neuro class will be removed soon
+int old_findNeuro(Neuro* n);
+#endif
+
+/** create new Part and add it to the model. @see addPart()  */
+Part *addNewPart() {return addPart(new Part());}
+/** create new Joint and add it to the model. @see addJoint() */
+Joint *addNewJoint() {return addJoint(new Joint());}
+/** create new Neuro and add it to the model. @see addNeuro() */
+Neuro *addNewNeuro() {return addNeuro(new Neuro());}
+
+/** add p to the model. p->refno is adjusted. @return the Part just added (==p). */
+Part *addPart(Part *p);
+/** add j to the model. j->refno is adjusted. @return the Joint just added (==j). */
+Joint *addJoint(Joint *j);
+/** add n to the model. n->refno is adjusted. @return the Neuro just added (==n). */
+Neuro *addNeuro(Neuro *n);
+
+/** remove the part from model.
+    @param removeattachedjoints if not 0 -> remove all joints connected with this part
+    @param removeattachedneurons if not 0 -> remove neurons attached to this part */
+void removePart(int partindex,int removeattachedjoints=1,int removeattachedneurons=1);
+
+/** remove the joint from model.
+    @param removeattachedneurons if not 0 -> remove neurons attached to this joint */
+void removeJoint(int jointindex,int removeattachedneurons=1);
+
+/** remove the neuron from model.
+    @param removereferences if true -> look for references to this neuron
+    (i.e. connections from other neurons) and remove them as well */
+void removeNeuro(int neuroindex,bool removereferences=true);
+
+void removeNeuros(SList &nlist);
+
+/// @return part index or -1 if not found in the model
+int findPart(Part* p);
+/// @return joint index or -1 if not found in the model
+int findJoint(Joint* j);
+/// @return neuro index or -1 if not found in the model
+int findNeuro(Neuro* nu);
+/// @return joint index or -1 if not found in the model
+int findJoint(Part *p1, Part *p2);
+
+/** make the list of neuros satisfying given search criteria: classname,part,joint
+    @param result objects will be appended here
+    @return number of objects found  */
+int findNeuros(SList& result,const char* classname=0,const Part* part=0,const Joint* joint=0);
+
+/** search for joints connected to the part
+    @param result objects will be appended here
+    @return number of objects found  */ 
+int findJoints(SList& result,const Part* part=0);
+
+void disturb(double amount);
+
+#ifdef EASYMAPDEBUG
+static int partToMap(int i) {return 0+i;}
+static int jointToMap(int i) {return 10+i;}
+static int neuroToMap(int i) {return 20+i;}
+static int mapToPart(int i) {return i-0;}
+static int mapToJoint(int i) {return i-10;}
+static int mapToNeuro(int i) {return i-20;}
+#else
+static int partToMap(int i) {return 0x10000000+i;}
+static int jointToMap(int i) {return 0x20000000+i;}
+static int neuroToMap(int i) {return 0x30000000+i;}
+static int mapToPart(int i) {return i-0x10000000;}
+static int mapToJoint(int i) {return i-0x20000000;}
+static int mapToNeuro(int i) {return i-0x30000000;}
+#endif
+
+static void makeGenToGenMap(MultiMap& result,const MultiMap& gen1tomodel,const MultiMap& gen2tomodel);
+
+///////////////////////////
+
+static const Part& getMinPart();
+static const Part& getMaxPart();
+static const Part& getDefPart();
+static const Joint& getMinJoint();
+static const Joint& getMaxJoint();
+static const Joint& getDefJoint();
+static const Neuro& getMinNeuro();
+static const Neuro& getMaxNeuro();
+static const Neuro& getDefNeuro();
+};
+
+#endif
Index: /cpp/gdk/modelparts.cpp
===================================================================
--- /cpp/gdk/modelparts.cpp	(revision 5)
+++ /cpp/gdk/modelparts.cpp	(revision 5)
@@ -0,0 +1,838 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include <stdlib.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#include <errno.h>
+
+///////////////////////////////     MODELPARTS.CPP     ///////////////
+
+#include "modelparts.h"
+#include "model.h"
+
+#include "nonstd.h"
+#include "param.h"
+#include "neurolibrary.h"
+#include "multirange.h"
+#include "extvalue.h"
+
+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)
+	:longname(_props->id),
+	 name(_props->name),
+	 description(_description),
+	 props(_props),
+	 prefinputs(_prefinputs),
+	 prefoutput(_prefoutput),
+	 preflocation(_preflocation),
+	 vectordata(_vectordata),ownedvectordata(own_vd),
+	 visualhints(vhints),impl(0),active(1),genactive(0)
+{}
+
+NeuroClass::~NeuroClass()
+{
+setSymbolGlyph(0,0);
+}
+
+NeuroClass::NeuroClass()
+	:name("Invalid"),props(empty_paramtab),
+	 prefinputs(0), prefoutput(0),
+	 preflocation(0), vectordata(0), ownedvectordata(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 {sprintf(t.directAppend(30),"   uses %d inputs\n",getPreferredInputs()); t.endAppend();}
+	}
+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<p.getPropCount();i++)
+		{
+		if (i) t+="\n";
+		t+="   "; t+=p.name(i); t+=" ("; t+=p.id(i); t+=")";
+		switch(*p.type(i))
+			{
+			case 'd': t+=" integer";
+			{long a,b,c; if (p.getMinMax(i,a,b,c)>=2) {sprintf(t.directAppend(30)," %d..%d",a,b); t.endAppend();}}
+				break;
+			case 'f': t+=" float";
+			{double a,b,c; if (p.getMinMax(i,a,b,c)>=2) {sprintf(t.directAppend(30)," %g..%g",a,b); t.endAppend();}}
+				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)
+	:state(_state),PartBase(getDefaultStyle())
+#ifdef MODEL_V1_COMPATIBLE
+,inertia(_inertia),force(_force),sigmo(_sigmo)
+#endif
+{
+#ifdef MODEL_V1_COMPATIBLE
+olditems=0;
+#endif
+flags=0;
+myclass=0;
+knownclass=1;
+}
+
+Neuro::Neuro(void):PartBase(getDefaultStyle())
+{
+#include "defassign-f0_neuro.h"
+state=0.0;
+myclass=0;
+knownclass=1;
+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;
+}
+
+
+Neuro::~Neuro()
+{
+#ifdef MODEL_V1_COMPATIBLE
+if (olditems) delete olditems;
+#endif
+int i;
+for(i=0;i<inputs.size();i++)
+	{
+	NInput &ni=inputs(i);
+	if (ni.info) delete ni.info;
+	}
+}
+
+SString** Neuro::inputInfo(int i)
+{
+if (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()
+{
+NeuroClass *cl=getClass();
+ParamEntry *pe = cl ? cl->getParamTab() : emptyParamTab;
+return SyntParam(pe,&myclassparams);
+}
+
+SString Neuro::getClassName()
+{
+return myclassname;
+}
+
+void Neuro::setClassName(const SString& clazz)
+{
+myclassname=clazz;
+knownclass=0;
+}
+
+int Neuro::addInput(Neuro* child,float 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<inputs.size();i++)
+	if (inputs(i).n==child) return i;
+return -1;
+}
+
+Neuro* Neuro::getInput(int i,float &weight) const
+{
+if (i>=getInputCount()) return 0;
+NInput &inp=inputs(i);
+weight=inp.weight;
+return inp.n;
+}
+
+float Neuro::getInputWeight(int i) const
+{
+return inputs(i).weight;
+}
+
+void Neuro::setInputWeight(int i,float 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,float 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;i<owner->getNeuroCount();i++)
+     for(int j=0;j<owner->getNeuro(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(&st_neuroparam,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);
+}
+
+/////// 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;i<neuro.getInputCount();i++)
+	{
+	float w;
+	Neuro *n=neuro.getInput(i,w);
+	if (n->isOldNeuron())
+		{
+		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
+
+///////////////////////////////////////
+
+const SString& Part::getDefaultStyle()
+{static SString s("part"); return s;}
+const SString& Joint::getDefaultStyle()
+{static SString s("joint"); return s;}
+/*
+const SString& Neuro::getDefaultStyle()
+{static SString s("neuro"); return s;}
+const SString& NeuroItem::getDefaultStyle()
+{static SString s("neuroitem"); return s;}
+*/
+const SString& Neuro::getDefaultStyle()
+{static SString s("neuro"); return s;}
+
+Part::Part():PartBase(getDefaultStyle())
+{
+o=Orient_1;
+p=Pt3D_0;
+rot=Pt3D_0;
+flags=0;
+#include "defassign-f0_part.h"
+}
+
+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;
+}
+
+///////////////////////////
+
+Joint::Joint():PartBase(getDefaultStyle())
+{
+rot=Pt3D_0;
+#include "defassign-f0_joint.h"
+d.x=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,0,0);
+}
+
+void Joint::useDelta(int false_or_true)
+{
+usedelta=false_or_true;
+}
+
+int Joint::isDelta()
+{
+return usedelta;
+}
+
+/////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////
+
+#include "f0classes.h"
+
+#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,},
+};
+
+static Param staticparam;
+
+ParamInterface &Part::extraProperties()
+{
+staticparam.setParamTab(f0_part_xtra_paramtab);
+staticparam.select(this);
+return staticparam;
+}
+
+ParamInterface &Joint::extraProperties()
+{
+staticparam.setParamTab(f0_joint_xtra_paramtab);
+staticparam.select(this);
+return staticparam;
+}
+
+ParamInterface &Neuro::extraProperties()
+{
+staticparam.setParamTab(f0_neuro_xtra_paramtab);
+staticparam.select(this);
+return staticparam;
+}
+
+ParamInterface &Part::properties()
+{
+staticparam.setParamTab(f0_part_paramtab);
+staticparam.select(this);
+return staticparam;
+}
+
+ParamInterface &Joint::properties()
+{
+staticparam.setParamTab(usedelta?f0_joint_paramtab:f0_nodeltajoint_paramtab);
+staticparam.select(this);
+return staticparam;
+}
+
+ParamInterface &Neuro::properties()
+{
+staticparam.setParamTab(f0_neuro_paramtab);
+staticparam.select(this);
+return staticparam;
+}
+
+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);
+	}
+};
+
+////////////////////////
+
+NeuroConn::NeuroConn()
+{
+#include "defassign-f0_neuroconn.h"
+}
+
+//////////////////////////////////////
+
+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;}
+
+Param st_neuroparam(f0_neuro_paramtab,0,"NeuroDef");
+Param st_jointparam(f0_joint_paramtab,0,"Joint");
+Param st_partparam(f0_part_paramtab,0,"Part");
+
+
Index: /cpp/gdk/modelparts.h
===================================================================
--- /cpp/gdk/modelparts.h	(revision 5)
+++ /cpp/gdk/modelparts.h	(revision 5)
@@ -0,0 +1,518 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _MODELPARTS_H_
+#define _MODELPARTS_H_
+
+#include "3d.h"
+#include "genoconv.h"
+
+#include "extvalue.h"
+#include "list.h"
+#include "sstring.h"
+#include "sstringutils.h"
+#include "param.h"
+#include "syntparam.h"
+#include "usertags.h"
+#include "paramtabobj.h"
+
+#include <stdio.h>
+
+//#define MODEL_V1_COMPATIBLE
+
+class Model;
+class IRange;
+class MultiRange;
+
+typedef UserTags<Model,void*,5> ModelUserTags;
+
+/** Common base for model elements. */
+class PartBase
+{
+public:
+SString vis_style;
+PartBase(const SString& s):vis_style(s),mapped(0) {}
+~PartBase();
+static const SString& getDefaultStyle(){static SString s("none"); return s;}
+MultiRange *mapped;
+enum PartBaseFlags { Selected=1 };
+long flags;
+Model *owner;	///< backlink to the model
+
+SString info;
+
+Model &getModel() const {return *owner;}
+
+ModelUserTags userdata;
+
+void notifyMappingChange();
+
+void clearMapping();
+MultiRange* getMapping() {return mapped;}
+void setMapping(const IRange &mr);
+void addMapping(const IRange &mr);
+void setMapping(const MultiRange &mr);
+void addMapping(const MultiRange &mr);
+
+void setInfo(const SString& name,const SString& value);
+void setInfo(const SString& name,int value);
+void setInfo(const SString& name,double value);
+SString getInfo(const SString& name);
+};
+
+/// Part is the only real physical object in the framsticks creature.
+/// You can use this class for querying and adjusting constructed
+/// model properties
+class Part: public PartBase
+{
+friend class Model;
+static const SString& getDefaultStyle();
+Part(double _mass,double _size,double _density,double _friction,double _ingest,double _assim)
+	:mass(_mass),size(_size),density(_density),friction(_friction),ingest(_ingest),assim(_assim),
+	PartBase(getDefaultStyle())
+	{}
+public:
+// base properties - have special meaning and therefore are often accessed directly for convenience
+Pt3D p;    ///< 3d coordinates of the part
+Orient o;  ///< orientation in 3d space (rotation matrix)
+/// ParamInterface object is preferred way to get/set other properties.
+ParamInterface &extraProperties();
+ParamInterface &properties();
+long refno;
+Pt3D rot;
+
+///
+double mass,size,density,friction,ingest,assim;
+Pt3D food;
+//SList points; // collistion points
+//Slist neurons; // "select * from owner->neurons where part=this" ;-)
+
+Part();
+Part(const Part& src):PartBase(getDefaultStyle()) {operator=(src);}
+void operator=(const Part& src);
+};
+
+/// Imaginary connection between two parts.
+/// Joint has no mass nor intertia but can transfer forces.
+class Joint: public PartBase
+{
+friend class Model;
+static const SString& getDefaultStyle();
+Joint(double _stamina,double _stif,double _rotstif,double _d)
+	:stamina(_stamina),stif(_stif),rotstif(_rotstif),PartBase(getDefaultStyle())
+	{d=Pt3D(_d,0,0);}
+public:
+// base properties:
+long p1_refno,p2_refno; ///< parts' reference numbers
+
+Part *part1,*part2;	///< references to parts
+class Pt3D d;		///< position delta between parts
+class Pt3D rot;	///< orientation delta between parts expressed as 3 angles
+
+Joint();
+Joint(const Joint& src):PartBase(getDefaultStyle()) {operator=(src);}
+void operator=(const Joint& src);
+
+/** connect two parts with this joint.
+    p2 position will be adjusted if delta option is in effect.
+    @see isDelta()
+  */
+void attachToParts(Part* p1,Part* p2);
+/// @see attachToParts(Part*,Part*)
+void attachToParts(int p1,int p2);
+
+/** discard delta information but don't disable delta flag.
+    delta will be calculated from parts positions during final consistency check.
+ */
+void resetDelta();
+
+/** enable or disable delta option.
+    delta value is not changed.
+ */
+void useDelta(int false_or_true);
+
+/** @return 1 if delta option is in effect.
+    @see useDelta(), resetDelta(), useDelta()
+*/
+int isDelta(); 
+
+/// ParamInterface object is preferred way to get/set other properties.
+ParamInterface &extraProperties();
+ParamInterface &properties();
+
+// do not touch these:
+long refno; ///< this joint's reference number
+double stamina;
+double stif,rotstif;	///< stiffness for moving and bending forces
+class Orient o;	///< orientation delta between parts as rotation matrix
+/** flag: generated f0 should include delta data.
+    set by 'singlestep' if j: attributes use delta option */
+int usedelta;
+};
+
+#define JOINT_DELTA_MARKER 99999.0
+
+////////////////// NN /////////////////
+
+class NeuroClass;
+
+typedef UserTags<NeuroClass,void*,5> NeuroClassUserTags;
+
+/** Information about neuron class.
+ */
+class NeuroClass
+{
+bool ownedvectordata;
+void operator=(const NeuroClass& nosuchthich){}
+  public:
+SString name,longname,description;
+ParamEntry *props;
+long prefinputs,prefoutput;
+long preflocation;
+int *vectordata;
+long visualhints;
+
+void *impl;
+bool active;
+int genactive;
+NeuroClassUserTags userdata;
+
+//////////////////////
+~NeuroClass();
+NeuroClass();
+NeuroClass(ParamEntry *_props,SString _description,
+	   int _prefinputs,int _prefoutput,int _preflocation,int *_vectordata,bool own_vd=1,int vhints=0);
+/** class name for use in Neuro::setClassName(), Neuro::setDetails() (former 'moredata' field),
+    eg. "N","-",G" */
+const SString& getName() {return name;}
+/** human friendly name, eg. "Neuron","Link","Gyroscope"  */
+const SString& getLongName() {return longname;}
+/** long description */
+const SString& getDescription() {return description;}
+ParamEntry* getParamTab() {return props;}
+
+/** NeuroClass specific properties, recognized by all neurons of this class */
+Param getProperties() {return Param(props);}
+
+/** preferred number of inputs, -1 = no preference (any number will go).
+    extra inputs may be ignored by the object (depends on the class).
+ */
+int getPreferredInputs() {return prefinputs;}
+
+/** @return 0 if this object doesn't provide useful output signal. */
+int getPreferredOutput() {return prefoutput;}
+
+/** @return 0 if the object doesn't need any assignment to the body element.
+    @return 1 = it likes to be attached to the Part ( @see Neuro::attachToPart() )
+    @return 2 = the object prefers to have the Joint ( @see Neuro::attachToJoint() )
+ */
+int getPreferredLocation() {return preflocation;}
+/** vector drawing to be used in neuro net diagram.
+    interpretation:
+       {   
+           LEN = datalength (excluding this number) 
+           NL = number_of_lines
+line#1 ->  NS = number_of_segments, x1,y1, x2,y2, ... xNS-1,yNS-1,
+         ...
+line#NL -> NS = number_of_segments, x1,y1, x2,y2, ... xNS-1,yNS-1,
+       }
+ */
+int* getSymbolGlyph()
+ {return vectordata;}
+void setSymbolGlyph(int *data,bool owned=1)
+ {if (vectordata&&ownedvectordata) delete []vectordata;
+ vectordata=data; ownedvectordata=owned;}
+/** additional information about how the neuron should be drawn
+    used by structure view (and maybe some other components).
+    return value is defined by the enum Hint
+    @see enum Hint
+ */
+int getVisualHints()
+ {return visualhints;}
+
+enum Hint
+	/** don't draw neurons of this class */
+ { Invisible=1,
+	/** don't draw classname label below the neuron */
+   DontShowClass=2,
+	/** draw the neuron at the first part when attached to joint (default is in the middle) */
+   AtFirstPart=4,
+	/** draw the neuron at the second part when attached to joint (default is in the middle) */
+   AtSecondPart=8,
+	/** use muscle colour for this neuro unit */
+   MuscleClass=16,
+	/** use receptor colour for this neuro unit */
+   ReceptorClass=32,
+   V1BendMuscle=64,
+   V1RotMuscle=128
+ };
+
+/** textual summary, automatically generated from other properties (like the neuro class tooltip) */
+SString getSummary();
+};
+
+class Neuro;
+
+#ifdef MODEL_V1_COMPATIBLE
+class NeuroItem;
+
+/** for compatibility with old Neuro/NeuroItem  */
+class OldItems
+{
+Neuro &neuro;
+SList syntitems; ///< to be deleted
+SList items;
+int listok;
+  public:
+OldItems(Neuro &n):neuro(n),listok(0) {}
+~OldItems() {freelist();}
+void buildlist();
+void freelist();
+
+int getItemCount();
+NeuroItem *getNeuroItem(int i);
+NeuroItem *addNewNeuroItem();
+int findNeuroItem(NeuroItem *n);
+};
+#endif
+
+/** Single processing unit in framsticks NN.  */
+class Neuro: public PartBase
+{
+friend class Model;
+static const SString& getDefaultStyle();
+
+struct NInput { Neuro *n; double weight; SString *info;
+	NInput(Neuro *_n,double w,SString *i=0):n(_n),weight(w),info(i) {} };
+
+SListTempl<NInput> inputs;
+
+NeuroClass *myclass;
+bool knownclass;
+SString myclassname, myclassparams;
+/** set myclass and make knownclass=true */
+void checkClass();
+
+SString** inputInfo(int i);
+
+public:
+enum NeuroFlags { HoldState=2 };
+ParamInterface &properties();
+ParamInterface &extraProperties();
+
+void setInputInfo(int i,const SString& name,const SString &value);
+void setInputInfo(int i,const SString& name,int value);
+void setInputInfo(int i,const SString& name,double value);
+SString getInputInfo(int i);
+SString getInputInfo(int i,const SString& name);
+
+NeuroClass* getClass();
+void setClass(NeuroClass*);
+
+SString getClassParams() {return myclassparams;}
+void setClassParams(const SString& cp) {myclassparams=cp;}
+
+SString getClassName();
+void setClassName(const SString& clazz);
+
+/** return neuro unit details encoded as <CLASS> ":" <PROPERTIES>
+    
+    new Neuro can be created as root object (without parent) or can be 
+    the child of existing Neuro. Children of the Neuro are its inputs.
+    Standard framsticks neuron calculates the sum of all input units - other processing
+    units don't have to treat them equally and can even ignore some of them.
+    There are hints about expected inputs in the class database, @see getClass
+
+    Application should not assume anything about classes and its properties
+    except for two standard classes: (information about all current classes
+    can be retrieved with getClass/getClassProperties methods)
+    - getClassName()="N" is the standard framsticks neuron, accepts any number of inputs,
+      compatible with old Neuro object
+    - getClassName()="-" is the neuron link, compatible with old Neuro-Neuro link
+      (NeuroItem with empty details)
+    Empty details defaults to "-" if the parent unit is specified,
+    and "N" if the unit has no parent.
+ */
+SString getDetails();
+
+/** details = classname + ":" + classparams
+    @see getDetails()
+ */
+void setDetails(const SString&);
+
+#define STATRICKCLASS Neuro
+PARAMGETDEF(details) {arg1->setString(getDetails());}
+PARAMSETDEF(details) {setDetails(arg1->getString());return PSET_CHANGED;}
+PARAMGETDEF(inputCount);
+PARAMPROCDEF(p_getInputNeuroDef);
+PARAMPROCDEF(p_getInputNeuroIndex);
+PARAMPROCDEF(p_getInputWeight);
+#undef STATRICKCLASS
+
+SyntParam classProperties();
+// base properties:
+long refno; ///< unique reference number (former 'neuro' refno)
+
+long part_refno; ///< can be used by some items as the part ref#
+long joint_refno; ///< can be used by some items as the joint ref#
+
+Pt3D pos,rot;	///< default = zero
+
+ModelUserTags userdata;
+
+Neuro();
+Neuro(double _state,double _inertia,double _force,double _sigmo);
+Neuro(const Neuro& src):PartBase(getDefaultStyle()) {operator=(src);}
+
+~Neuro();
+
+void operator=(const Neuro& src);
+
+/** Attach this Neuro to the specified Part or detach it from the body if p==NULL.
+    Neuro can be attached to either Part or Joint, but not both.
+    @see getPart()
+ */
+void attachToPart(Part* p) {part=p; joint=0;}
+
+/** Attach this Neuro to the specified Joint or detach it from the body if p==NULL.
+    Neuro can be attached to either Part or Joint, but not both.
+    @see getJoint()
+ */
+void attachToJoint(Joint* j) {joint=j; part=0;}
+
+void attachToPart(int i);
+void attachToJoint(int i);
+
+/** @return Part the Neuro is attached to, or NULL if it has no defined location on the body.
+    @see attachToPart()
+ */
+Part *getPart() {return part;}
+
+/** @return Joint the Neuro is attached to, or NULL if it has no defined location on the body.
+    @see attachToJoint()
+ */
+Joint *getJoint() {return joint;}
+
+int isOldEffector();
+int isOldReceptor();
+int isOldNeuron();
+int isNNConnection();
+
+/** @return the number of inputs connected to this Neuro.
+    Functions like getInput(), getInputWeight() will accept connection number [0..InputCount-1]
+ */
+int getInputCount() const {return inputs.size();}
+
+/// @return the number of output connections (including possible self-connections)
+int getOutputsCount() const;
+
+/** @return the Neuro connected as i-th input */
+Neuro* getInput(int i) const {return (i>=inputs.size())?0:inputs(i).n;}
+/** @return the Neuro connected as i-th input.
+    @param weight
+ */
+Neuro* getInput(int i,float &weight) const;
+/** @return connectin weight for i-th input */
+float getInputWeight(int i) const;
+/** change connection weight for i-th input */
+void setInputWeight(int i,float weight);
+/** connect i-th input with another neuron */
+void setInput(int i,Neuro*n);
+/** connect i-th input with another neuron */
+void setInput(int i,Neuro*n,float weight);
+/** add new input. @return its reference number */
+int addInput(Neuro* child,float weight=1.0,const SString* info=0);
+/** @return reference number [0..InputCount-1] of the input
+   or -1 if 'child' is not connected with this Neuro.*/
+int findInput(Neuro* child) const;
+void removeInput(int refno);
+/**    @return reference number of the child connection, like findInput() */
+int removeInput(Neuro* child);
+
+int findInputs(SList& result,const char* classname=0,const Part* part=0,const Joint* joint=0) const;
+int findOutputs(SList& result,const char* classname=0,const Part* part=0,const Joint* joint=0) const;
+
+/* class database retrieval */
+static int getClassCount();
+/** @return Neuro class name.
+    @param classindex 0 .. getClassCount()
+ */
+static SString getClassName(int classindex);
+static NeuroClass* getClass(int classindex);
+static NeuroClass* getClass(const SString& classname);
+static int getClassIndex(const NeuroClass*nc);
+
+#ifdef MODEL_V1_COMPATIBLE
+friend class OldItems;
+long neuro_refno; ///< parent ref# (called neuro_refno for compatibility with old Neuro class), @see moredata
+long conn_refno; ///< the other neuron ref# in N-N connections, can be used by some other items
+double weight; ///< weight of the N-N connection and (all?) receptors
+double inertia,force,sigmo; //!!!
+
+/** @deprecated provided only for compatibility with old Neuro/NeuroItem classes.
+    use getInputCount() instead. @sa getInputCount() */
+int getItemCount() {return oldItems().getItemCount();}
+
+/** @deprecated provided only for compatibility with old Neuro/NeuroItem classes.
+    use getInput() instead. @sa getInput() */
+NeuroItem* getNeuroItem(int i) {return oldItems().getNeuroItem(i);}
+#endif
+
+  protected:
+#ifdef MODEL_V1_COMPATIBLE
+/** old Neuro compatibility */
+OldItems* olditems;
+OldItems& oldItems() {if (!olditems) olditems=new OldItems(*this); return *olditems;}
+void invalidateOldItems() {if (olditems) olditems->freelist();}
+#endif
+
+  public:
+
+// not really private, but you should not access those directly
+double state;
+
+/** may reference parent neuron if parentcount is exacty 1. parent is invalid otherwise. @sa parentcount */
+Neuro *parent;
+int parentcount; ///< @sa parent
+
+Part *part;	///< link to the Part
+Joint *joint;	///< link to the Joint - required by some objects (eg.muscles)
+Orient o;	///< rotation matrix calculated from "rot"
+static ParamEntry emptyParamTab[];
+};
+
+#ifdef MODEL_V1_COMPATIBLE
+class NeuroItem;
+
+/// for compatibility with old NeuroItem class.
+class NeuroItem: public Neuro
+{
+public:
+NeuroItem() {}
+};
+#endif
+
+class NeuroExt: public Neuro
+{
+  public:
+#define STATRICKCLASS NeuroExt
+PARAMGETDEF(neuroclass);
+PARAMSETDEF(neuroclass);
+#undef STATRICKCLASS
+static ParamEntry *getParamTab();
+};
+
+class NeuroConn
+{
+  public:
+int n1_refno,n2_refno;
+double weight;
+SString info;
+NeuroConn();
+};
+
+extern ParamEntry f0_part_paramtab[],f0_joint_paramtab[],f0_nodeltajoint_paramtab[],f0_neuro_paramtab[],f0_neuroconn_paramtab[],f0_neuroitem_paramtab[];
+extern Param st_neuroparam,st_jointparam,st_partparam;
+
+#endif
Index: /cpp/gdk/multimap.cpp
===================================================================
--- /cpp/gdk/multimap.cpp	(revision 5)
+++ /cpp/gdk/multimap.cpp	(revision 5)
@@ -0,0 +1,330 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "multimap.h"
+#include <stdio.h>
+
+int MultiMap::getBegin() const
+{
+if (isEmpty()) return 0;
+return getBegin(0);
+}
+
+int MultiMap::getEnd() const
+{
+if (isEmpty()) return -1;
+return getBegin(mappingCount()-1)-1;
+}
+
+int MultiMap::findData(int x) const
+{
+if (isEmpty()) return -1;
+if (getBegin(0)>x) return -1;
+int a,b,c;
+int n=mappingCount()-1;
+a=0; b=n; // find c = last range with begin<=x
+while(1){
+	c=(a+b+1)/2;
+	if (getBegin(c)<=x)
+		{
+		if ((c==n)||(getBegin(c+1)>x)) return c;
+		a=c;
+		}
+	else
+		{
+		b=c-1;
+		}
+	}
+}
+
+int MultiMap::addRange(int &r,const MultiRange& mr)
+{
+// precondition: 0 <= r < (mappingCount()-1)
+// 1.maybe change mapping in this range
+int ret=0;
+SingleMapping *sm=getMapping(r);
+if (sm->to.contains(mr)) return 0; // do nothing
+sm->to.add(mr);
+// after adding mr to this mapping it could be the same as the previous/next one
+if (r>0) // prev exists
+	{
+	SingleMapping *prev=getMapping(r-1);
+	if (prev->to == sm->to)
+		{ // splice with prev
+		removeData(r);
+		delete sm;
+		sm=prev;
+		r--;
+		ret--;
+		}
+	}
+if (r<(mappingCount()-2)) // next exists
+	{
+	SingleMapping *next=getMapping(r+1);
+	if (next->to == sm->to)
+		{ // splice with next
+		removeData(r+1);
+		delete next;
+		ret--;
+		r--;
+		}
+	}
+return ret;
+}
+
+int MultiMap::addRangeBeginEnd(int &r,int begin,int end,const MultiRange& mr)
+{
+// precondition: -1 <= r < mappingCount()
+//               begin <= end
+//               begin >= mapping.begin
+//               end < nextmapping.begin
+SingleMapping *m,*m2,*m1;
+if (r<0)
+	{
+	if (mappingCount())
+		{
+		m=getMapping(0);
+		if (end==(m->begin-1))
+			{ // adjacent to m
+			if (m->to==mr)
+				{ // shift only
+				m->begin=begin;
+				return 0;
+				}
+			// single add
+			SingleMapping *newmap=new SingleMapping(begin,mr);
+			addData(0,newmap);
+			r=0;
+			return 1;
+			}
+		}
+	// double add
+	SingleMapping *newmap=new SingleMapping(begin,mr);
+	SingleMapping *newmap2=new SingleMapping(end+1);
+	addData(0,newmap);
+	addData(1,newmap2);
+	r=1;
+	return 2;
+	}
+
+if (r==(mappingCount()-1))
+	{
+	m=getMapping(r);
+	m1=getMapping(r-1);
+	if (begin==m->begin)
+		{ // adjacent
+		if (m1->to==mr)
+			{ // shift only
+			m->begin=end+1;
+			return 0;
+			}
+		// single add
+		m->begin=end+1;
+		SingleMapping *newmap=new SingleMapping(begin,mr);
+		addData(r,newmap);
+		return 1;
+		}
+	// double add
+	SingleMapping *newmap=new SingleMapping(begin,mr);
+	SingleMapping *newmap2=new SingleMapping(end+1);
+	addData(r+1,newmap);
+	addData(r+2,newmap2);
+	r+=2;
+	return 2;
+	}
+
+m=getMapping(r);
+if (m->to.contains(mr)) return 0;
+if (begin==m->begin) // begin at range boundary
+	{
+	m2=getMapping(r+1);
+	if (end==(m2->begin-1)) return addRange(r,mr);
+
+	SingleMapping *newmap=new SingleMapping(begin,m->to);
+	newmap->to.add(mr);
+	if (r>0)
+		{ // join prev possible...
+		m1=getMapping(r-1);
+		if (m1->to==newmap->to)
+			{ // joint prev = shift
+			delete newmap;
+			m->begin=end+1;
+			return 0;
+			}
+		}
+	// single add:
+	m->begin=end+1;
+	addData(r,newmap);
+	return 1;
+	}
+
+m2=getMapping(r+1);
+if (end==(m2->begin-1)) // end at range boundary
+	{
+	SingleMapping *newmap=new SingleMapping(begin,m->to);
+	newmap->to.add(mr);
+	if (r<(mappingCount()-2))
+		{ // join next possible...
+		if (m2->to==newmap->to)
+			{ // joint next = shift
+			m2->begin=begin;
+			delete newmap;
+			return 0;
+			}
+		}
+	// single add
+	r++;
+	addData(r,newmap);
+	return 1;
+	}
+// double add:
+SingleMapping *newmap=new SingleMapping(begin,m->to);
+newmap->to.add(mr);
+SingleMapping *newmap2=new SingleMapping(end+1,m->to);
+addData(r+1,newmap);
+addData(r+2,newmap2);
+r+=2;
+return 2;
+}
+
+void MultiMap::add(int begin,int end,const MultiRange& to)
+{
+if (to.isEmpty()) return;
+if (end<begin) return;
+int r1=findData(begin);
+int r2=findData(end);
+if (r1==r2)
+	{
+	addRangeBeginEnd(r1,begin,end,to);
+	}
+else
+	{
+	r2+=addRangeBeginEnd(r1,begin,getBegin(r1+1)-1,to);
+	r1++;
+	for (;r1<r2;r1++)
+		r2+=addRange(r1,to);
+	addRangeBeginEnd(r1,getBegin(r1),end,to);
+	}
+}
+
+const MultiRange& MultiMap::map(int x) const
+{
+static MultiRange empty;
+int m=findData(x);
+if (m<0) return empty;
+SingleMapping *sm=getMapping(m);
+return sm->to;
+}
+
+MultiRange MultiMap::map(int begin,int end) const
+{
+MultiRange mr;
+int m=findData(begin);
+for (;m<rangeCount();m++)
+	if (m>=0)
+	{
+	SingleMapping *sm=getMapping(m);
+	if (sm->begin > end) break;
+	mr.add(sm->to);
+	}
+return mr;
+}
+
+MultiRange MultiMap::map(const MultiRange& ranges) const
+{
+MultiRange mr;
+for(int i=0;i<ranges.rangeCount();i++)
+	mr.add(map(ranges.getRange(i)));
+return mr;
+}
+
+IRange MultiMap::getRange(int i) const
+{
+if ((i<0)||(i>(data.size()-1))) return IRange();
+return IRange(getBegin(i),getBegin(i+1)-1);
+}
+
+void MultiMap::operator=(const MultiMap& mm)
+{
+clear();
+for(int i=0;i<mm.mappingCount();i++)
+	addData(i,new SingleMapping(*mm.getMapping(i)));
+}
+
+void MultiMap::addCombined(const MultiMap& m1,const MultiMap& m2)
+{
+for(int i=0;i<m1.rangeCount();i++)
+	{
+	IRange r=m1.getRange(i);
+	add(r,m2.map(m1.getMapping(i)->to));
+	}
+}
+
+void MultiMap::add(const MultiRange& from,const MultiRange& to)
+{
+for(int i=0;i<from.rangeCount();i++)
+	add(from.getRange(i),to);
+}
+
+void MultiMap::addReversed(const MultiMap& m)
+{
+for(int i=0;i<m.rangeCount();i++)
+	{
+	IRange r=m.getRange(i);
+	const MultiRange& mr=m.getMapping(i)->to;
+	for (int j=0;j<mr.rangeCount();j++)
+		add(mr.getRange(j),r);
+	}
+}
+
+MultiMap::~MultiMap()
+{ clear();}
+
+void MultiMap::clear()
+{
+for(int i=0;i<data.size();i++)
+	delete getData(i);
+data.clear();
+}
+
+///////////////////
+
+void MultiMap::print() const
+{
+printf("{ ");
+for (int i=0;i<(mappingCount()-1);i++)
+	{
+	if (i) printf("  ");
+	SingleMapping *sm=getMapping(i);
+	SingleMapping *sm2=getMapping(i+1);
+	if (sm2->begin==sm->begin+1)
+		printf("[%d] -> ",sm->begin);
+	else
+		printf("[%d-%d] -> ",sm->begin,sm2->begin-1);
+	sm->to.print();
+	printf("\n");
+	}
+printf("}\n");
+}
+
+void MultiMap::print2() const
+{
+int y;
+int id=0,id2;
+if (isEmpty())
+	{
+	printf("{ empty }\n");
+	return;
+	}
+printf("{\n");
+for (y=getBegin();y<=getEnd();y++)
+	{
+	id2=findMappingId(y+1);
+	printf("%2d %c",y,(id2!=id)?'_':' ');
+	id=id2;
+	map(y).print2();
+	printf("\n");
+	}
+printf("}\n");
+}
Index: /cpp/gdk/multimap.h
===================================================================
--- /cpp/gdk/multimap.h	(revision 5)
+++ /cpp/gdk/multimap.h	(revision 5)
@@ -0,0 +1,76 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _MULTIMAP_H_
+#define _MULTIMAP_H_
+
+#include "multirange.h"
+
+class SingleMapping
+{
+  public:
+SingleMapping(int b,const MultiRange& t):begin(b),to(t) {}
+SingleMapping(int b):begin(b) {}
+SingleMapping(const SingleMapping& sm):begin(sm.begin),to(sm.to) {}
+int begin;
+MultiRange to;
+};
+
+/** MultiMap - used for conversion mapping.
+    see @ref convmap
+  */
+class MultiMap
+{
+/** list of (SingleMapping*) */
+SList data;
+
+SingleMapping* getData(int i) const {return (SingleMapping*)data(i);}
+void addData(int i,SingleMapping* mapping) {data.insert(i,(void*)mapping);}
+void removeData(int i) {data.remove(i);}
+int findData(int x) const;
+int getBegin(int i) const {return getData(i)->begin;}
+
+// addRangeXXX return the shift for range numbers > r
+int addRange(int &r,const MultiRange& mr);
+// value of 'r' is adjusted according to its range number change
+int addRangeBeginEnd(int &r,int begin,int end,const MultiRange& mr);
+
+  public:
+MultiMap() {}
+MultiMap(const MultiMap& mm) {operator=(mm);}
+~MultiMap();
+void operator=(const MultiMap& mm);
+
+void clear();
+int isEmpty() const {return data.size()==0;}
+int mappingCount() const {return data.size();}
+SingleMapping* getMapping(int i) const {return (SingleMapping*)getData(i);}
+int findMappingId(int x) const {return findData(x);}
+int rangeCount() const {return isEmpty()?0:data.size()-1;}
+IRange getRange(int i) const;
+
+int getBegin() const;
+int getEnd() const;
+
+void add(const IRange& from,const IRange& to) {add(from.begin, from.end, MultiRange(to));}
+void add(const IRange& from,const MultiRange& to) {add(from.begin, from.end, to);}
+void add(int from1,int from2,int to1,int to2) {add(from1,from2,MultiRange(to1,to2));}
+void add(int from1,int from2,const MultiRange& to);
+void add(const MultiRange& from,const MultiRange& to);
+void add(const MultiMap& mm);
+void addCombined(const MultiMap& m1,const MultiMap& m2);
+void addReversed(const MultiMap& mm);
+
+const MultiRange& map(int x) const;
+MultiRange map(int begin,int end) const;
+MultiRange map(const IRange& range) const {return map(range.begin, range.end);}
+MultiRange map(const MultiRange& ranges) const;
+
+void print() const;
+void print2() const;
+};
+
+#endif
+
+
Index: /cpp/gdk/multiparamload.cpp
===================================================================
--- /cpp/gdk/multiparamload.cpp	(revision 5)
+++ /cpp/gdk/multiparamload.cpp	(revision 5)
@@ -0,0 +1,264 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "multiparamload.h"
+#include "framsg.h"
+#include <ctype.h>
+
+void MultiParamLoader::init()
+{
+file=0; ownfile=0;
+status=0;
+reset();
+}
+
+void MultiParamLoader::reset()
+{
+status=0;
+breakcond=OnError;
+emptyparam.setParamTab(empty_paramtab);
+}
+
+void MultiParamLoader::load()
+{
+clearstack();
+if (!file)
+	{
+	lasterror="can't open file";
+	status=OnError;
+	return;
+	}
+status=Loading;
+}
+
+void MultiParamLoader::abort()
+{
+if (file && ownfile)
+	{
+	fclose(file);
+	file=0;
+	}
+clearstack();
+status=Finished;
+}
+
+void MultiParamLoader::load(VirtFILE *f)
+{
+abort();
+ownfile=0;
+file=f;
+load();
+}
+
+void MultiParamLoader::load(const char* filename)
+{
+abort();
+ownfile=1;
+file=Vfopen(filename,FOPEN_READ);
+load();
+}
+
+static int isEOL(char ch)
+{
+return (ch=='\n')||(ch=='\r');
+}
+
+static char* fgets0(char*t,int d,VirtFILE *f,int &linlen)
+{
+char *r=fgets(t,d,f);
+if (r)
+	{
+	int d=strlen(r);
+	if (d && isEOL(r[d-1])) { d--; if (d && isEOL(r[d-1])) d--; }
+	linlen=d;
+	r[d]=0;
+	}
+else
+	linlen=0;
+return r;
+}
+
+static char* trim(char*t,int &linlen)
+{
+char *x=t;
+while(isspace(*x)) x++;
+linlen-=(x-t);
+t=x;
+if (!linlen) return t;
+x=t+linlen-1;
+while(isspace(*x)) x--;
+x[1]=0;
+linlen=x-t+1;
+return t;
+}
+
+int MultiParamLoader::go()
+{
+char buf[100];
+char *t;
+int linlen;
+if (status==OnError) return status;
+while (!finished())
+	{
+	if ((status==BeforeObject) || ((status==BeforeUnknown)&&lastclass))
+		{
+		lastclass->load(file);
+		if (maybeBreak(AfterObject))
+			break;
+		continue;
+		}
+	else if (status==BeforeUnknown)
+		{
+		loadObjectNow(&emptyparam);
+		continue;
+		}
+	t=fgets0(buf,100,file,linlen);
+	if (!t)
+		{
+		if (!returnFromIncluded())
+			{
+			abort();
+			break;
+			}
+		else
+			continue;
+		}
+	if (buf[0]=='#')
+		{
+		if (!strncmp(buf+1,"include",7))
+			{
+			const char* t=strchr(buf,'\"'),*t2=0;
+			if (t) t2=strchr(t+1,'\"');
+			if (t2)
+				{
+				SString filename(t+1,t2-t-1);
+				include(filename);
+				}
+			else
+				{
+				const char* thisfilename=file->VgetPath();
+				FMprintf("MultiParamLoader","go",FMLV_WARN,"invalid \"%s\"%s%s",buf,
+					    (thisfilename?" in ":""),(thisfilename?thisfilename:""));
+				}
+			continue;
+			}
+		else if (maybeBreak(OnComment))
+			{
+			lastcomment=t+1;
+			break;
+			}
+		}
+	t=trim(buf,linlen);
+	if ((linlen>1)&&(t[linlen-1]==':'))
+		{
+		lastunknown=0;
+		lastunknown.append(t,linlen-1);
+		lastclass=0;
+		FOREACH(ParamInterface*,pi,params)
+			{
+			if (!strcmp(pi->getName(),lastunknown)) { lastclass=pi; break; }
+			}
+			if (lastclass)
+				{
+				if (maybeBreak(BeforeObject))
+					break;
+				}
+			else
+				{
+				if (maybeBreak(BeforeUnknown))
+					break;
+				}
+		
+		}
+	}
+return status;
+}
+
+bool MultiParamLoader::alreadyIncluded(const char* filename)
+{
+int i;
+const char* t;
+for(i=0;i<filestack.size();i++)
+	{
+	t=filestack(i)->VgetPath();
+	if (!t) continue;
+	if (!strcmp(filename,t)) return true;
+	}
+return false;
+}
+
+void MultiParamLoader::include(SString& filename)
+{
+const char* thisfilename=file->VgetPath();
+SString newfilename;
+const char* t=thisfilename?strrchr(thisfilename,PATHSEPARATORCHAR):0;
+
+if (thisfilename && t)
+	{
+	newfilename.append(thisfilename,t-thisfilename+1);
+	newfilename+=filename;
+	}
+else
+	newfilename=filename;
+
+if (alreadyIncluded(newfilename))
+	{
+	FMprintf("MultiParamLoader","include",FMLV_WARN,"circular reference ignored (\"%s\")",
+		    (const char*)filename);
+	return;
+	}
+
+VirtFILE *f=Vfopen(newfilename,FOPEN_READ);
+if (!f)
+	{
+	FMprintf("MultiParamLoader","include",FMLV_WARN,"\"%s\" not found",(const char*)newfilename);
+	}
+else
+	{
+	filestack+=file;
+	file=f;
+	}
+}
+
+VirtFILE* MultiParamLoader::popstack()
+{
+if (!filestack.size()) return 0;
+VirtFILE* f=filestack(filestack.size()-1);
+filestack.remove(filestack.size()-1);
+return f;
+}
+
+void MultiParamLoader::clearstack()
+{
+VirtFILE *f;
+while(f=popstack()) fclose(f);
+}
+
+bool MultiParamLoader::returnFromIncluded()
+{
+if (!filestack.size()) return false;
+if (file) fclose(file);
+file=popstack();
+return true;
+}
+
+int MultiParamLoader::loadObjectNow(ParamInterface *pi)
+{
+pi->load(file);
+status=AfterObject;
+return 0;
+}
+
+int MultiParamLoader::run()
+{
+int stat;
+breakOn(OnError);
+while(stat=go())
+	if (stat==OnError)
+		{
+		abort();
+		return 0;
+		}
+return 1;
+}
Index: /cpp/gdk/multiparamload.h
===================================================================
--- /cpp/gdk/multiparamload.h	(revision 5)
+++ /cpp/gdk/multiparamload.h	(revision 5)
@@ -0,0 +1,110 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _MULTIPARAMLOAD_H_
+#define _MULTIPARAMLOAD_H_
+
+#include <stdio.h>
+#include "param.h"
+#include "virtfile.h"
+
+/** "param" file parser for loading multiple objects.
+    The loader can be configured to recognize multiple object types from object headers
+    and automatically call ParamInterface::load for matching class.
+    By using MultiParamLoader::go() function you can receive status events, they can be
+    used to handle multiple object instances or parse complex files (see loadtest.cpp sample code).
+    A simple MultiParamLoader::run() can be used if you need any events.
+ */
+class MultiParamLoader
+{
+VirtFILE *file;
+SListTempl<VirtFILE*> filestack;
+char ownfile;
+SList params;
+int status;
+SString lasterror, lastcomment, lastunknown;
+ParamInterface *lastclass;
+int breakcond;
+Param emptyparam;
+
+void init();
+void load();
+
+int maybeBreak(int cond)
+{ status=cond; return breakcond & cond; }
+
+VirtFILE* popstack();
+void clearstack();
+
+  public:
+MultiParamLoader() {init();}
+MultiParamLoader(VirtFILE *f) {init(); load(f);}
+MultiParamLoader(const char* filename) {init(); load(filename);}
+
+~MultiParamLoader() {abort();}
+
+void reset();
+
+void load(VirtFILE *f);
+void load(const char* filename);
+
+/** register the object class. classes' names will be matched with object headers ("xxx:" in the file) */
+void addClass(ParamInterface *pi) {params+=pi;}
+void removeClass(ParamInterface *pi) {params-=pi;}
+void clearClasses() {params.clear();}
+
+/** to be used in the main loop: while(event=loader.go()) { ... }
+    loader.go() will return on specified events (@see breakOn(), noBreakOn())
+    then you can handle the event and resume loading
+ */
+virtual int go();
+/** same value as 'go()' */
+int getStatus() {return status;}
+int finished() {return (status==Finished);}
+
+VirtFILE *getFile() {return file;}
+
+/** abort immediately and close the file if needed */
+void abort();
+/** @param conditions can be combined bitwise, eg. MultiParamLoader::BeforeObject |  MultiParamLoader::OnComment
+    @see BreakConfitions
+*/
+void breakOn(int conditions) {breakcond|=conditions;}
+void noBreakOn(int conditions) {breakcond&=~conditions;}
+/**
+   - BeforeObject: found an object with recognized classname
+   - AfterObject: the object was loaded into the registered class interface
+   - BeforeUnknown: unknown (not registered) object header detected.
+@see getClass(), GetClassName()
+ */
+enum BreakConditions { Finished=0, BeforeObject=1, AfterObject=2, 
+		       BeforeUnknown=4, OnComment=8, OnError=16, Loading=32 };
+
+/** can be used BeforeObject and AfterObject */
+ParamInterface *getClass() {return lastclass;}
+/** can be used BeforeUnknown, BeforeObject, AfterObject */
+const SString& getClassName() {return lastunknown;}
+/** unknown object will be loaded if you set its class BeforeUnknown */
+void setClass(ParamInterface *pi) {lastclass=pi;}
+/** can be used OnComment */
+const SString& getComment() {return lastcomment;}
+/** can be used OnError */
+const SString& getError() {return lasterror;}
+/** can be used BeforeObject and BeforeUnknown */
+int loadObjectNow(ParamInterface *pi);
+/** can be used BeforeObject */
+int loadObjectNow() {return loadObjectNow(getClass());}
+/** can be used BeforeObject and BeforeUnknown.
+    object data will not be loaded. */
+int skipObject() {return loadObjectNow(&emptyparam);}
+/** @return 1 if no errors */
+int run();
+
+void include(SString& filename);
+bool returnFromIncluded();
+bool alreadyIncluded(const char* filename);
+
+};
+
+#endif
Index: /cpp/gdk/multirange.cpp
===================================================================
--- /cpp/gdk/multirange.cpp	(revision 5)
+++ /cpp/gdk/multirange.cpp	(revision 5)
@@ -0,0 +1,316 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "multirange.h"
+
+#include <stdio.h>
+
+int IRange::operator==(const IRange& r)
+{
+if (isEmpty()&&r.isEmpty()) return 1;
+return (begin==r.begin)&&(end==r.end);
+}
+
+void IRange::intersect(const IRange& r)
+{
+if (r.begin>begin) begin=r.begin;
+if (r.end<end) end=r.end;
+}
+void IRange::add(const IRange& r)
+{
+if (r.begin<begin) begin=r.begin;
+if (r.end>end) end=r.end;
+}
+
+void IRange::print() const
+{
+if (begin==end) printf("[%d]",begin);
+else printf("[%d-%d]",begin,end);
+}
+
+////////////////////////////////////////
+
+void MultiRange::print() const
+{
+printf("[");
+for (int i=0;i<data.size();i+=2)
+	{
+	int b=getData(i);
+	int e=getData(i+1);
+	if (i) printf(",");
+	if (b==e) printf("%d",b);
+	else printf("%d-%d",b,e);
+	}
+printf("]");
+}
+
+void MultiRange::print2() const
+{
+const IRange& r=singleRange();
+for(int i=0;i<=r.end;i++)
+	printf(contains(i)?"X":".");
+}
+
+void MultiRange::shift(int delta)
+{
+for(int i=0;i<data.size();i++)
+	data.get(i)+=delta;
+}
+
+int MultiRange::findRange(int x) const
+{
+if (isEmpty()) return -1;
+if (getData(0)>x) return -1;
+int a,b,c;
+int n=rangeCount()-1;
+a=0; b=n; // find c = last range with begin<=x
+while(1){
+	c=(a+b+1)/2;
+	if (getBegin(c)<=x)
+		{
+		if ((c==n)||(getBegin(c+1)>x)) return c;
+		a=c;
+		}
+	else
+		{
+		b=c-1;
+		}
+	}
+}
+
+void MultiRange::addRange(int i,int b,int e)
+{
+data.insert(2*i,b);
+data.insert(2*i+1,e);
+}
+
+void MultiRange::removeRanges(int r1,int r2)
+{
+//data.remove(2*r1,(r2-r1)*2+2);
+for (;r2>=r1;r2--)
+	removeRange(r2);
+}
+
+void MultiRange::removeRange(int i)
+{
+data.remove(2*i,2);
+}
+
+void MultiRange::clear()
+{data.clear();}
+
+int MultiRange::isEmpty() const
+{
+return rangeCount()==0;
+}
+
+IRange MultiRange::singleRange() const
+{
+if (isEmpty()) return IRange();
+int b=getData(0);
+int e=getData(data.size()-1);
+return IRange(b,e);
+}
+
+int MultiRange::rangeCount() const
+{
+return data.size()/2;
+}
+
+IRange MultiRange::getRange(int i) const
+{
+if ((i<0)||(i>=rangeCount())) return IRange();
+return IRange(getData(2*i),getData(2*i+1));
+}
+
+void MultiRange::remove(int begin, int end)
+{
+if (end<begin) return; // NOP
+int count=rangeCount();
+if (!count) return;
+int r1=findRange(begin);
+int r2=findRange(end);
+if (r2<0) return; // NOP
+if (r1==r2)
+	{
+	int e=getEnd(r1);
+	int b=getBegin(r1);
+	if (begin<=e)
+		{
+		if (end>=e)
+			{
+			if (begin>b)
+				setEnd(r1,begin-1);
+			else
+				removeRange(r1);
+			}
+		else
+			{
+			if (begin>b)
+				{ //split
+				addRange(r1+1,end+1,e);
+				setEnd(r1,begin-1);
+				}
+			else
+				{
+				setBegin(r1,end+1);
+				}
+			}
+		}
+	}
+else
+	{
+	if (r1>=0)
+		{
+		int e1=getEnd(r1);
+		int b1=getBegin(r1);
+		if (begin<=e1)
+			{
+			if (begin==b1)
+				{
+				removeRange(r1);
+				r2--;
+				r1--;
+				}
+			else
+				{
+				setEnd(r1,begin-1);
+				}
+			}
+		}
+	int e2=getEnd(r2);
+	if (end<e2)
+		{
+		setBegin(r2,end+1);
+		removeRanges(r1+1,r2-1);
+		}
+	else
+		{
+		removeRanges(r1+1,r2);
+		}
+	}
+}
+
+void MultiRange::add(int begin, int end)
+{
+if (end<begin) return; // NOP
+int count=rangeCount();
+int last=count-1;
+int r1=findRange(begin);
+int r2=findRange(end);
+if (r2<0) // special case: before first range
+	{
+	if (count&&(getData(0)==(end+1)))
+		setData(0,begin);
+	else
+		addRange(0,begin,end);
+	return;
+	}
+if (r1<0) // special case: begin is before first range
+	{
+	setData(0,begin);
+	r1=0;
+	}
+// now r1>=0 and r2>=0
+int joinbegin=(begin<=(getEnd(r1)+1));
+int joinend=(r2<last)&&(end>=(getBegin(r2+1)-1));
+const int SAME=1;
+const int JOINBEGIN=2;
+const int JOINEND=4;
+int action=((r1==r2)?SAME:0)+(joinbegin?JOINBEGIN:0)+(joinend?JOINEND:0);
+switch(action)
+	{
+	case SAME+JOINBEGIN+JOINEND: // remove 1 range
+		setEnd(r1,getEnd(r1+1));
+		removeRange(r1+1);
+		break;
+	case SAME+JOINBEGIN: // extend 1 range
+		setEnd(r1,max(getEnd(r2),end));
+		break;
+	case SAME+JOINEND: // extend 1 range
+		setBegin(r1+1,begin);
+		break;
+	case SAME: // add 1 range
+		addRange(r1+1,begin,end);
+		break;
+
+	case JOINBEGIN+JOINEND: // extend r2+1
+		setBegin(r2+1,getBegin(r1));
+		removeRanges(r1,r2);
+		break;
+	case JOINBEGIN: // extend r1
+		setEnd(r1,max(end,getEnd(r2)));
+		removeRanges(r1+1,r2);
+		break;
+	case JOINEND: // extend r2+1
+		setBegin(r2+1,begin);
+		removeRanges(r1+1,r2);
+		break;
+	case 0: // extend r2
+		setBegin(r2,begin);
+		setEnd(r2,max(end,getEnd(r2)));
+		removeRanges(r1+1,r2-1);
+		break;
+	}
+}
+
+void MultiRange::remove(const MultiRange &mr)
+{
+for(int i=0;i<mr.rangeCount();i++)
+	{
+	IRange r=mr.getRange(i);
+	remove(r);
+	}
+}
+
+void MultiRange::add(const MultiRange &mr)
+{
+for(int i=0;i<mr.rangeCount();i++)
+	{
+	IRange r=mr.getRange(i);
+	add(r);
+	}
+}
+
+void MultiRange::intersect(const MultiRange &mr)
+{
+// = this - (1-mr)
+MultiRange full(singleRange());
+full.remove(mr);
+remove(full);
+}
+
+int MultiRange::contains(const MultiRange &mr) const
+{
+for(int i=0;i<mr.rangeCount();i++)
+	{
+	IRange r=mr.getRange(i);
+	if (!contains(r)) return 0;
+	}
+return 1;
+}
+
+int MultiRange::contains(int x) const
+{
+int r=findRange(x);
+if (r<0) return 0;
+return getEnd(r)>=x;
+}
+
+int MultiRange::contains(const IRange& r) const
+{
+if (r.isEmpty()) return 0;
+int r1=findRange(r.begin);
+if (r1<0) return 0;
+return getRange(r1).contains(r);
+}
+
+void MultiRange::intersect(int begin, int end)
+{
+if (isEmpty()) return;
+if (end<begin) {clear(); return;}
+IRange sr=singleRange();
+remove(sr.begin, begin-1);
+remove(end+1, sr.end);
+}
Index: /cpp/gdk/multirange.h
===================================================================
--- /cpp/gdk/multirange.h	(revision 5)
+++ /cpp/gdk/multirange.h	(revision 5)
@@ -0,0 +1,104 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _MULTIRANGE_H_
+#define _MULTIRANGE_H_
+
+#include "list.h"
+
+/**
+   range in integer domain.
+   - (a,a) contains single integer: a
+   - (a,b) contains [b-a+1] integers
+ */
+class IRange
+{
+  public:
+int begin,end;
+IRange():begin(0),end(0) {}
+IRange(int b,int e):begin(b),end(e) {}
+IRange(const IRange& r):begin(r.begin),end(r.end) {}
+int size() const {return end-begin+1;}
+int isEmpty() const {return end<begin;}
+void makeEmpty() {end=begin;}
+void set(int b,int e) {begin=b; end=e;}
+void intersect(const IRange& r);
+void add(const IRange& r);
+/** all empty ranges are equal */
+int operator==(const IRange& r);
+void operator=(const IRange& r) {begin=r.begin; end=r.end;}
+int contains(int x) {return (x>=begin)&&(x<=end);}
+int contains(const IRange& r) {return !r.isEmpty()&&contains(r.begin)&&contains(r.end);}
+void print() const;
+};
+
+/** set of ranges = multiple selection. used in conversion mapping. see @ref convmap */
+class MultiRange
+{
+/** subsequent ranges in array, stored as: {begin1,end1,begin2,end2,...}
+    there are data.size()/2 ranges.
+    all ranges are sorted by 'begin' value.
+    ranges cannot intersect.
+ */
+SListTempl<int> data;
+int getData(int i) const {return (int)data(i);}
+void setData(int i,int x) {data.set(i,x);}
+int getBegin(int i) const {return getData(2*i);}
+int getEnd(int i) const {return getData(2*i+1);}
+void setBegin(int i,int x) {setData(2*i,x);}
+void setEnd(int i,int x) {setData(2*i+1,x);}
+/** find the last range with begin<=x
+ @return -1 if not found */
+int findRange(int x) const;
+void addRange(int i,int b,int e);
+void removeRange(int i);
+void removeRanges(int r1,int r2);
+
+  public:
+MultiRange() {}
+MultiRange(const MultiRange &mr) {data=mr.data;}
+void operator=(const MultiRange &mr) {data=mr.data;}
+MultiRange(const IRange &r) {add(r);}
+MultiRange(int begin,int end) {add(begin,end);}
+MultiRange(int x) {add(x);}
+
+int operator==(const MultiRange &mr) const {return data==mr.data;}
+
+void clear();
+int isEmpty() const;
+
+IRange singleRange() const;
+int rangeCount() const;
+IRange getRange(int i) const;
+
+void add(int x) {add(x,x);}
+void add(const IRange& r) {add(r.begin,r.end);}
+void add(int begin, int end);
+void add(const MultiRange &mr);
+
+void remove(int x) {remove(x,x);}
+void remove(const IRange& r) {remove(r.begin,r.end);}
+void remove(int begin, int end);
+void remove(const MultiRange &mr);
+
+int contains(int x) const;
+int contains(const IRange& r) const;
+int contains(const MultiRange &mr) const;
+
+void intersect(const IRange& r) {intersect(r.begin,r.end);}
+void intersect(int begin, int end);
+void intersect(const MultiRange &mr);
+
+void shift(int delta);
+
+void print() const;
+void print2() const;
+};
+
+#endif
+
+
+
+
+
Index: /cpp/gdk/neuroclasses.h
===================================================================
--- /cpp/gdk/neuroclasses.h	(revision 5)
+++ /cpp/gdk/neuroclasses.h	(revision 5)
@@ -0,0 +1,28 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+CLASS(StdNeuron,"N","Neuron",`"Standard Framsticks Neuron, compatible with 1.0"',-1,1,0,0,0)
+
+CLASS(Gyro,"G","Gyroscope","Equilibrium sensor",0,1,2,
+	`{7, 4, 15,45,25,60,5,60,15,45,15,30,3, 25,60,20,65,10,65,5,60,4, 55,35,65,50,45,50,55,35,55,20,3, 65,50,60,55,50,55,45,50,1, 55,20,15,30,4, 35,25,35,75,30,80,40,80,35,75, 7, 100,50,90,50,90,40,70,40,80,50,70,60,90,60,90,50}',0)
+
+CLASS(Touch,"T","Touch","Touch sensor",0,1,1,
+      `{9, 15, 6,40,13,47,17,57,18,63,21,67,25,66,26,59,29,54,34,54,48,66,54,68,57,66,56,62,38,44,33,41,30,40,3, 46,51,46,45,40,39,31,36,4, 46,45,42,36,37,33,21,30,16,25,2, 58,62,63,62,64,65,1, 66,66,67,68,2, 68,70,70,73,66,73,1, 63,73,59,73,2, 56,73,52,73,51,69,7, 100,50,90,50,90,40,70,40,80,50,70,60,90,60,90,50}',0)
+
+CLASS(Smell,"S","Smell","Smell sensor",0,1,1,
+      `{13, 11, 11,6,21,7,29,13,30,30,38,36,47,52,29,53,29,64,17,67,28,68,26,83,8,86,1, 40,49,30,49,1, 24,19,16,20,1, 16,20,24,22,1, 40,57,44,61,1, 46,64,50,68,1, 52,71,56,75,1, 41,57,46,59,1, 50,59,55,60,1, 41,58,41,63,1, 41,65,41,70,1, 58,78,62,83,7, 100,50,90,50,90,40,70,40,80,50,70,60,90,60,90,50}',0)
+
+CLASS(Const,"*","Const","Constant value",0,1,0,
+      `{9, 2, 20,80,20,20,15,25,1, 20,20,25,25,2, 10,70,70,70,65,65,1, 70,70,65,75,1, 25,40,30,40,1, 35,40,40,40,1, 45,40,50,40,1, 55,40,60,40,7, 100,50,90,50,90,40,70,40,80,50,70,60,90,60,90,50}',0)
+
+CLASS(BendMuscle,"|","Bend Muscle","",1,0,2,
+`{11,4, 72,23,82,26,73,50,64,46,72,23,4, 62,51,71,54,63,78,54,74,62,51,1, 69,52,73,49,1, 76,47,80,45,1, 84,43,87,41,1, 66,50,65,46,1, 63,42,62,38,1, 60,34,59,30,1, 91,40,94,38,1, 57,27,55,22,5, 25,40,35,40,45,50,35,60,25,60,25,40}',
+  2,
+  `{"p",0,0,"power","f 0.01 1.0",FIELD(power),},
+   {"r",0,0,"rot.range","f 0.0 1.0",FIELD(rotrange),},')
+
+CLASS(RotMuscle,"@","Rotation Muscle","",1,0,2,
+`{12,4, 78,22,87,26,79,49,69,46,78,22,4, 67,51,77,54,68,78,59,74,67,51,1, 82,47,87,50,1, 89,52,91,58,1, 90,62,85,63,1, 82,64,77,64,1, 73,63,68,62,1, 65,60,59,56,1, 56,53,53,49,1, 53,45,57,41,1, 60,41,64,41,5, 25,40,35,40,45,50,35,60,25,60,25,40}',
+  1,
+  `{"p",0,0,"power","f 0.01 1.0",FIELD(power),},')
Index: /cpp/gdk/neurocls-factory.h
===================================================================
--- /cpp/gdk/neurocls-factory.h	(revision 5)
+++ /cpp/gdk/neurocls-factory.h	(revision 5)
@@ -0,0 +1,166 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+
+// do not edit - generated automatically from "f0.def"
+// (to be included in "neurofactory.cpp")
+
+
+
+
+
+#define FIELDSTRUCT NI_StdNeuron 
+ParamEntry NI_StdNeuron_tab []={
+{"Neuron",1, 4 ,"N",},
+{"in",1,0,"Inertia","f 0.0 1.0 0.8",FIELD(inertia),},
+{"fo",1,0,"Force","f 0.0 999.0 0.04",FIELD(force),},
+{"si",1,0,"Sigmoid","f -99999.0 99999.0 2.0",FIELD(sigmo),},
+{"s",2,0,"State","f -1.0 1.0 0.0",FIELD(newstate),},
+ {0,0,0,},};
+#undef FIELDSTRUCT
+
+#define FIELDSTRUCT NI_StdUNeuron 
+ParamEntry NI_StdUNeuron_tab []={
+{"Unipolar neuron [EXPERIMENTAL!]",1, 4 ,"Nu",},
+{"in",1,0,"Inertia","f 0.0 1.0 0.8",FIELD(inertia),},
+{"fo",1,0,"Force","f 0.0 999.0 0.04",FIELD(force),},
+{"si",1,0,"Sigmoid","f -99999.0 99999.0 2.0",FIELD(sigmo),},
+{"s",2,0,"State","f -1.0 1.0 0.0",FIELD(newstate),},
+ {0,0,0,},};
+#undef FIELDSTRUCT
+
+#define FIELDSTRUCT NI_Gyro 
+ParamEntry NI_Gyro_tab []={
+{"Gyroscope",1, 0 ,"G",},
+ {0,0,0,},};
+#undef FIELDSTRUCT
+
+#define FIELDSTRUCT NI_Touch 
+ParamEntry NI_Touch_tab []={
+{"Touch",1, 0 ,"T",},
+ {0,0,0,},};
+#undef FIELDSTRUCT
+
+#define FIELDSTRUCT NI_Smell 
+ParamEntry NI_Smell_tab []={
+{"Smell",1, 0 ,"S",},
+ {0,0,0,},};
+#undef FIELDSTRUCT
+
+#define FIELDSTRUCT NI_Const 
+ParamEntry NI_Const_tab []={
+{"Constant",1, 0 ,"*",},
+ {0,0,0,},};
+#undef FIELDSTRUCT
+
+#define FIELDSTRUCT NI_BendMuscle 
+ParamEntry NI_BendMuscle_tab []={
+{"Bend muscle",1, 2 ,"|",},
+{"p",0,0,"power","f 0.01 1.0 0.25",FIELD(power),},
+{"r",0,0,"bending range","f 0.0 1.0 1.0",FIELD(bendrange),},
+ {0,0,0,},};
+#undef FIELDSTRUCT
+
+#define FIELDSTRUCT NI_RotMuscle 
+ParamEntry NI_RotMuscle_tab []={
+{"Rotation muscle",1, 1 ,"@",},
+{"p",0,0,"power","f 0.01 1.0 1.0",FIELD(power),},
+ {0,0,0,},};
+#undef FIELDSTRUCT
+
+#define FIELDSTRUCT NI_Diff 
+ParamEntry NI_Diff_tab []={
+{"Differentiate",1, 0 ,"D",},
+ {0,0,0,},};
+#undef FIELDSTRUCT
+
+#define FIELDSTRUCT NI_FuzzyNeuro 
+ParamEntry NI_FuzzyNeuro_tab []={
+{"Fuzzy system [EXPERIMENTAL!]",1, 4 ,"Fuzzy",},
+{"ns",0,0,"number of fuzzy sets","d 1  ",FIELD(fuzzySetsNr),},
+{"nr",0,0,"number of rules","d 1  ",FIELD(rulesNr),},
+{"fs",0,0,"fuzzy sets","s 0 -1 0",FIELD(fuzzySetString),},
+{"fr",0,0,"fuzzy rules","s 0 -1 0",FIELD(fuzzyRulesString),},
+ {0,0,0,},};
+#undef FIELDSTRUCT
+
+#define FIELDSTRUCT NI_Sticky 
+ParamEntry NI_Sticky_tab []={
+{"Sticky [EXPERIMENTAL!]",1, 0 ,"Sti",},
+ {0,0,0,},};
+#undef FIELDSTRUCT
+
+#define FIELDSTRUCT NI_LinearMuscle 
+ParamEntry NI_LinearMuscle_tab []={
+{"Linear muscle [EXPERIMENTAL!]",1, 1 ,"LMu",},
+{"p",0,0,"power","f 0.01 1.0 1.0",FIELD(power),},
+ {0,0,0,},};
+#undef FIELDSTRUCT
+
+#define FIELDSTRUCT NI_WaterDetect 
+ParamEntry NI_WaterDetect_tab []={
+{"Water detector",1, 0 ,"Water",},
+ {0,0,0,},};
+#undef FIELDSTRUCT
+
+#define FIELDSTRUCT NI_Energy 
+ParamEntry NI_Energy_tab []={
+{"Energy level",1, 0 ,"Energy",},
+ {0,0,0,},};
+#undef FIELDSTRUCT
+
+#define FIELDSTRUCT NI_Channelize 
+ParamEntry NI_Channelize_tab []={
+{"Channelize",1, 0 ,"Ch",},
+ {0,0,0,},};
+#undef FIELDSTRUCT
+
+#define FIELDSTRUCT NI_ChMux 
+ParamEntry NI_ChMux_tab []={
+{"Channel multiplexer",1, 0 ,"ChMux",},
+ {0,0,0,},};
+#undef FIELDSTRUCT
+
+#define FIELDSTRUCT NI_ChSel 
+ParamEntry NI_ChSel_tab []={
+{"Channel selector",1, 1 ,"ChSel",},
+{"ch",0,0,"channel","d   ",FIELD(ch),},
+ {0,0,0,},};
+#undef FIELDSTRUCT
+
+#define FIELDSTRUCT NI_Random 
+ParamEntry NI_Random_tab []={
+{"Random noise",1, 0 ,"Rnd",},
+ {0,0,0,},};
+#undef FIELDSTRUCT
+
+#define FIELDSTRUCT NI_Sinus 
+ParamEntry NI_Sinus_tab []={
+{"Sinus generator",1, 2 ,"Sin",},
+{"f0",0,0,"base frequency","f -1.0 1.0 0.06283185307",FIELD(f0),},
+{"t",0,0,"time","f 0 6.283185307 0",FIELD(t),},
+ {0,0,0,},};
+#undef FIELDSTRUCT
+
+#define SETIMPLEMENTATION \
+setImplementation("N",new NI_StdNeuron); \
+setImplementation("Nu",new NI_StdUNeuron); \
+setImplementation("G",new NI_Gyro); \
+setImplementation("T",new NI_Touch); \
+setImplementation("S",new NI_Smell); \
+setImplementation("*",new NI_Const); \
+setImplementation("|",new NI_BendMuscle); \
+setImplementation("@",new NI_RotMuscle); \
+setImplementation("D",new NI_Diff); \
+setImplementation("Fuzzy",new NI_FuzzyNeuro); \
+setImplementation("Sti",new NI_Sticky); \
+setImplementation("LMu",new NI_LinearMuscle); \
+setImplementation("Water",new NI_WaterDetect); \
+setImplementation("Energy",new NI_Energy); \
+setImplementation("Ch",new NI_Channelize); \
+setImplementation("ChMux",new NI_ChMux); \
+setImplementation("ChSel",new NI_ChSel); \
+setImplementation("Rnd",new NI_Random); \
+setImplementation("Sin",new NI_Sinus); \
+
Index: /cpp/gdk/neurocls-factory.m4
===================================================================
--- /cpp/gdk/neurocls-factory.m4	(revision 5)
+++ /cpp/gdk/neurocls-factory.m4	(revision 5)
@@ -0,0 +1,42 @@
+divert(-1)
+##
+##  NEUROCLASS(c_classname,name,longname,description,prefinputs,prefoutput,preflocat)
+##             $1          $2   $3       $4          $5         $6         $7
+##  SYMBOL(vectordata)
+##
+##  NEUROPROP(id,group,flags,name,type,min,max,def,field)
+##            $1 $2    $3    $4   $5   $6  $7  $8  $9
+##  ENDNEUROCLASS
+##
+
+divert(1)
+#define SETIMPLEMENTATION \
+divert(2)
+divert(-1)
+
+define(`CLASS',`dnl')
+define(`GROUP',`dnl')
+define(`PROP',`dnl')
+define(`XPROP',`dnl')
+define(`ENDCLASS',`dnl')
+
+define(`TABNAME',`NI_$1_tab')
+define(`CLSNAME',`NI_$1')
+define(`VARNAME',`tmp_$1')
+define(`XYNAME',`$1_xy')
+
+define(`SYMBOL',`dnl')
+define(`VISUALHINTS',`dnl')
+
+define(`NEUROCLASS',`define(`numprops',`0')`#'define FIELDSTRUCT' CLSNAME($1) `
+ParamEntry TABNAME($1) []={
+{"$3",1,divert(3),"$2",},divert(1)setImplementation("$2",new CLSNAME($1)); \
+divert(3)')
+
+define(`ENDNEUROCLASS',`divert numprops undivert(3) {0,0,0,},};
+`#'undef FIELDSTRUCT')
+define(`NEUROPROP',`define(`numprops',incr(numprops)){"$1",$2,$3,"$4","$5 $6 $7 $8",FIELD($9),},')
+
+divert
+// do not edit - generated automatically from "f0.def"
+// (to be included in "neurofactory.cpp")
Index: /cpp/gdk/neurocls-library.h
===================================================================
--- /cpp/gdk/neurocls-library.h	(revision 5)
+++ /cpp/gdk/neurocls-library.h	(revision 5)
@@ -0,0 +1,182 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+
+// do not edit - generated automatically from "f0.def"
+// (to be included in "neurolibrary.cpp")
+
+
+
+
+
+     
+static ParamEntry NI_StdNeuron_tab[]={
+{"Neuron",1, 4 ,"N",},
+
+{"in",1,0,"Inertia","f 0.0 1.0 0.8",},
+{"fo",1,0,"Force","f 0.0 999.0 0.04",},
+{"si",1,0,"Sigmoid","f -99999.0 99999.0 2.0",},
+{"s",2,0,"State","f -1.0 1.0 0.0",},
+ 
+{0,0,0,},};
+addClass(new NeuroClass(NI_StdNeuron_tab,"Standard neuron",-1,1,0, 0,2));
+
+     
+static ParamEntry NI_StdUNeuron_tab[]={
+{"Unipolar neuron [EXPERIMENTAL!]",1, 4 ,"Nu",},
+{"in",1,0,"Inertia","f 0.0 1.0 0.8",},
+{"fo",1,0,"Force","f 0.0 999.0 0.04",},
+{"si",1,0,"Sigmoid","f -99999.0 99999.0 2.0",},
+{"s",2,0,"State","f -1.0 1.0 0.0",},
+ 
+{0,0,0,},};
+addClass(new NeuroClass(NI_StdUNeuron_tab,"Works like standard neuron (N) but the output value is scaled to 0...+1 instead of -1...+1.\nHaving 0 as one of the saturation states should help in \"gate circuits\", where input signal is passed through or blocked depending on the other singal.",-1,1,0, 0,0));
+
+     static int Gyro_xy[]={83,8,7,100,50,90,50,90,40,70,40,80,50,70,60,90,60,90,50,12,43,24,48,24,48,19,38,19,38,24,43,24,43,54,48,54,48,64,43,69,38,64,38,54,43,54,5,63,69,58,74,48,79,38,79,28,74,23,69,1,43,79,43,74,1,23,69,26,66,1,63,69,60,66,1,55,76,53,73,1,31,75,33,72};   
+static ParamEntry NI_Gyro_tab[]={
+{"Gyroscope",1, 0 ,"G",},
+
+
+ 
+{0,0,0,},};
+addClass(new NeuroClass(NI_Gyro_tab,"Equilibrium sensor.\n0=the stick is horizontal\n+1/-1=the stick is vertical",0,1,2, Gyro_xy,0,32));
+
+     static int Touch_xy[]={43,2,7,100,50,90,50,90,40,70,40,80,50,70,60,90,60,90,50,11,75,50,65,50,60,55,55,45,50,55,45,45,40,50,35,50,30,45,25,50,30,55,35,50};   
+static ParamEntry NI_Touch_tab[]={
+{"Touch",1, 0 ,"T",},
+
+
+ 
+{0,0,0,},};
+addClass(new NeuroClass(NI_Touch_tab,"Touch sensor.\n-1=no contact\n0=just touching\n>0=pressing, value depends on the force applied",0,1,1, Touch_xy,0,32));
+
+     static int Smell_xy[]={64,5,7,100,50,90,50,90,40,70,40,80,50,70,60,90,60,90,50,3,10,40,15,45,15,55,10,60,5,20,30,25,35,30,45,30,55,25,65,20,70,4,15,35,20,40,22,50,20,60,15,65,5,75,50,50,50,45,45,40,50,45,55,50,50};   
+static ParamEntry NI_Smell_tab[]={
+{"Smell",1, 0 ,"S",},
+
+
+ 
+{0,0,0,},};
+addClass(new NeuroClass(NI_Smell_tab,"Smell sensor. Aggregated \"smell of energy\" experienced from all energy objects (creatures and food pieces).\nClose objects have bigger influence than the distant ones: for each energy source, its partial feeling is proportional to its energy/(distance^2)",0,1,1, Smell_xy,0,32));
+
+     static int Const_xy[]={26,3,6,100,50,90,50,90,40,70,40,70,60,90,60,90,50,1,85,50,75,50,1,80,45,80,55};   
+static ParamEntry NI_Const_tab[]={
+{"Constant",1, 0 ,"*",},
+
+
+ 
+{0,0,0,},};
+addClass(new NeuroClass(NI_Const_tab,"Constant value",0,1,0, Const_xy,0,1));
+
+     static int BendMuscle_xy[]={63,6,5,25,40,35,40,45,50,35,60,25,60,25,40,4,65,85,65,50,75,50,75,85,65,85,3,65,56,49,29,57,24,72,50,4,68,53,70,53,70,55,68,55,68,53,5,50,21,60,15,70,14,79,15,87,20,81,10,1,86,20,77,21};   
+static ParamEntry NI_BendMuscle_tab[]={
+{"Bend muscle",1, 2 ,"|",},
+
+
+{"p",0,0,"power","f 0.01 1.0 0.25",},
+{"r",0,0,"bending range","f 0.0 1.0 1.0",},
+ 
+{0,0,0,},};
+addClass(new NeuroClass(NI_BendMuscle_tab,"",1,0,2, BendMuscle_xy,0,2+16+64+4));
+
+     static int RotMuscle_xy[]={62,5,5,25,40,35,40,45,50,35,60,25,60,25,40,4,65,85,65,50,75,50,75,85,65,85,1,69,10,77,17,10,59,15,57,17,57,22,60,26,69,27,78,26,82,21,82,16,79,12,69,10,80,6,3,65,50,65,20,75,20,75,50};   
+static ParamEntry NI_RotMuscle_tab[]={
+{"Rotation muscle",1, 1 ,"@",},
+
+
+{"p",0,0,"power","f 0.01 1.0 1.0",},
+ 
+{0,0,0,},};
+addClass(new NeuroClass(NI_RotMuscle_tab,"",1,0,2, RotMuscle_xy,0,2+16+128+4));
+
+     
+static ParamEntry NI_Diff_tab[]={
+{"Differentiate",1, 0 ,"D",},
+ 
+{0,0,0,},};
+addClass(new NeuroClass(NI_Diff_tab,"Calculate the difference between the current and previous input value. Multiple inputs are aggregated with respect to their weights",-1,1,0, 0,0));
+
+     static int FuzzyNeuro_xy[]={44,5,2,30,65,37,37,44,65,3,37,65,44,37,51,37,58,65,2,51,65,58,37,65,65,6,100,50,70,50,70,25,25,10,25,90,70,75,70,50,1,70,65,25,65};   
+static ParamEntry NI_FuzzyNeuro_tab[]={
+{"Fuzzy system [EXPERIMENTAL!]",1, 4 ,"Fuzzy",},
+
+{"ns",0,0,"number of fuzzy sets","d 1  ",},
+{"nr",0,0,"number of rules","d 1  ",},
+{"fs",0,0,"fuzzy sets","s 0 -1 0",},
+{"fr",0,0,"fuzzy rules","s 0 -1 0",},
+ 
+{0,0,0,},};
+addClass(new NeuroClass(NI_FuzzyNeuro_tab,"Refer to publications to learn about this neuron",-1,1,0, FuzzyNeuro_xy,0,0));
+
+     
+static ParamEntry NI_Sticky_tab[]={
+{"Sticky [EXPERIMENTAL!]",1, 0 ,"Sti",},
+
+ 
+{0,0,0,},};
+addClass(new NeuroClass(NI_Sticky_tab,"",1,0,1, 0,32));
+
+     
+static ParamEntry NI_LinearMuscle_tab[]={
+{"Linear muscle [EXPERIMENTAL!]",1, 1 ,"LMu",},
+
+{"p",0,0,"power","f 0.01 1.0 1.0",},
+ 
+{0,0,0,},};
+addClass(new NeuroClass(NI_LinearMuscle_tab,"",1,0,2, 0,16));
+
+     
+static ParamEntry NI_WaterDetect_tab[]={
+{"Water detector",1, 0 ,"Water",},
+
+ 
+{0,0,0,},};
+addClass(new NeuroClass(NI_WaterDetect_tab,"Output signal:\n0=on or above water surface\n1=under water (deeper than 1)\n0..1=in the transient area just below water surface",0,1,1, 0,32));
+
+     
+static ParamEntry NI_Energy_tab[]={
+{"Energy level",1, 0 ,"Energy",},
+
+ 
+{0,0,0,},};
+addClass(new NeuroClass(NI_Energy_tab,"The current energy level divided by the initial energy level.\nUsually falls from initial 1.0 down to 0.0 and then the creature dies. It can rise above 1.0 if enough food is ingested",0,1,0, 0,32));
+
+     
+static ParamEntry NI_Channelize_tab[]={
+{"Channelize",1, 0 ,"Ch",},
+ 
+{0,0,0,},};
+addClass(new NeuroClass(NI_Channelize_tab,"Combines all input signals into a single multichannel output; Note: ChSel and ChMux are the only neurons which support multiple channels. Other neurons discard everything except the first channel.",-1,1,0, 0,0));
+
+     
+static ParamEntry NI_ChMux_tab[]={
+{"Channel multiplexer",1, 0 ,"ChMux",},
+ 
+{0,0,0,},};
+addClass(new NeuroClass(NI_ChMux_tab,"Outputs the selected channel from the second (multichannel) input. The first input is used as the selector value (-1=select first channel, .., 1=last channel)",2,1,0, 0,0));
+
+     
+static ParamEntry NI_ChSel_tab[]={
+{"Channel selector",1, 1 ,"ChSel",},
+{"ch",0,0,"channel","d   ",},
+ 
+{0,0,0,},};
+addClass(new NeuroClass(NI_ChSel_tab,"Outputs a single channel (selected by the \"ch\" parameter) from multichannel input",1,1,0, 0,0));
+
+     
+static ParamEntry NI_Random_tab[]={
+{"Random noise",1, 0 ,"Rnd",},
+ 
+{0,0,0,},};
+addClass(new NeuroClass(NI_Random_tab,"Generates random noise (subsequent random values in the range of -1..+1)",0,1,0, 0,0));
+
+     static int Sinus_xy[]={46,3,12,75,50,71,37,62,28,50,25,37,28,28,37,25,50,28,62,37,71,50,75,62,71,71,62,75,50,1,75,50,100,50,5,35,50,40,35,45,35,55,65,60,65,65,50};   
+static ParamEntry NI_Sinus_tab[]={
+{"Sinus generator",1, 2 ,"Sin",},
+
+{"f0",0,0,"base frequency","f -1.0 1.0 0.06283185307",},
+{"t",0,0,"time","f 0 6.283185307 0",},
+ 
+{0,0,0,},};
+addClass(new NeuroClass(NI_Sinus_tab,"Output frequency = f0+input",1,1,0, Sinus_xy,0,0));
Index: /cpp/gdk/neurocls-library.m4
===================================================================
--- /cpp/gdk/neurocls-library.m4	(revision 5)
+++ /cpp/gdk/neurocls-library.m4	(revision 5)
@@ -0,0 +1,48 @@
+divert(-1)
+##
+##  NEUROCLASS(c_classname,name,longname,description,prefinputs,prefoutput,preflocat)
+##             $1          $2   $3       $4          $5         $6         $7
+##  SYMBOL(vectordata)
+##
+##  NEUROPROP(id,group,flags,name,type,min,max,def,field)
+##            $1 $2    $3    $4   $5   $6  $7  $8  $9
+##  ENDNEUROCLASS
+##
+
+define(`Invisible',1)
+define(`DontShowClass',`2')
+define(`AtFirstPart',`4')
+define(`AtSecondPart',`8')
+define(`InTheMiddle',`12')
+define(`MuscleClass',`16')
+define(`ReceptorClass',`32')
+define(`V1BendMuscle',`64')
+define(`V1RotMuscle',`128')
+
+define(`nargs', `$#')
+define(`CLASS',`dnl')
+define(`GROUP',`dnl')
+define(`PROP',`dnl')
+define(`XPROP',`dnl')
+define(`ENDCLASS',`dnl')
+
+define(`TABNAME',`NI_$1_tab')
+define(`CLSNAME',`NI_$1')
+define(`XYNAME',`$1_xy')
+
+define(`SYMBOL',`divert static int XYNAME(currentcls)[]={nargs($1),`$1'}; define(`hasxy',+) divert(2)')
+
+define(`VISUALHINTS',`define(`vhints',$1)')
+
+define(`NEUROCLASS',`define(`numprops',`0') define(`currentcls',$1) define(`hasxy',) define(`vhints',0) divert(1)
+static ParamEntry TABNAME($1)[]={
+{"$3",1,divert(2),"$2",},divert(3)
+{0,0,0,},};
+addClass(new NeuroClass(TABNAME($1),"$4",$5,$6,$7,divert(2)'))
+
+define(`ENDNEUROCLASS',`divert undivert(1) numprops undivert(2) undivert(3) ifelse(hasxy,,0,XYNAME(currentcls)`,0'),vhints));')
+define(`NEUROPROP',`define(`numprops',incr(numprops)){"$1",$2,$3,"$4","$5 $6 $7 $8",},')
+
+divert
+// do not edit - generated automatically from "f0.def"
+// (to be included in "neurolibrary.cpp")
Index: /cpp/gdk/neurofactory.cpp
===================================================================
--- /cpp/gdk/neurofactory.cpp	(revision 5)
+++ /cpp/gdk/neurofactory.cpp	(revision 5)
@@ -0,0 +1,58 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "neurofactory.h"
+#include "sstring.h"
+#include "param.h"
+#include "neuroimpl.h"
+#include "neuroimplfiles.h"
+
+int NeuroFactory::used=0;
+
+NeuroImpl* NeuroFactory::createNeuroImpl(NeuroClass *nc)
+{
+if (!nc) return 0;
+if (!nc->active) return 0;
+NeuroImpl* ni=(NeuroImpl*)nc->impl;
+if (!ni) return 0;
+return ni->makeNew();
+}
+
+NeuroImpl* NeuroFactory::setImplementation(const SString& classname,NeuroImpl *ni,bool deleteold)
+{
+NeuroClass *nc=Neuro::getClass(classname);
+if (!nc) return ni;
+return setImplementation(nc,ni,deleteold);
+}
+
+NeuroImpl* NeuroFactory::setImplementation(NeuroClass *nc,NeuroImpl *ni,bool deleteold)
+{
+NeuroImpl* old_ni=(NeuroImpl*)nc->impl;
+nc->impl=ni;
+if (deleteold && old_ni) delete old_ni;
+return old_ni;
+}
+
+#include "neuroimplfiles.h"
+#include "neurocls-factory.h"
+
+void NeuroFactory::setImplementation()
+{
+if (!used)
+	{
+	SETIMPLEMENTATION
+	}
+used++;
+}
+
+void NeuroFactory::freeImplementation()
+{
+used--;
+if (!used)
+	{
+	for(int i=0;i<Neuro::getClassCount();i++)
+		setImplementation(Neuro::getClass(i),0);
+	}
+}
+
Index: /cpp/gdk/neurofactory.h
===================================================================
--- /cpp/gdk/neurofactory.h	(revision 5)
+++ /cpp/gdk/neurofactory.h	(revision 5)
@@ -0,0 +1,26 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _NEUROFACTORY_H_
+#define _NEUROFACTORY_H_
+
+#include "modelparts.h"
+
+class NeuroImpl;
+
+class NeuroFactory
+{
+public:
+static NeuroImpl* setImplementation(NeuroClass *nc,NeuroImpl *ni,bool deleteold=1);
+static NeuroImpl* setImplementation(const SString& classname,NeuroImpl *ni,bool deleteold=1);
+static class NeuroImpl* createNeuroImpl(Neuro *n)
+	{NeuroClass *nc=n->getClass(); if (!nc) return 0; return createNeuroImpl(nc);}
+static class NeuroImpl* createNeuroImpl(NeuroClass *nc);
+
+static int used;
+static void setImplementation();
+static void freeImplementation();
+};
+
+#endif
Index: /cpp/gdk/neuroimpl-body-gdk.h
===================================================================
--- /cpp/gdk/neuroimpl-body-gdk.h	(revision 5)
+++ /cpp/gdk/neuroimpl-body-gdk.h	(revision 5)
@@ -0,0 +1,96 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _NEUROIMPLBODY_H_
+#define _NEUROIMPLBODY_H_
+
+#include "neuroimpl.h"
+
+class NI_Gyro: public NeuroImpl
+{
+public:
+NeuroImpl* makeNew(){return new NI_Gyro();} // for NeuroFactory
+int lateinit() {if (!neuro->joint) return 0; simorder=0; return 1;}
+void go() {setState(0);}
+};
+
+class NI_Touch: public NeuroImpl
+{
+public:
+NeuroImpl* makeNew(){return new NI_Touch();} // for NeuroFactory
+int lateinit() {if (!neuro->part) return 0; simorder=0; return 1;}
+void go() {setState(0);}
+};
+
+class NI_Smell: public NeuroImpl
+{
+public:
+NeuroImpl* makeNew(){return new NI_Smell();} // for NeuroFactory
+void go() {setState(0);}
+int lateinit() {if (!neuro->part) return 0; simorder=0; return 1;}
+};
+
+extern ParamEntry NI_BendMuscle_tab[];
+class NI_BendMuscle: public NeuroImpl
+{
+public:
+double power,bendrange;
+NeuroImpl* makeNew(){return new NI_BendMuscle();} // for NeuroFactory
+NI_BendMuscle() {paramentries=NI_BendMuscle_tab;}
+int lateinit() {if (!neuro->joint) return 0; simorder=2; return 1;}
+void go() {}
+};
+
+extern ParamEntry NI_RotMuscle_tab[];
+class NI_RotMuscle: public NeuroImpl
+{
+public:
+double power;
+NeuroImpl* makeNew(){return new NI_RotMuscle();} // for NeuroFactory
+NI_RotMuscle() {paramentries=NI_RotMuscle_tab;}
+int lateinit() {if (!neuro->joint) return 0; simorder=2; return 1;}
+void go() {}
+};
+
+extern ParamEntry NI_LinearMuscle_tab[];
+class NI_LinearMuscle: public NeuroImpl
+{
+public:
+double power;
+NeuroImpl* makeNew(){return new NI_RotMuscle();} // for NeuroFactory
+NI_LinearMuscle() {paramentries=NI_RotMuscle_tab;}
+int lateinit() {if (!neuro->joint) return 0; simorder=2; return 1;}
+void go() {}
+};
+
+class NI_Sticky: public NeuroImpl
+{
+public:
+double power;
+NeuroImpl* makeNew(){return new NI_Sticky();} // for NeuroFactory
+int lateinit() {if (!neuro->part) return 0; simorder=0; return 1;}
+void go() {}
+};
+
+class NI_WaterDetect: public NeuroImpl
+{
+public:
+NeuroImpl* makeNew(){return new NI_WaterDetect();} // for NeuroFactory
+int lateinit() {if (!neuro->part) return 0; simorder=0; return 1;}
+void go() {setState(0);}
+};
+
+class NI_Energy: public NeuroImpl
+{
+public:
+NeuroImpl* makeNew(){return new NI_Energy();} // for NeuroFactory
+void go() {setState(0);}
+};
+
+#endif
+
Index: /cpp/gdk/neuroimpl-channels.cpp
===================================================================
--- /cpp/gdk/neuroimpl-channels.cpp	(revision 5)
+++ /cpp/gdk/neuroimpl-channels.cpp	(revision 5)
@@ -0,0 +1,34 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "neuroimpl-channels.h"
+
+void NI_Channelize::go()
+{
+setChannelCount(getInputCount());
+for(int i=0;i<getInputCount();i++)
+	setState(getWeightedInputState(i),i);
+}
+
+void NI_ChMux::go()
+{
+int c=getInputChannelCount(1);
+if (c<2) {setState(getWeightedInputState(1)); return;}
+double s=getWeightedInputState(0);
+s=(max(-1.0,min(1.0,s))+1.0)/2.0; // 0..1
+int i1;
+i1=s*(c-1); i1=max(0,min(i1,c-2));
+double sw=1.0/(c-1);
+double s1=sw*i1;
+double w1=fabs((s-s1)/sw);
+double w2=1.0-w1;
+double is1=getWeightedInputState(1,i1);
+double is2=getWeightedInputState(1,i1+1);
+setState(is1*w2 + is2*w1);
+}
+
+void NI_ChSel::go()
+{
+setState(getWeightedInputState(0,ch));
+}
Index: /cpp/gdk/neuroimpl-channels.h
===================================================================
--- /cpp/gdk/neuroimpl-channels.h	(revision 5)
+++ /cpp/gdk/neuroimpl-channels.h	(revision 5)
@@ -0,0 +1,39 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _NEUROIMPLCHANNELS_H
+#define _NEUROIMPLCHANNELS_H
+
+#include "neuroimpl.h"
+
+class NI_Channelize: public NeuroImpl
+{
+public:
+NeuroImpl* makeNew(){return new NI_Channelize();} // for NeuroFactory
+void go();
+};
+
+class NI_ChMux: public NeuroImpl
+{
+public:
+NeuroImpl* makeNew(){return new NI_ChMux();} // for NeuroFactory
+void go();
+};
+
+extern ParamEntry NI_ChSel_tab[];
+
+class NI_ChSel: public NeuroImpl
+{
+public:
+int ch; // channel
+NI_ChSel():ch(0) {paramentries=NI_ChSel_tab;}
+NeuroImpl* makeNew(){return new NI_ChSel();} // for NeuroFactory
+void go();
+};
+
+
+#endif
+
+
+
Index: /cpp/gdk/neuroimpl-fuzzy-f0.cpp
===================================================================
--- /cpp/gdk/neuroimpl-fuzzy-f0.cpp	(revision 5)
+++ /cpp/gdk/neuroimpl-fuzzy-f0.cpp	(revision 5)
@@ -0,0 +1,136 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+/// this is a module included into neuroimpl-fuzzy
+/// it converts string parameters - fuzzy sets and fuzzy rules - into appropriate variables
+
+#include "neuroimpl-fuzzy-f0.h"
+// nonstd z powodu max()
+#include "nonstd.h"
+
+//this part concerns fuzzy sets transformation
+
+/** This function converts given string into numbers representing fuzzy sets */
+int FuzzyF0String::convertStrToSets(const SString& str, double numbers[], int nrOfSets)
+{
+  int pos=0;
+  SString t;
+  int have=0;
+  int maxnumbers=4*nrOfSets; //number of semicolons should be equal 4*nrOfSets
+
+  while (str.getNextToken(pos,t,';'))
+    if (have>=maxnumbers)
+      break;
+    else
+      numbers[have++]=atof(t);
+
+  //check if number of read numbers (separated with semicolon) is equal to declared
+  if (have != 4*nrOfSets)
+    return -1; //number of sets found is lower than declared!
+
+  //check corectness of sets - must not be decreasing
+  for(int i=0;i<nrOfSets;i++)
+    if((numbers[4*i]>numbers[4*i+1])||(numbers[4*i+1]>numbers[4*i+2])||(numbers[4*i+2]>numbers[4*i+3]))
+      return -2; //error
+
+  return 0;
+}
+
+//this part concerns fuzzy rules transformation
+
+/** This function counts number of inputs and outputs given in string consisting fuzzy rules.
+It counts number of separators:
+; between inputs/outputs and fuzzy sets number
+: between conditional and decision part of a rule
+/ end of rule
+*/
+int FuzzyF0String::countInputsOutputs(const char* str, int ruldef[], int rulesNr)
+{ //ruledef will remember counted number of inputs and outputs for every rule
+  const char* t;
+  int separators=0, inouts=0;
+
+  for(t=str;*t;t++)
+  {
+    while(isdigit(*t))
+      t++; //only count, does not care about numbers now
+    if (!*t)
+      break; //end of the string - get out of 'for' loop
+    if ( (*t==';')||(*t==':')||(*t=='/') ) //found sth different than digit - it must be a separator
+    {
+      separators++; //one of separators
+      if (*t!=';') // end of [conditional part of] rule
+      {
+	if (inouts >= 2*rulesNr) //more rules declared in string than declared in rulesNr
+	  return -2;
+        ruldef[inouts]=(separators+1)/2; //cause fuzzy sets - for 1 in/out there are 2 semicolons
+	separators=0;  //begin counting number of in/out from zero
+	inouts++; //next part of rule / or next rule
+      }
+    }
+    else // illegal character
+      return -1;
+  }
+
+  //check, if nr of found rules is equal to declared
+  if (inouts == 2*rulesNr) //each rule has a conditional part (inputs) and decisional part (outputs)
+    return 0;
+  else
+    return -5; // ShowMessage("Inconsistent number of rules!");
+}
+
+/** This function converts given string into variable 'rules' that remembers all inputs/outputs and fuzzy set.
+The procedure is conduct according to ruledef, calculated earlier.*/
+int FuzzyF0String::convertStrToRules(const SString& str, const int ruledef[], int **rules, int setsNr, int rulesNr, int &maxOutputNr)
+{
+  int pos=0, j, k, len=str.len();
+  int dNr=0, sNr=0;
+  int inNr, outNr; //number of inputs/outputs and corresponding fuzzy sets
+  SString t;
+  bool conditional=true; //which part of rule: conditional or decisional
+
+  maxOutputNr=0; //sets maximum output nr found in rules string
+
+  //check corectness of the string: number semicolon ... separated with colon or slash
+  while(pos<len)
+  {
+    while((pos<len)&&(isdigit(str.charAt(pos)))) pos++;
+    if(!(pos<len))
+      break; //end of the string
+    if(str.charAt(pos)!=';')
+      if((str.charAt(pos)==':')&&(conditional))
+        {sNr++; conditional=false;}
+      else if((str.charAt(pos)=='/')&&(!conditional))
+        {dNr++; conditional=true;}
+      else
+        return -4; //error - illegal character
+    pos++;
+  }
+  if( (dNr!=sNr) || (dNr!=rulesNr) )
+    return -5; //error - wrong number of rules
+
+  pos=0;
+
+  for(j=0;j<rulesNr;j++)
+  { //sum of inputs and outputs
+    inNr = 2*ruledef[2*j];
+    outNr = 2*ruledef[2*j+1];
+    for(k=0;k<inNr+outNr;k++)
+    {
+      t = ""; //clear previous value
+      //cuts next integer values
+      while ( (pos<len)&&(isdigit(str.charAt(pos))) )
+        t += str.charAt(pos++);
+      pos++;
+      rules[j][k]=atol(t); //convert cut out string into number
+      //fuzzy sets - odd index table - are counted from 0,
+      //so if 5 fuzzy sets declared, values acceptable are 0,1,2,3,4
+      if ( ((k%2)!=0) && (rules[j][k] >= setsNr) )
+      	return -1;
+      if((k>=inNr)&&((k%2)==0))
+        maxOutputNr=max(maxOutputNr,rules[j][k]);
+    }
+  }
+  return 0;
+};
+
Index: /cpp/gdk/neuroimpl-fuzzy-f0.h
===================================================================
--- /cpp/gdk/neuroimpl-fuzzy-f0.h	(revision 5)
+++ /cpp/gdk/neuroimpl-fuzzy-f0.h	(revision 5)
@@ -0,0 +1,23 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+/// this is a modul included into neuroimpl-fuzzy
+/// it converts string parameters - fuzzy sets and fuzzy rules - into appropriate variables
+
+#ifndef _neuroimpl_fuzzy_f0_h
+#define _neuroimpl_fuzzy_f0_h
+
+#include <ctype.h>
+#include "sstring.h"
+
+class FuzzyF0String
+{
+  public:
+  static int convertStrToSets(const SString& str, double numbers[], int nrOfSets);
+  static int countInputsOutputs(const char* str, int ruldef[], int rulesNr);
+  static int convertStrToRules(const SString& str, const int ruledef[], int **rules, int setsNr, int rulesNr, int &maxOutputNr);
+};
+
+#endif
+
Index: /cpp/gdk/neuroimpl-fuzzy.cpp
===================================================================
--- /cpp/gdk/neuroimpl-fuzzy.cpp	(revision 5)
+++ /cpp/gdk/neuroimpl-fuzzy.cpp	(revision 5)
@@ -0,0 +1,208 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "neuroimpl-fuzzy.h"
+#include "neuroimpl-fuzzy-f0.h"
+
+int NI_FuzzyNeuro::countOuts(const Model *m, const Neuro *fuzzy)
+{
+  int outputs=0;
+  for(int i=0;i<m->getNeuroCount();i++)
+     for(int in=0;in<m->getNeuro(i)->getInputCount();in++)
+        if (m->getNeuro(i)->getInput(in)==fuzzy) outputs++;
+  return outputs;
+}
+
+int NI_FuzzyNeuro::lateinit()
+{
+  int i, maxOutputNr;
+
+  //check correctness of given parameters: string must not be null, sets&rules number > 0
+  if((fuzzySetsNr<1)||(rulesNr<1)||(fuzzySetString.len()==0)||(fuzzyRulesString.len()==0))
+    return 0; //error
+
+  // this part contains transformation of fuzzy sets
+  fuzzySets = new double[4*fuzzySetsNr]; //because every fuzzy set consist of 4 numbers
+  // converts fuzzy string from f0 to table of fuzzy numbers type 'double'
+  // (fill created space with numbers taken from string)
+  // also checks whether number of fuzzy sets in the string equals declared in the definition
+  if (FuzzyF0String::convertStrToSets(fuzzySetString, fuzzySets, fuzzySetsNr) != 0)
+    return 0; //error
+
+  // this part contains transformation of fuzzy rules and defuzzyfication parameters
+  rulesDef = new int[2*rulesNr];    //for each rule remembers number of inputs and outputs
+  //check correctness of string and fill in the rulesDef
+  if (FuzzyF0String::countInputsOutputs(fuzzyRulesString, rulesDef, rulesNr) == 0)
+  {
+    defuzzParam = new double[rulesNr]; // parameters used in defuzyfication process
+    // create space for rules according to rulesDef
+    rules = new int*[rulesNr];   //list of rules...
+    for (i=0; i<rulesNr; i++)    //...that contains rules body
+    {
+      rules[i] = new int[2*(rulesDef[2*i]+rulesDef[2*i+1])];  //each rule can have different number of inputs and outputs
+      defuzzParam[i] = 0; //should be done a little bit earlier, but why do not use this loop?
+    }
+    // fill created space with numbers taken from string
+    if (FuzzyF0String::convertStrToRules(fuzzyRulesString, rulesDef, rules, fuzzySetsNr, rulesNr, maxOutputNr) != 0)
+      return 0; //error
+  }
+  else
+    return 0; //error
+
+  setChannelCount(countOuts(neuro->owner, neuro));
+  return 1; //success
+}
+
+NI_FuzzyNeuro::~NI_FuzzyNeuro()
+{
+  if(rules) //delete rows and columns of **rules
+  {
+    for (int i=0; i<rulesNr; i++) SAFEDELETEARRAY(rules[i])
+    SAFEDELETEARRAY(rules)
+  }
+  SAFEDELETEARRAY(defuzzParam)
+  SAFEDELETEARRAY(rulesDef)
+  SAFEDELETEARRAY(fuzzySets)
+}
+
+int NI_FuzzyNeuro::GetFuzzySetParam(int set_nr, double &left, double &midleft, double &midright, double &right)
+{
+  if ( (set_nr>=0) && (set_nr<fuzzySetsNr) )
+  {
+    left = fuzzySets[4*set_nr];
+    midleft = fuzzySets[4*set_nr+1];
+    midright = fuzzySets[4*set_nr+2];
+    right = fuzzySets[4*set_nr+3];
+    return 0;
+  }
+  else
+    return 1;
+};
+
+/** Function conduct fuzzyfication of inputs and calculates - according to rules - crisp multi-channel output */
+void NI_FuzzyNeuro::go()
+{
+  if (Fuzzyfication()!=0)
+    return;
+  if (Defuzzyfication()!=0)
+    return;
+};
+
+/**
+* Function conduct fuzzyfication process - calculates minimum membership function (of every input) for each rule,
+* and writes results into defuzzParam - variable that contains data necessary for defuzzyfication
+*/
+int NI_FuzzyNeuro::Fuzzyfication()
+{
+  int i, j, nrIn, inputNr, nrFuzzySet;
+  double minimumCut; // actual minimal level of cut (= min. membership function)
+
+  // sets defuzzyfication parameters for each rule:
+  for (i=0; i<rulesNr; i++)
+  {
+    nrIn = rulesDef[2*i]; // nr of inputs in rule #i
+    minimumCut = 2; // the highest value of membership function is 1.0, so this value will definitely change
+    for (j=0; (j<nrIn)&&(minimumCut>0); j++) //minimumCut can not be <0, so if =0 then stop calculations
+    {
+      nrFuzzySet = rules[i][j*2 + 1]; // j*2 moves pointer through each output, +1 moves to nr of fuzzy set
+      inputNr = rules[i][j*2]; // as above but gives input number
+      minimumCut = min( minimumCut, TrapeziumFuzz(nrFuzzySet, getWeightedInputState(inputNr))); // value of membership function for this input and given fuzzy set
+    }
+    if ( (minimumCut>1) || (minimumCut<0) )
+      return 1;
+    defuzzParam[i] = minimumCut;
+  }
+  return 0;
+};
+
+/**
+* Function calculates value of the membership function of the set given by wchich_fuzzy_set for given crisp value input_val
+* In other words, this function fuzzyficates given crisp value with given fuzzy set, returning it's membership function
+* @param which_fuzzy_set - 0 < number of set < fuzzySetsNr
+* @param input_val - crisp value of input in range <-1; 1>
+* @return value of membership function (of given input for given set) in range <0;1> or, if error occur, negative value
+*/
+double NI_FuzzyNeuro::TrapeziumFuzz(int which_fuzzy_set, double input_val)
+{
+  double range=0, left=0, midleft=0, midright=0, right=0;
+
+  if ( (which_fuzzy_set < 0) || (which_fuzzy_set > fuzzySetsNr) )
+    return -2;
+  if ( (input_val < -1) || (input_val > 1) )
+    return -3;
+
+  if (GetFuzzySetParam(which_fuzzy_set, left, midleft, midright, right) != 0)
+    return -4;
+
+  if ( (input_val < left) || (input_val > right) ) // greather than right value
+    return 0;
+  else if ( (input_val >= midleft) && (input_val <= midright) ) // in the core of fuzzy set
+    return 1;
+  else if ( (input_val >= left) && (input_val < midleft) ) // at the left side of trapezium
+  {
+    range = fabs(midleft - left);
+    return fabs(input_val-left)/((range>0)?range:1); // quotient of distance between input and extreme left point of trapezium and range of rising side, or 1
+  }
+  else if ( (input_val > midright) && (input_val <= right) ) // at the right side of trapezium
+  {
+    range = fabs(right - midright);
+    return fabs(right-input_val)/((range>0)?range:1); // quotient of distance between input and extreme right point of trapezium and range of falling side, or 1
+  };
+
+  // should not occur
+  return 0;
+
+};
+
+/**
+* Function conducts defuzzyfication process: multi-channel output values are calculates with singleton method (method of high).
+* For each rules, all outputs fuzzy sets are taken and cut at 'cut-level', that is at minumum membership function (of current rule).
+* For all neuro pseudo-outputs, answer is calculated according to prior computations.
+* In fact, there is one output with multi-channel answer and appropriate values are given to right channels.
+*/
+int NI_FuzzyNeuro::Defuzzyfication()
+{
+  int i, j, nrIn, nrOut, out, set, outputsNr;
+  double *numerators, *denominators, midleft, midright, unimp;
+
+  outputsNr = getChannelCount();
+
+  numerators = new double[outputsNr];
+  denominators = new double[outputsNr];
+
+  for(i=0;i<outputsNr;i++) numerators[i] = denominators[i] = 0;
+
+  // for each rule...
+  for (i=0; i<rulesNr; i++)
+  {
+    nrIn = rulesDef[2*i]; // number of inputs in rule #i
+    nrOut = rulesDef[2*i + 1]; // number of outputs in rule #i
+    // ...calculate each output's product of middle fuzzy set value and minimum membership function (numerator) and sum of minimum membership function (denominator)
+    for (j=0; j<nrOut; j++)
+    {
+      out = rules[i][2*nrIn + 2*j]; //number of j-output
+      set = rules[i][2*nrIn + 2*j + 1]; //number of fuzzy set attributed to j-output
+      if (GetFuzzySetParam(set, unimp, midleft, midright, unimp) != 0) // gets range of core of given fuzzy set
+        { SAFEDELETEARRAY(denominators) SAFEDELETEARRAY(numerators) return 1; }
+      //defuzzParam[i] = minimum membership function for rule #i - calculated in fuzzyfication block
+      // defuzzyfication method of singletons (high): (fuzzy set modal value) * (minimum membership value)
+      numerators[out] += ((midleft + midright)/2.0) * defuzzParam[i];
+      denominators[out] += defuzzParam[i];
+    }
+  }
+
+  for (i=0; i<outputsNr; i++)
+  {
+    if (denominators[i] == 0)
+      setState(0, i);
+    else
+      setState(numerators[i]/denominators[i], i);
+  }
+
+  SAFEDELETEARRAY(denominators)
+  SAFEDELETEARRAY(numerators)
+
+  return 0;
+};
+
Index: /cpp/gdk/neuroimpl-fuzzy.h
===================================================================
--- /cpp/gdk/neuroimpl-fuzzy.h	(revision 5)
+++ /cpp/gdk/neuroimpl-fuzzy.h	(revision 5)
@@ -0,0 +1,71 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _NEUROIMPLFUZZY_H_
+#define _NEUROIMPLFUZZY_H_
+
+#include <stdlib.h>
+#include <math.h>
+
+#include "neuroimpl.h"
+#include "sstring.h"
+
+extern ParamEntry NI_FuzzyNeuro_tab[];
+
+/** Does the fuzzyfication process (of inputs) and defuzzyfication proces (of outpurs) - represents fuzzy rules
+*/
+class NI_FuzzyNeuro : public NeuroImpl
+{
+private:
+
+  double *fuzzySets;    /// list of four digits which represents fuzzy sets: [0]-l, [1]-m, [2]-n, [3]-r, ...  fuzzySet[4*i] = left, fuzzySet[4*i + 1] = midleft, fuzzySet[4*i + 2] = midright, fuzzySet[4*i + 3] = right
+
+  /** Determines, which fuzzy set is connected with each input of neuron. For instance third rule:
+  *   'IF input3 = fuzzy set #3 AND input5 = fuzzy set #1 then output2 = fuzzy set #6 AND output7 = fuzzy set #5'
+  *   the variables shoul have values as shown below:
+  *   RulesDef[4]=2; RulesDef[5]=2; //rule 3: 2 inputs, 2 outputs
+  *   Rules[2][0]=3, Rules[2][1]=3, Rules[2][2]=5, Rules[2][3]=1, Rules[2][4]=2, Rules[2][5]=6, Rules[2][6]=7, Rules[2][3]=5
+  */
+  int *rulesDef;    ///list of rules definitions: nr of inputs in rule 1, nr of outputs in rule 1, ... and so on for each rule
+  int **rules;      ///list of rules body: input nr, fuzzy set nr, ... , output nr, fuzzy set nr, ... and so on for each rule
+
+  /**
+  *  Sets defuzzyfication parameters: determines - for each rule - cut level <0;1> (minimum membership function of current rule).
+  *  In fact, defuzzParam remembers the values from 'first layer' - fuzzyfication layer (see neuron at documentation)
+  *  i.e. rule 1: defuzzParam[0] = 0.3522
+  */
+  double *defuzzParam; /// i.e.: defuzParam[5] = 0.455 means that rule #6 has got a minimum membership function (of given inputs set for this rule) at value 0.455 (it's cut level)
+
+protected:
+
+  ///Fuzzy functions
+  double TrapeziumFuzz(int which_fuzzy_set, double input_val);
+  int Fuzzyfication();
+  int Defuzzyfication();
+  int GetFuzzySetParam(int set_nr, double &left, double &midleft, double &midright, double &right);
+
+public:
+
+  int fuzzySetsNr;      /// number of fuzzy sets
+  int rulesNr;      ///number of rules
+  SString fuzzySetString; /// strings containing all fuzzy sets given in f0
+  SString fuzzyRulesString; /// strings containing all fuzzy rules given in f0
+
+  NI_FuzzyNeuro() {paramentries=NI_FuzzyNeuro_tab; fuzzySets=defuzzParam=NULL; rulesDef=NULL; rules=NULL;}
+  ~NI_FuzzyNeuro();
+  NeuroImpl* makeNew() { return new NI_FuzzyNeuro(); };
+  void go();
+  int lateinit();
+  /** Function build model based on given genotype and conts number of neurons connected with fuzzy neuro,
+    also checks number of fuzzy neuron inputs.
+    \param genotype genotype to be scanned
+    \param inputs number of fuzzy neuron inputs
+    \param output number of fuzzy neuron outputs (= number of neurons connected to fuzzy neuron)
+    @return success or failure
+  **/
+  static int countOuts(const Model *m, const Neuro *fuzzy);
+  
+};
+
+#endif
Index: /cpp/gdk/neuroimpl-simple.cpp
===================================================================
--- /cpp/gdk/neuroimpl-simple.cpp	(revision 5)
+++ /cpp/gdk/neuroimpl-simple.cpp	(revision 5)
@@ -0,0 +1,52 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "neuroimpl-simple.h"
+
+#define NEURO_MAX 10.0
+#define OVERLOAD 0.1
+#define MUSCLESPEED   0.08
+#define MUSCLEACC   0.01
+
+int NI_StdNeuron::lateinit()
+{
+#ifdef MODEL_V1_COMPATIBLE
+if (inertia<0) inertia=neuro->inertia;
+if (force<0) force=neuro->force;
+if (sigmo>1e9) sigmo=neuro->sigmo;
+#endif
+istate=newstate+neuro->state; // neuro->state -> random initialization
+calcOutput();
+neuro->state=newstate;
+return 1;
+}
+
+void NI_StdNeuron::calcInternalState()
+{
+double sum=getWeightedInputSum();
+velocity=force*(sum-istate)+inertia*velocity;
+istate+=velocity;
+if (istate>NEURO_MAX) istate=NEURO_MAX;
+else if (istate<-NEURO_MAX) istate=-NEURO_MAX;
+}
+
+void NI_StdNeuron::go()
+{
+calcInternalState();
+calcOutput();
+}
+
+void NI_StdNeuron::calcOutput()
+{
+double s=istate * sigmo;
+if (s<-30.0) setState(-1);
+else setState(2.0/(1.0+exp(-s))-1.0); // -1...1
+}
+
+void NI_StdUNeuron::calcOutput()
+{
+double s=istate * sigmo;
+if (s<-30.0) setState(0);
+else setState(1.0/(1.0+exp(-s))); // 0...1
+}
Index: /cpp/gdk/neuroimpl-simple.h
===================================================================
--- /cpp/gdk/neuroimpl-simple.h	(revision 5)
+++ /cpp/gdk/neuroimpl-simple.h	(revision 5)
@@ -0,0 +1,99 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _NEUROIMPLSIMPLE_H_
+#define _NEUROIMPLSIMPLE_H_
+
+#include "neuroimpl.h"
+
+extern ParamEntry NI_StdNeuron_tab[];
+
+class NI_StdNeuron: public NeuroImpl
+{
+  protected:
+double istate, velocity;
+void calcInternalState();
+virtual void calcOutput();
+  public:
+double inertia,force,sigmo;
+NI_StdNeuron():velocity(0)
+#ifdef MODEL_V1_COMPATIBLE
+	,inertia(-1),force(-1),sigmo(1e10)// illegal values, will be adjusted in lateinit()
+#else
+	,inertia(0),force(0),sigmo(0)
+#endif
+	{paramentries=NI_StdNeuron_tab;}
+NeuroImpl* makeNew(){return new NI_StdNeuron();} // for NeuroFactory
+int lateinit();
+void go();
+};
+
+extern ParamEntry NI_StdUNeuron_tab[];
+
+class NI_StdUNeuron: public NI_StdNeuron
+{
+  public:
+NI_StdUNeuron()
+	{paramentries=NI_StdUNeuron_tab;}
+NeuroImpl* makeNew(){return new NI_StdUNeuron();} // for NeuroFactory
+void calcOutput();
+};
+
+class NI_Const: public NeuroImpl
+{
+public:
+NeuroImpl* makeNew(){return new NI_Const();} // for NeuroFactory
+int lateinit()
+	{
+	neuro->state=newstate=1.0;
+	simorder=0;
+	return 1;
+	}
+};
+
+class NI_Diff : public NeuroImpl
+{
+double previous;      
+  public:
+NeuroImpl* makeNew() { return new NI_Diff(); };
+
+void go()
+	{
+	double s=getWeightedInputSum();
+	setState(s-previous);
+	previous=s;
+	}
+int lateinit()
+	{
+	NeuroImpl::lateinit();
+	previous=neuro->state;
+	return 1;
+	}
+};
+
+class NI_Random : public NeuroImpl
+{
+  public:
+NeuroImpl* makeNew() { return new NI_Random(); };
+void go() {setState(rnd01*2.0-1.0);}
+};
+
+extern ParamEntry NI_Sinus_tab[];
+
+class NI_Sinus : public NeuroImpl
+{
+  public:
+double f0,t;
+NeuroImpl* makeNew() { return new NI_Sinus(); };
+NI_Sinus():f0(0),t(0)
+	{paramentries=NI_Sinus_tab;}
+void go()
+	{
+	t+=f0+getWeightedInputSum();
+	setState(sin(t));
+	}
+};
+
+#endif
+
Index: /cpp/gdk/neuroimpl.cpp
===================================================================
--- /cpp/gdk/neuroimpl.cpp	(revision 5)
+++ /cpp/gdk/neuroimpl.cpp	(revision 5)
@@ -0,0 +1,531 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "neuroimpl.h"
+#include "neurofactory.h"
+#ifndef NOCREATUREOBJECT
+#include "creature.h"
+#include "creatmechobj.h"
+#include "livegroups.h"
+#include "simul.h"
+#endif
+
+const int NeuroImpl::ENDDRAWING=-9999;
+const int NeuroImpl::MAXDRAWINGXY=0xffff;
+
+int NeuroNetImpl::mytags_id=0;
+
+/////////////////////////////////////////////////////////
+
+#define FIELDSTRUCT NeuroNetConfig
+static ParamEntry nncfg_paramtab[]=
+{
+{"Creature: Neurons",1,2,"nnsim",},
+{"randinit",1,0,"Random initialization","f 0 10 0.01",FIELD(randominit),"Initialize all neuron states with uniform distribution random numbers"},
+{"touchrange",1,0,"T receptor range","f 0 100 1",FIELD(touchrange),},
+{0,0,0,},
+}; 
+#undef FIELDSTRUCT
+
+NeuroNetConfig::NeuroNetConfig()
+	:par(nncfg_paramtab,this),
+	 randominit(0.01),
+	 touchrange(1)
+{}
+
+NeuroNetConfig NeuroNetConfig::globalconfig;
+
+/////////////////////////////////////////////////////////////////
+
+NeuroNetImpl::NeuroNetImpl(Model& model, NeuroNetConfig& conf
+#ifdef NEURO_SIGNALS
+, ChannelSpace *ch
+#endif
+)
+	:mod(model),config(conf),
+	 isbuilt(1),errorcount(0)
+#ifdef NEURO_SIGNALS
+,channels(ch)
+#endif
+{
+if (!mytags_id) mytags_id=mod.userdata.newID();
+
+Neuro *n;
+NeuroImpl *ni;
+Joint *j;
+int i;
+DB(printf("makeNeuroNet(%p)\n",&mod));
+
+minorder=3; maxorder=0;
+errorcount=0;
+
+for (i=0;j=mod.getJoint(i);i++)
+	j->flags&=~(4+8); // todo: !!!neuroitems shouldn't use model fields!!!
+
+for (i=0;n=mod.getNeuro(i);i++)
+	{
+	ni=NeuroFactory::createNeuroImpl(n);
+	n->userdata[mytags_id]=ni;
+	if (!ni) { errorcount++;
+		FMprintf("NeuroNetImpl","create",FMLV_WARN,"neuron #%d (%s) implementation not available",
+			 i,(const char*)n->getClassName());
+		continue; } // implementation not available?!
+	ni->owner=this;
+	ni->neuro=n;
+	ni->readParam();
+	}
+
+for (i=0;n=mod.getNeuro(i);i++)
+	{
+	n->state+=(rnd01-0.5)*config.randominit;
+	ni=(NeuroImpl*)n->userdata[mytags_id];
+	if (!ni) continue;
+	if (!ni->lateinit())
+		{ ni->status=NeuroImpl::InitError; errorcount++;
+		FMprintf("NeuroNetImpl","create",FMLV_WARN,"neuron #%d (%s) initialization failed",
+			 i,(const char*)n->getClassName());
+		continue; }
+	ni->status=NeuroImpl::InitOk;
+	int order=ni->getSimOrder();
+	if (order<0) order=0; else if (order>2) order=2;
+	if (order<minorder) minorder=order;
+	if (order>maxorder) maxorder=order;
+	neurons[order]+=ni;
+	if (ni->getNeedPhysics())
+		neurons[3]+=ni;
+	}
+cnode=mod.delmodel_list.add(STATRICKCALLBACK(this,&NeuroNetImpl::destroyNN,0));
+}
+
+void NeuroNetImpl::destroyNN(CALLBACKARGS)
+{
+if (!isbuilt) return;
+DB(printf("destroyNeuroNet(%p)\n",&mod));
+NeuroImpl *ni;
+Neuro *n;
+for (int i=0;n=mod.getNeuro(i);i++)
+	{
+	ni=(NeuroImpl*)n->userdata[mytags_id];
+	delete ni;
+	n->userdata[mytags_id]=0;
+	}
+mod.delmodel_list.remove(cnode);
+isbuilt=0; errorcount=0;
+delete this;
+}
+
+NeuroNetImpl::~NeuroNetImpl()
+{
+destroyNN(0,0);
+}
+
+void NeuroNetImpl::simulateNeuroNet()
+{
+NeuroImpl *ni;
+for (int order=minorder;order<=maxorder;order++)
+	{
+	int i;
+	SList &nlist=neurons[order];
+	for (i=0;ni=(NeuroImpl*)nlist(i);i++)
+		ni->go();
+	for (i=0;ni=(NeuroImpl*)nlist(i);i++)
+		ni->commit();
+	}
+}
+
+void NeuroNetImpl::simulateNeuroPhysics()
+{
+NeuroImpl *ni;
+int i;
+SList &nlist=neurons[3];
+for (i=0;ni=(NeuroImpl*)nlist(i);i++)
+	ni->goPhysics();
+}
+
+///////////////////////////////////////////////
+
+void NeuroImpl::setChannelCount(int c)
+{
+if (c<1) c=1;
+if (c==channels) return;
+if (c<channels) {channels=c; chstate.trim(c-1); chnewstate.trim(c-1); return;}
+double s=getState(channels-1);
+chnewstate.setSize(c-1);
+chstate.setSize(c-1);
+for(int i=channels;i<c;i++)
+	{chstate(i-1)=s; chnewstate(i-1)=s;}
+channels=c;
+}
+
+void NeuroImpl::setState(double st,int channel)
+{
+validateNeuroState(st);
+if (channel>=channels) channel=channels-1;
+if (channel<=0) {newstate=st;return;}
+chnewstate(channel-1)=st;
+}
+
+void NeuroImpl::setCurrentState(double st,int channel)
+{
+validateNeuroState(st);
+if (channel>=channels) channel=channels-1;
+if (channel<=0) {neuro->state=st; return;}
+chstate(channel-1)=st;
+}
+
+double NeuroImpl::getNewState(int channel)
+{
+if (neuro->flags&Neuro::HoldState) return getState(channel);
+if (channel>=channels) channel=channels-1;
+if (channel<=0) {return newstate;}
+return chnewstate(channel-1);
+}
+
+double NeuroImpl::getState(int channel)
+{
+if (channel>=channels) channel=channels-1;
+if (channel<=0) return neuro->state;
+return chstate(channel-1);
+}
+
+void NeuroImpl::commit()
+{
+if (!(neuro->flags&Neuro::HoldState))
+	{
+	if (channels>1)
+		chstate=chnewstate;
+	neuro->state=newstate;
+	}
+}
+
+int NeuroImpl::getInputChannelCount(int i)
+{
+if ((i<0)||(i >= neuro->getInputCount())) return 1;
+Neuro *nu=neuro->getInput(i);
+NeuroImpl *ni=NeuroNetImpl::getImpl(nu);
+if (!ni) return 1;
+return ni->channels;
+}
+
+double NeuroImpl::getInputState(int i,int channel)
+{
+if ((i<0)||(i >= neuro->getInputCount())) return 0;
+Neuro *nu=neuro->getInput(i);
+if (channel<=0) return nu->state;
+NeuroImpl *ni=NeuroNetImpl::getImpl(nu);
+if (!ni) return nu->state;
+if (channel>=ni->channels) channel=ni->channels-1;
+if (!channel) return nu->state;
+return ni->chstate(channel-1);
+}
+
+double NeuroImpl::getWeightedInputState(int i, int channel)
+{
+if ((i<0)||(i >= neuro->getInputCount())) return 0;
+float w;
+Neuro *nu=neuro->getInput(i,w);
+if (channel<=0) return nu->state * w;
+NeuroImpl *ni=NeuroNetImpl::getImpl(nu);
+if (!ni) return nu->state * w;
+if (channel>=ni->channels) channel=ni->channels-1;
+if (!channel) return w * nu->state;
+return w * ni->chstate(channel-1);
+}
+
+double NeuroImpl::getInputSum(int startwith)
+{
+if (startwith<0) return 0;
+Neuro *inp;
+double sum=0.0;
+while(inp=neuro->getInput(startwith++))
+	sum+=inp->state;
+return sum;
+}
+
+double NeuroImpl::getWeightedInputSum(int startwith)
+{
+if (startwith<0) return 0;
+Neuro *inp;
+double sum=0.0;
+float w;
+while(inp=neuro->getInput(startwith++,w))
+	sum+=inp->state*w;
+return sum;
+}
+
+void NeuroImpl::readParam()
+{
+static Param par;
+if (!paramentries) return;
+par.setParamTab(paramentries);
+par.select(this);
+par.setDefault();
+int zero=0;
+par.load2(neuro->getClassParams(),zero);
+}
+
+/////////////////////////////
+
+#ifdef NEURO_SIGNALS
+#define NEUROIMPL_SIGNAL_PROPS 1
+#else
+#define NEUROIMPL_SIGNAL_PROPS 0
+#endif
+
+#define FIELDSTRUCT NeuroImpl
+ParamEntry neuroimpl_tab[]=
+{
+{"Neuro",1,26+NEUROIMPL_SIGNAL_PROPS,"Neuro","Live Neuron object."},
+
+{"getInputState",0,0,"get input signal","p f(d input)",PROCEDURE(p_get),},
+{"getInputWeight",0,0,"get input weight","p f(d input)",PROCEDURE(p_getweight),},
+{"getWeightedInputState",0,0,"get weighted input signal","p f(d input)",PROCEDURE(p_getw),},
+{"getInputSum",0,0,"get signal sum","p f(d input)",PROCEDURE(p_getsum),},
+{"getWeightedInputSum",0,0,"get weighted signal sum","p f(d input)",PROCEDURE(p_getwsum),"uses any number of inputs starting with the specified input. getWeightedInputSum(0)=weightedInputSum"},
+{"getInputCount",0,0,"get input count","d",GETONLY(count),},
+{"inputSum",0,0,"full signal sum","f",GETONLY(sum),},
+{"weightedInputSum",0,0,"full weighted signal sum","f",GETONLY(wsum),},
+{"getInputChannelCount",0,0,"get channel count for input","p d(d input)",PROCEDURE(p_getchancount),},
+{"getInputStateChannel",0,0,"get input signal from channel","p f(d input,d channel)",PROCEDURE(p_getchan),},
+{"getWeightedInputStateChannel",0,0,"get weighted input signal from channel","p f(d input,d channel)",PROCEDURE(p_getwchan),},
+{"state",0,0,"neuron state (channel 0)","f",GETSET(state),"when read, returns the current neuron state.\nWhen written, sets the next neuron state (for use in the neuron definition)"},
+{"channelCount",0,0,"number of output channels","d",GETSET(channels),},
+{"getStateChannel",0,0,"get output state for channel","p f(d channel)",PROCEDURE(p_getstate),},
+{"setStateChannel",0,0,"set output state for channel","p(d channel,f value)",PROCEDURE(p_setstate),},
+{"hold",0,0,"Hold state","d 0 1",GETSET(hold),"",},
+{"currState",0,0,"neuron state (channel 0)","f",GETSET(cstate),"the only difference from the \"state\" field is that currState, when written, changes the internal neuron state immediately (which disturbs the regular synchronous NN operation). This feature should only be used while controlling the neuron 'from outside' (like a neuro probe) and not in the neuron definition.",},
+{"setCurrStateChannel",0,0,"set neuron for channel","p(d channel,f value)",PROCEDURE(p_setcstate),"like \"currState\""},
+{"position_x",0,0,"position x","f",GETONLY(position_x),},
+{"position_y",0,0,"position y","f",GETONLY(position_y),},
+{"position_z",0,0,"position z","f",GETONLY(position_z),},
+{"creature",0,0,"get owner creature","o Creature",GETONLY(creature),},
+{"part",0,0,"the Part object where this neuron is located","o MechPart",GETONLY(part),},
+{"joint",0,0,"the Joint object where this neuron is located","o MechJoint",GETONLY(joint),},
+{"fields",0,0,"custom neuron fields","o Fields",GETONLY(fields),
+"Neurons can have different fields depending on their class. Script neurons have their fields defined using the \"prop:\" syntax. If you develop a custom neuron script you should use the Fields object for accessing your own neuron fields. The Neuro.fields property is meant for accessing the neuron fields from the outside script.\n"
+"Examples:\n"
+"var c=LiveLibrary.createFromString(\"X[N]\");\n"
+"Simulator.print(\"standard neuron inertia=\"+c.getNeuro(0).fields.in);\n"
+"c=LiveLibrary.createFromString(\"X[Nn,e:0.1]\");\n"
+"Simulator.print(\"noisy neuron error rate=\"+c.getNeuro(0).fields.e);\n"
+"\n"
+"The Interface object can be used to discover which fields are available for a certain neuron object:\n"
+"c=LiveLibrary.createFromString(\"X[N]\");\n"
+"var iobj=Interface.makeFrom(c.getNeuro(0).fields);\n"
+"var i;\n"
+"for(i=0;i<iobj.properties;i++)\n"
+" Simulator.print(iobj.getId(i)+\" (\"+iobj.getName(i)+\")\");",},
+{"def",0,0,"Neuron definition from which this live neuron was built","o NeuroDef",GETONLY(neurodef),},
+#ifdef NEURO_SIGNALS
+{"signals",0,PARAM_READONLY,"Signals","o NeuroSignals",FIELD(sigs_obj),},
+#endif
+
+{0,0,0,},
+};
+#undef FIELDSTRUCT
+
+#ifdef NEURO_SIGNALS
+ParamEntry neurosignals_paramtab[]=
+ {
+{"NeuroSignals",1,8,"NeuroSignals","Signals attached to the neuron.\nSee also: Signal, WorldSignals, CreatureSignals.\nscripts/light.neuro and scripts/seelight.neuro are simple custom neuron examples demonstrating how to send/receive signals between creatures.",},
+
+#define FIELDSTRUCT NeuroSignals
+{"add",0,PARAM_NOSTATIC,"add","p(s channel)",PROCEDURE(p_add),"Create a new signal"},
+{"receive",0,PARAM_NOSTATIC,"receive","p f(s channel)",PROCEDURE(p_receive),"Receive the aggregated signal power in a given channel."},
+{"receiveSet",0,PARAM_NOSTATIC,"receive","p oVector(s channel,f max distance)",PROCEDURE(p_receiveSet),"Get all signals in the specified range. Returns a readonly vector object containing Signal objects (individual signals can be accessed as result[0] throught result[result.size-1])."},
+{"receiveFilter",0,PARAM_NOSTATIC,"receive","p f(s channel,f max distance,f flavor,f filter)",PROCEDURE(p_receiveFilter),"Receive the aggregated signal power in a given channel.\n\nAdditional filtering options:\n- Max distance only receives the neighbor signals (based on their physical location)\n- Flavor filtering: only signals having the flavor close to the specified one will be received. The filter value is the maximum allowed difference."},
+{"receiveSingle",0,PARAM_NOSTATIC,"receive","p oSignal(s channel,f range)",PROCEDURE(p_receiveSingle),"Find the signal source having the highest signal power (including the distance)"},
+#undef FIELDSTRUCT
+
+#define FIELDSTRUCT SignalSet
+{"get",0,PARAM_NOSTATIC,"get","p oSignal(d index)",PROCEDURE(p_get),},
+{"size",0,1+PARAM_NOSTATIC,"size","d",GETONLY(size),},
+{"clear",0,1+PARAM_NOSTATIC,"clear","p()",PROCEDURE(p_clear),},
+#undef FIELDSTRUCT
+{0,0,0,},
+ }; 
+Param neurosignals_param(neurosignals_paramtab,0);
+#endif
+
+Param st_neuroimplparam(neuroimpl_tab,0,"Neuro");
+
+#ifdef NEURO_SIGNALS
+class NeuroSigSource: public SigSource
+{
+  protected:
+NeuroImpl* owner;
+  public:
+NeuroSigSource(NeuroImpl *n,Creature *c):SigSource(0,c),owner(n) {}
+bool update();
+};
+
+bool NeuroSigSource::update()
+{
+Pt3D p;
+if (owner->getPosition(p))
+	{
+	setLocation(p);
+	return true;
+	}
+return false;
+}
+
+Creature *NeuroSignals::getCreature()
+{
+if (!cr)
+	{
+	cr=owner->getCreature();
+	}
+return cr;
+}
+
+void NeuroSignals::p_add(PARAMPROCARGS)
+{
+if (!owner->owner->channels) {ret->setEmpty();return;}
+SigChannel *ch=owner->owner->channels->getChannel(args->getString(),true);
+SigSource *s=new NeuroSigSource(owner,getCreature());
+ch->addSource(s);
+sigs+=s;
+s->setupObject(ret);
+}
+
+void NeuroSignals::p_receive(PARAMPROCARGS)
+{
+SigChannel *ch; Pt3D p;
+if (owner->owner->channels && (ch=owner->owner->channels->getChannel(args->getString(),false)) && owner->getPosition(p))
+	ret->setDouble(ch->receive(&p,getCreature()));
+else
+	ret->setDouble(0);
+}
+
+void NeuroSignals::p_receiveFilter(PARAMPROCARGS)
+{
+SigChannel *ch; Pt3D p;
+if (owner->owner->channels && (ch=owner->owner->channels->getChannel(args[3].getString(),false)) && owner->getPosition(p))
+	ret->setDouble(ch->receive(&p,getCreature(),args[2].getDouble(),args[1].getDouble(),args[0].getDouble()));
+else
+	ret->setDouble(0);
+}
+
+void NeuroSignals::p_receiveSet(PARAMPROCARGS)
+{
+SigChannel *ch; Pt3D p;
+SigVector *vec=new SigVector();
+if (owner->owner->channels && (ch=owner->owner->channels->getChannel(args[1].getString(),false)) && owner->getPosition(p))
+	ch->receiveSet(vec,&p,getCreature(),args[0].getDouble());
+ret->setObject(vec->makeObject());
+}
+
+void NeuroSignals::p_receiveSingle(PARAMPROCARGS)
+{
+SigChannel *ch; Pt3D p;
+if (owner->owner->channels && (ch=owner->owner->channels->getChannel(args[1].getString(),false)) && owner->getPosition(p))
+	{
+	SigSource *src=ch->receiveSingle(&p,getCreature(),args[0].getDouble(),0,1e99);
+	if (src)
+		{
+		src->setupObject(ret);
+		return;
+		}
+	}
+ret->setEmpty();
+}
+#endif
+
+extern ParamEntry creature_paramtab[];
+static Param creature_param(creature_paramtab,0);
+
+Creature* NeuroImpl::getCreature()
+{
+#ifndef NOCREATUREOBJECT
+CreatMechObject *cmo=(CreatMechObject *)neuro->owner->userdata[CreatMechObject::modeltags_id];
+return cmo->creature;
+#else
+return 0;
+#endif
+}
+
+void NeuroImpl::get_creature(ExtValue *ret)
+{
+#ifndef NOCREATUREOBJECT
+ret->setObject(ExtObject(&creature_param,getCreature()));
+#endif
+}
+
+void NeuroImpl::get_part(ExtValue *ret)
+{
+#ifndef NOCREATUREOBJECT
+Part *pa;
+if (pa=neuro->getPart())
+	ret->setObject(ExtObject(&mechpart_param,((MechPart *)pa->userdata[CreatMechObject::modeltags_id])));
+else
+	ret->setEmpty();
+#endif
+}
+
+void NeuroImpl::get_joint(ExtValue *ret)
+{
+#ifndef NOCREATUREOBJECT
+Joint *jo;
+if (jo=neuro->getJoint())
+	ret->setObject(ExtObject(&mechjoint_param,((MechJoint*)jo->userdata[CreatMechObject::modeltags_id])));
+else
+	ret->setEmpty();
+#endif
+}
+
+bool NeuroImpl::getPosition(Pt3D &pos)
+{
+#ifndef NOCREATUREOBJECT
+Part *pa; Joint *jo;
+if (pa=neuro->getPart())
+	{pos=((MechPart *)pa->userdata[CreatMechObject::modeltags_id])->p; return true;}
+if (jo=neuro->getJoint())
+	{
+	if (neuro->getClass()->getVisualHints() & NeuroClass::AtFirstPart)
+		pos=((MechPart*)jo->part1->userdata[CreatMechObject::modeltags_id])->p;
+	else if (neuro->getClass()->getVisualHints() & NeuroClass::AtSecondPart)
+		pos=((MechPart*)jo->part2->userdata[CreatMechObject::modeltags_id])->p;
+	else pos=(((MechPart*)jo->part1->userdata[CreatMechObject::modeltags_id])->p
+		   +((MechPart*)jo->part2->userdata[CreatMechObject::modeltags_id])->p)/2;
+	return true;
+	}
+#endif
+return false;
+}
+
+void NeuroImpl::get_position_x(ExtValue *ret)
+{Pt3D pos; if (getPosition(pos)) ret->setDouble(pos.x); else ret->setEmpty();}
+void NeuroImpl::get_position_y(ExtValue *ret)
+{Pt3D pos; if (getPosition(pos)) ret->setDouble(pos.y); else ret->setEmpty();}
+void NeuroImpl::get_position_z(ExtValue *ret)
+{Pt3D pos; if (getPosition(pos)) ret->setDouble(pos.z); else ret->setEmpty();}
+
+
+void NeuroImpl::createFieldsObject()
+{
+fields_param=new Param(paramentries?paramentries:(ParamEntry*)&empty_paramtab,this,"Fields");
+fields_object=new ExtObject(fields_param);
+}
+
+void NeuroImpl::get_fields(ExtValue *ret)
+{
+if (!fields_object)
+	createFieldsObject();
+ret->setObject(*fields_object);
+}
+
+void NeuroImpl::get_neurodef(ExtValue *ret)
+{
+ret->setObject(ExtObject(&st_neuroparam,neuro));
+}
+
+NeuroImpl::~NeuroImpl()
+{
+if (fields_param)
+	{
+	delete fields_param;
+	delete fields_object;
+	}
+}
Index: /cpp/gdk/neuroimpl.h
===================================================================
--- /cpp/gdk/neuroimpl.h	(revision 5)
+++ /cpp/gdk/neuroimpl.h	(revision 5)
@@ -0,0 +1,299 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _NEUROIMPL_H_
+#define _NEUROIMPL_H_
+
+#include "model.h"
+#include "param.h"
+#include "framsg.h"
+#ifdef NEURO_SIGNALS
+#include "signals.h"
+#endif
+
+class NeuroImpl;
+extern ParamEntry neuroimpl_tab[];
+#ifdef NEURO_SIGNALS
+extern Param neurosignals_param;
+#endif
+
+class Creature;
+
+class NeuroNetConfig
+{
+public:
+NeuroNetConfig();
+
+Param par;
+double randominit;
+double touchrange;
+
+static NeuroNetConfig globalconfig;
+};
+
+#ifdef NEURO_SIGNALS
+class NeuroSignals: public SignalSet
+{
+  protected:
+Creature *cr;
+NeuroImpl *owner;
+Creature *getCreature();
+  public:
+
+NeuroSignals(NeuroImpl *n):owner(n),cr(0) {}
+
+#define STATRICKCLASS NeuroSignals
+PARAMPROCDEF(p_add);
+PARAMPROCDEF(p_get);
+PARAMGETDEF(size);
+PARAMPROCDEF(p_receive);
+PARAMPROCDEF(p_receiveSet);
+PARAMPROCDEF(p_receiveFilter);
+PARAMPROCDEF(p_receiveSingle);
+#undef STATRICKCLASS
+};
+#endif
+
+/// Neuro net implementation
+class NeuroNetImpl
+{
+CallbackNode *cnode;
+Model &mod;
+SList neurons[4];
+NeuroNetConfig& config;
+int isbuilt,errorcount;
+STCALLBACKDEFC(NeuroNetImpl,destroyNN);
+int minorder,maxorder;
+
+  public:
+#ifdef NEURO_SIGNALS
+ChannelSpace *channels;
+#endif
+static int mytags_id;
+static double getStateFromNeuro(Neuro *n);
+int getErrorCount() {return errorcount;}
+NeuroNetImpl(Model& model, NeuroNetConfig& conf = NeuroNetConfig::globalconfig
+#ifdef NEURO_SIGNALS
+, ChannelSpace *ch=0
+#endif
+);
+~NeuroNetImpl();
+void simulateNeuroNet();
+void simulateNeuroPhysics();
+
+static NeuroImpl *getImpl(Neuro* n) {return (NeuroImpl*)n->userdata[mytags_id];}
+};
+
+
+/**
+   Neuro implementation - this object calculates the Neuron's state
+   (Neuro::state) in each simulation step.
+
+SUBCLASSING TUTORIAL
+====================
+
+1.Derive your custom neuron from NeuroImpl class. The name must be prefixed with NI_
+
+class NI_MyNeuron: public NeuroImpl
+{ ... };
+
+2.Public parameters
+Create any number of public fields, they will be adjustable from the genotype level.
+3 datatypes are supported: long, double and SString
+
+public:
+  long intParameter;
+  double fpParameter;
+  SString txtParameter;
+
+
+3.Required method: "instantiator".
+It is always the same, just create a new instance of your neuron.
+public:
+  NeuroImpl* makeNew() { return new NI_MyNeuron(); };
+
+
+4.Required method: default constructor
+Set the "paramentries" variable if you need public parameters in your neuron.
+NI_..._tab is created automatically and should be declared as: extern ParamEntry NI_..._tab[];
+At this stage the parameter values are not yet available.
+
+public:
+ NI_MyNeuron() // no parameters!
+ {
+ paramentries=NI_MyNeuron_tab;
+ // you add here: some general initialization
+ }
+
+
+5.Optional method: initialization
+This method is called once before the neuron is actually used in the simulation.
+The parameter values are already initialized (according to the genotype) and the neuron is bound to the creature (i.e. this->neuro is valid).
+Return 0 if the neuron cannot be initialized.
+
+int lateinit()
+ {
+ // you add here: initialization using full neuron context
+ // example: if (!neuro->joint) return 0; //this neuron must be attached to joint
+ return 1;//OK
+ }
+
+
+6.Required method: simulation step
+If it has output: calculate the next neuron state and call setState()
+If it is an effector: do anything else
+
+void go()
+ {
+ // you add here: things called every simulation step
+ }
+
+Note: You can make your neuron fire before or after "regular" neurons by changing its "simorder" property (during initialization). The default value is 1, whereas receptors have simorder=0 and effectors have simorder=2.
+
+
+7.Neuron definition
+In order to incorporate the new neuron into Framsticks you need to provide some additional information (to be added to "f0.def" file).
+
+NEUROCLASS(MyNeuron,MN,This is the name,`Neuron description',-1,1,0)
+NEUROPROP(int,0,0,name of the int,d,,,,intParameter)
+NEUROPROP(fp,0,0,name of the floating point,f,,,,fpParameter)
+NEUROPROP(txt,0,0,name of the text,s,,,,txtParameter)
+ENDNEUROCLASS 
+
+NEUROCLASS:
+- MyNeuron: neuron class name (without the NI_ prefix)
+- MN: neuron symbol (used in genotypes)
+- full name and description
+- -1: preferred number of inputs (special case: -1=any)
+- 1: provides output: 1=yes/0=no
+- 0: preferred location: 0=none, 1=part, 2=joint
+
+NEUROPROP:
+- int/fp/txt: parameter names as visible in genotypes and scripting
+- "name of the ...": descriptive name
+- d/f/s: type (int/floating point/string)
+- intParameter/fpParameter/txtParameter: C++ field names
+
+   
+ */
+class NeuroImpl
+{
+protected:
+int simorder;
+int channels;
+SListTempl<double> chstate;
+SListTempl<double> chnewstate;
+Param *fields_param;
+ExtObject *fields_object;
+public:
+static const int ENDDRAWING;
+static const int MAXDRAWINGXY;
+
+enum NeuroImplStats { BeforeInit=0, InitError=1, InitOk=2 };
+NeuroImplStats status;
+/** originating neuron object (from the model) */
+Neuro *neuro;
+/** don't access directly */
+double newstate;
+
+#ifdef NEURO_SIGNALS
+NeuroSignals sigs;
+#endif
+NeuroNetImpl *owner;
+ExtObject sigs_obj;
+
+/** "virtual constructor" - NeuroFactory uses this method to create the proper implementation object.
+    subclasses must return new object here. */
+virtual NeuroImpl* makeNew() {return 0;} // 
+/** will be used by readParam() method, if not null  */
+ParamEntry *paramentries; // no extra properties if ==0
+/** read additional properties from "moredata" field of the originating Neuro */
+void readParam();
+/** called when all other neuro objects were already created and "moredata" transferred to
+    object fields.
+    useful for initialization that cannot be performed in the constructor.
+    @return 1=ok  0=failure
+*/
+virtual int lateinit() {return 1;}
+/** calculate 'newstate - implementation dependent */
+virtual void go(){}
+/** for neurons doing some physical actions (called each simulation step when nnspeed!=1.0) */
+virtual void goPhysics(){}
+
+int getSimOrder() {return simorder;}
+virtual int getNeedPhysics() {return 0;}
+
+void setChannelCount(int c);
+int getChannelCount() {return channels;}
+
+int getInputCount() {return neuro->getInputCount();}
+int getInputChannelCount(int i);
+double getInputState(int i,int channel=0);
+double getWeightedInputState(int i,int channel=0);
+double getInputSum(int startwith=0);
+double getWeightedInputSum(int startwith=0);
+double getInputWeight(int i) {return neuro->getInputWeight(i);}
+void setState(double st,int channel);
+void setState(double st) {validateNeuroState(st); newstate=st;}
+double getState(int channel);
+double getState() {return neuro->state;}
+
+virtual int getDrawingCount() {return 0;}
+virtual int* getDrawing(int i) {return 0;}
+
+void commit();
+void validateNeuroState(double& st) {if (st<=-1e10) st=-1e10; else if (st>1e10) st=1e10;}
+
+NeuroImpl():owner(0),neuro(0),newstate(0),paramentries(0),simorder(1),status(BeforeInit),channels(1),fields_param(0),fields_object(0)
+#ifdef NEURO_SIGNALS
+,sigs(this),sigs_obj(&neurosignals_param,&sigs)
+#endif
+ {}
+virtual ~NeuroImpl();
+virtual void createFieldsObject();
+
+/** usually == "newstate" but will obey the "hold state" */
+double getNewState(int channel=0);
+
+/** don't use! */
+void setCurrentState(double st,int channel=0);
+
+bool getPosition(Pt3D &pos);
+Creature* getCreature();
+
+#define STATRICKCLASS NeuroImpl
+PARAMGETDEF(count) {arg1->setInt(getInputCount());}
+PARAMPROCDEF(p_get) {arg2->setDouble(getInputState(arg1->getInt()));}
+PARAMPROCDEF(p_getweight) {arg2->setDouble(getInputWeight(arg1->getInt()));}
+PARAMPROCDEF(p_getw) {arg2->setDouble(getWeightedInputState(arg1->getInt()));}
+PARAMPROCDEF(p_getsum) {arg2->setDouble(getInputSum(arg1->getInt()));}
+PARAMPROCDEF(p_getwsum) {arg2->setDouble(getWeightedInputSum(arg1->getInt()));}
+PARAMGETDEF(sum) {arg1->setDouble(getInputSum(0));}
+PARAMGETDEF(wsum) {arg1->setDouble(getWeightedInputSum(0));}
+PARAMPROCDEF(p_getchancount) {arg2->setInt(getInputChannelCount(arg1->getInt()));}
+PARAMPROCDEF(p_getchan) {arg2->setDouble(getInputState(arg1[1].getInt(),arg1[0].getInt()));}
+PARAMPROCDEF(p_getwchan) {arg2->setDouble(getWeightedInputState(arg1[1].getInt(),arg1[0].getInt()));}
+PARAMGETDEF(state) {arg1->setDouble(getState());}
+PARAMSETDEF(state) {setState(arg1->getDouble()); return 0;}
+PARAMGETDEF(cstate) {arg1->setDouble(neuro->state);}
+PARAMSETDEF(cstate) {setCurrentState(arg1->getDouble()); return 0;}
+PARAMGETDEF(hold) {arg1->setInt((neuro->flags&(Neuro::HoldState))?1:0);}
+PARAMSETDEF(hold) {neuro->flags=(neuro->flags&~Neuro::HoldState)|(arg1->getInt()?Neuro::HoldState:0); return 0;}
+PARAMGETDEF(channels) {arg1->setInt(getChannelCount());}
+PARAMSETDEF(channels) {setChannelCount(arg1->getInt()); return 0;}
+PARAMPROCDEF(p_getstate) {arg2->setDouble(getState(arg1->getInt()));}
+PARAMPROCDEF(p_setstate) {setState(arg1[0].getDouble(),arg1[1].getInt());}
+PARAMPROCDEF(p_setcstate) {setCurrentState(arg1[0].getDouble(),arg1[1].getInt());}
+PARAMGETDEF(creature);
+PARAMGETDEF(part);
+PARAMGETDEF(joint);
+PARAMGETDEF(position_x);
+PARAMGETDEF(position_y);
+PARAMGETDEF(position_z);
+PARAMGETDEF(fields);
+PARAMGETDEF(neurodef);
+#undef STATRICKCLASS
+};
+
+#endif
Index: /cpp/gdk/neuroimplfiles.h
===================================================================
--- /cpp/gdk/neuroimplfiles.h	(revision 5)
+++ /cpp/gdk/neuroimplfiles.h	(revision 5)
@@ -0,0 +1,8 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "neuroimpl-simple.h"
+#include "neuroimpl-channels.h"
+#include "neuroimpl-fuzzy.h"
+#include "neuroimpl-body-gdk.h"
Index: /cpp/gdk/neurolibrary.cpp
===================================================================
--- /cpp/gdk/neurolibrary.cpp	(revision 5)
+++ /cpp/gdk/neurolibrary.cpp	(revision 5)
@@ -0,0 +1,71 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "neurolibrary.h"
+#include "param.h"
+#include "modelparts.h"
+
+NeuroLibrary NeuroLibrary::staticlibrary;
+
+int NeuroLibrary::findClassIndex(const SString & classname, bool activeonly)
+{
+NeuroClass* cl;
+for(int i=0;cl=(NeuroClass*)classes(i);i++)
+	{
+	if (activeonly && !cl->active) continue;
+	if (classname == cl->getName()) return i;
+	}
+return -1;
+}
+
+NeuroClass* NeuroLibrary::findClass(const SString & classname, bool activeonly)
+{
+int i=findClassIndex(classname,activeonly);
+if (i<0) return 0;
+return getClass(i);
+}
+
+NeuroClass *NeuroLibrary::addClass(NeuroClass *cls,bool replace)
+{
+NeuroClass *old=findClass(cls->getName());
+if (old)
+	{
+	if (replace)
+		{
+		classes-=old;
+		classes+=cls;
+		}
+	}
+else
+	classes+=cls;
+return old;
+}
+
+void NeuroLibrary::addStandardClasses()
+{
+#include "neurocls-library.h"
+}
+
+NeuroLibrary::NeuroLibrary()
+{
+addStandardClasses();
+}
+
+NeuroLibrary::~NeuroLibrary()
+{
+FOREACH(NeuroClass*,cl,classes)
+	delete cl;
+}
+
+void NeuroLibrary::removeClass(int i)
+{
+classes-=i;
+}
+
+void NeuroLibrary::clear()
+{
+while(getClassCount()>0)
+	removeClass(getClassCount()-1);
+}
+
Index: /cpp/gdk/neurolibrary.h
===================================================================
--- /cpp/gdk/neurolibrary.h	(revision 5)
+++ /cpp/gdk/neurolibrary.h	(revision 5)
@@ -0,0 +1,30 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _NILIBRARY_H_
+#define _NILIBRARY_H_
+
+#include "advlist.h"
+#include "param.h"
+
+class NeuroClass;
+
+class NeuroLibrary
+{
+  public:
+static NeuroLibrary staticlibrary;
+NeuroLibrary();
+~NeuroLibrary();
+AdvList classes;
+NeuroClass* findClass(const SString& classname, bool activeonly=1);
+void addStandardClasses();
+int findClassIndex(const SString& classname, bool activeonly=1);
+NeuroClass* getClass(int classindex) {return (NeuroClass*)classes(classindex);}
+int getClassCount() {return classes.size();}
+void removeClass(int i);
+void clear();
+NeuroClass *addClass(NeuroClass *cls,bool replace=1);
+};
+
+#endif
Index: /cpp/gdk/neurotest.cpp
===================================================================
--- /cpp/gdk/neurotest.cpp	(revision 5)
+++ /cpp/gdk/neurotest.cpp	(revision 5)
@@ -0,0 +1,141 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "geno.h"
+#include "stdiofile.h"
+#include "sstringutils.h"
+#include "defgenoconv.h"
+#include "neuroimpl.h"
+#include "neurofactory.h"
+#include "stdouterr.h"
+
+/**
+ @file
+ Sample code: Neural network tester (can run your custom neurons)
+*/
+
+StdoutErrorHandler err; //redirect model-related errors to stdout
+DefaultGenoConvManager gcm; //without this object the application would only handle "format 0" genotypes
+
+#ifndef NOCREATUREOBJECT
+#include "creatmechobj.h"
+int CreatMechObject::modeltags_id=0;
+int CreatMechObject::mechtags_id=0;
+#endif
+
+ParamEntry creature_paramtab[]={0};
+
+#ifdef VEYETEST
+#include "neuroimpl-vectoreye.h"
+
+#define N_VEye 0
+#define N_VMotor 1
+#define N_Mode 2
+#define N_Fitness 3
+#define LEARNINGSTEPS 50
+
+void veyeStep(Model &m,int step)
+{
+  static float angle=0;
+
+  NeuroNetImpl::getImpl(m.getNeuro(N_Mode))->setState(step>=LEARNINGSTEPS); //0 (learning) or 1 (normal)
+
+	NeuroImpl *ni=NeuroNetImpl::getImpl(m.getNeuro(N_VEye));
+  ((NI_VectorEye*)ni)->relpos.y=0;
+  ((NI_VectorEye*)ni)->relpos.z=0;
+  if (NeuroNetImpl::getImpl(m.getNeuro(N_Mode))->getNewState()<0.5)
+  { //learning
+    ((NI_VectorEye*)ni)->relpos.x=5.0*sin(2*M_PI*step/LEARNINGSTEPS);
+  }
+  else
+  { //VMotor controls location of VEye
+    angle+=NeuroNetImpl::getImpl(m.getNeuro(N_VMotor))->getState();
+    angle=fmod((double)angle,M_PI*2.0);
+    ((NI_VectorEye*)ni)->relpos.x=5*sin(angle);
+  }
+
+  NeuroNetImpl::getImpl(m.getNeuro(N_Fitness))->setState(angle); //wymaga poprawy
+  //oraz trzeba przemyslec kolejnosc get/set'ow neuronow zeby sygnal sie dobrze propagowal.
+}
+#endif
+
+int main(int argc,char*argv[])
+{
+if (argc<=1)
+	{
+	puts("no genotype");
+	return 10;
+	}
+SString gen(argv[1]);
+if (!strcmp(gen,"-"))
+	{
+	gen=0;
+	StdioFILEDontClose in(stdin);
+	loadSString(&in,gen);
+	}
+Geno g(gen);
+if (!g.isValid()) {puts("invalid genotype");return 5;}
+Model m(g);
+if (!m.getNeuroCount()) {puts("no neural network");return 1;}
+printf("%d neurons,",m.getNeuroCount());
+NeuroFactory::setImplementation();
+NeuroNetImpl *nn=new NeuroNetImpl(m);
+int i; Neuro *n;
+if (!nn->getErrorCount()) printf(" no errors\n");
+else
+	{
+	printf(" %d errors:",nn->getErrorCount());
+	int no_impl=0; SString no_impl_names;
+	int init_err=0; SString init_err_names;
+	for(i=0;i<m.getNeuroCount();i++)
+		{
+		n=m.getNeuro(i);
+		NeuroImpl *ni=NeuroNetImpl::getImpl(n);
+		if (!ni)
+			{
+			if (no_impl) no_impl_names+=',';
+			sprintf(no_impl_names.directAppend(100),"#%d.%s",
+				i,(const char*)n->getClassName());
+			no_impl_names.endAppend();
+			no_impl++;
+			}
+		else if (ni->status==NeuroImpl::InitError)
+			{
+			if (init_err) init_err_names+=',';
+			sprintf(init_err_names.directAppend(100),"#%d.%s",
+				i,(const char*)n->getClassName());
+			init_err_names.endAppend();
+			init_err++;
+			}
+		}
+	printf("\n");
+	if (no_impl) printf("%d x missing implementation (%s)\n",no_impl,(const char*)no_impl_names);
+	if (init_err) printf("%d x failed initialization (%s)\n",init_err,(const char*)init_err_names);
+	}
+int steps=1;
+if (argc>2) steps=atol(argv[2]);
+int st;
+printf("step");
+for(i=0;i<m.getNeuroCount();i++)
+	{
+	n=m.getNeuro(i);
+	printf("\t#%d.%s",i,(const char*)n->getClassName());
+	}
+printf("\n");
+for(st=0;st<=steps;st++)
+	{
+#ifdef VEYETEST
+  veyeStep(m,st);
+#endif
+	printf("%d",st);
+	for(i=0;i<m.getNeuroCount();i++)
+		{
+		n=m.getNeuro(i);
+		printf("\t%g",n->state);
+		}
+	printf("\n");
+	nn->simulateNeuroNet();
+	}
+NeuroFactory::freeImplementation();
+}
Index: /cpp/gdk/neurotest.dsp
===================================================================
--- /cpp/gdk/neurotest.dsp	(revision 5)
+++ /cpp/gdk/neurotest.dsp	(revision 5)
@@ -0,0 +1,311 @@
+# Microsoft Developer Studio Project File - Name="neurotest" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=neurotest - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "neurotest.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "neurotest.mak" CFG="neurotest - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "neurotest - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ""
+# PROP Intermediate_Dir ""
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /W3 /Gm /GR /GX /ZI /Od /D "_Windows" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "EASYMAPDEBUG" /D "NOCREATUREOBJECT" /FD /GZ /c
+# SUBTRACT CPP /nologo /YX /Yc /Yu
+# ADD BASE RSC /l 0x415 /d "_DEBUG"
+# ADD RSC /l 0x415 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# Begin Target
+
+# Name "neurotest - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\3d.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\advlist.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\callbacks.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\conv_f1.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\defgenoconv.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\errmanager.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\extvalue.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\framsg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\geno.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\genoconv.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\list.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\model.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modelparts.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\multimap.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\multirange.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\neurofactory.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=".\neuroimpl-channels.cpp"
+# End Source File
+# Begin Source File
+
+SOURCE=".\neuroimpl-fuzzy-f0.cpp"
+# End Source File
+# Begin Source File
+
+SOURCE=".\neuroimpl-fuzzy.cpp"
+# End Source File
+# Begin Source File
+
+SOURCE=".\neuroimpl-simple.cpp"
+# End Source File
+# Begin Source File
+
+SOURCE=.\neuroimpl.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\neurolibrary.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\neurotest.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\param.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\paramobj.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\paramtabobj.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sstring.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sstringutils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\stdouterr.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\syntparam.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\virtfile.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\3d.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\advlist.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\callbacks.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\conv_f1.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\defassign-f0_joint.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\defassign-f0_neuro.h"
+# End Source File
+# Begin Source File
+
+SOURCE=".\defassign-f0_part.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\defgenoconv.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\extvalue.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\f0classes.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\framsg.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\gen-config.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\geno.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\genoconv.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\list.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\model.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\modelparts.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\multimap.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\multirange.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\neuroclasses.h
+# End Source File
+# Begin Source File
+
+SOURCE=".\neurocls-library.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\neurolibrary.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\nonstd.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\param.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\paramtabobj.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\printconvmap.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\sstring.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\sstringutils.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\statrick.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\syntparam.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\usertags.h
+# End Source File
+# End Group
+# End Target
+# End Project
Index: /cpp/gdk/nonstd.h
===================================================================
--- /cpp/gdk/nonstd.h	(revision 5)
+++ /cpp/gdk/nonstd.h	(revision 5)
@@ -0,0 +1,98 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+//Define rnd01, rnd0N, and randomN so that they
+//work in your C++ environment.
+//Some other functions/macros may also be needed if they
+//are missing in your environment, like min, max, etc.
+
+#ifndef __NONSTD_H
+#define __NONSTD_H
+
+#define APPLICATION_NAME "Framsticks"
+#define MAIN_FRAMSTICKS
+#define SAFEDELETE(p) {if (p) {delete p; p=NULL;}}
+#define SAFEDELETEARRAY(p) {if (p) {delete[] p; p=NULL;}}
+
+//#ifndef _Windows   included below?
+//#include <stdlib.h>
+//#endif
+
+#define DB(x) //output debug info. If needed, use #define DB(x) x
+//#define DB(x) x
+
+// ms visual c++
+#ifdef _MSC_VER
+ #define WIN32_LEAN_AND_MEAN     // Exclude rarely-used stuff from Windows headers
+ #include <windows.h>
+ #include <stdio.h>
+ #include <stdarg.h>
+ #define vsnprintf _vsnprintf
+ #define _USE_MATH_DEFINES
+
+ #ifndef M_PI
+ #define M_PI 3.1415926535897932384626433832795
+ #endif
+ #ifndef M_PI_2
+ #define M_PI_2 (M_PI/2)
+ #endif
+
+#endif
+
+/////////////////////////////////////////////////////// 64-bit int type and other macros
+#ifdef _Windows
+	typedef __int64 LONGLONG;
+	#define PATHSEPARATORCHAR '\\'
+	#define PATHSEPARATORSTRING "\\"
+	#define FPU_THROWS_EXCEPTIONS
+#else
+	#define LONGLONG long long int
+	#define PATHSEPARATORCHAR '/'
+	#define PATHSEPARATORSTRING "/" 
+#endif
+
+#ifdef __BORLANDC__
+	#define fileExists(f) (!access(f,0))
+        #include "stdlib.h" //random
+	#define FOPEN_READ "rt"
+	#define FOPEN_WRITE "wt"
+	#define FOPEN_APPEND "at"
+	#define rnd01 ((double)((double)_lrand()/(double)(LRAND_MAX+1)))
+	//#define rnd01 ((double)((double)rand()/(RAND_MAX+1)))
+	#define rnd0N(num) ((double)((num)*rnd01))
+	#define randomN(num) random(num) //uses _lrand
+#else
+	#ifdef _MSC_VER
+	#define fileExists(f) (!access(f,0))
+	#else
+	#define fileExists(f) (!access(f,R_OK))
+	#endif
+
+	#define FOPEN_WRITE "wa"
+	#define FOPEN_APPEND "aa"
+	#define FOPEN_READ "ra"
+	//#define FLOATRAND
+	#ifdef FLOATRAND
+		#define randomN(x) ((int)((x)*drand48()))
+		#define rnd01 (drand48())
+  		#define rnd0N(x) (drand48()*(x))
+	#else
+		#define rnd01 ((double)(rand()/(RAND_MAX+1.0)))
+		#define rnd0N(x) ((x)*rnd01)
+		#define randomN(x) ((int)rnd0N(x))
+	#endif
+#endif
+
+
+#ifdef __GNUC__
+/*
+	#define min(a,b) (((a)>(b))?(b):(a))
+	#define max(a,b) (((a)>(b))?(a):(b))
+	#define abs(a) ((a)>=0?(a):-(a))
+*/
+#include <algorithm>
+using namespace std;
+#endif
+
+#endif
Index: /cpp/gdk/nonstd_io.h
===================================================================
--- /cpp/gdk/nonstd_io.h	(revision 5)
+++ /cpp/gdk/nonstd_io.h	(revision 5)
@@ -0,0 +1,15 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+// int access(const char *pathname, int mode);
+#ifdef _Windows
+ #include <dir.h> 
+ #include <io.h> //include io.h przed dir.h powoduje ze w simul.h nie poznaje klasy SimWorld - szokujacy i niewyjasniony blad.
+ #define makeDirectory(name) mkdir(name) 
+#else
+ #include <unistd.h>
+ #include <sys/stat.h>
+ #define makeDirectory(name) mkdir(name,0777)
+#endif
+
Index: /cpp/gdk/param.cpp
===================================================================
--- /cpp/gdk/param.cpp	(revision 5)
+++ /cpp/gdk/param.cpp	(revision 5)
@@ -0,0 +1,907 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include "param.h"
+#include "extvalue.h"
+#include "framsg.h"
+#include "sstringutils.h"
+
+//#define SAVE_ALL_NAMES
+#define SAVE_SELECTED_NAMES
+#define WARN_MISSING_NAME
+
+char MakeCodeGuardHappy;
+
+ParamEntry empty_paramtab[]=
+{ {"Empty",1,0,"Empty",}, {0,0,0,}, }; 
+
+static void czytdotyldy(VirtFILE *f,SString &s)
+{
+SString temp;
+int z;
+char last_char=0;
+while((z=fgetc(f))!=EOF)
+	{
+	if (z=='~')
+		if (last_char!='\\') break;
+	last_char=(char)z;
+	temp+=last_char;
+	}
+s=temp;
+}
+
+static const char *strchrlimit(const char *t,int ch,const char *limit)
+{
+int n=limit-t;
+for (;(n>0)&&*t;t++,n--)
+	if (*t==ch) return t;
+return 0;
+}
+
+static char* fgets0(char*t,int d,VirtFILE *f, bool& eolfound)
+{
+char *r=fgets(t,d,f);
+eolfound=false;
+if (r)
+	{
+	int d=strlen(r);
+	while (d-- > 0) if ((r[d]=='\r')||(r[d]=='\n')) {r[d]=0; eolfound=true;} else break;
+	}
+return r;
+}
+
+void ParamInterface::copyFrom(ParamInterface *src)
+{
+int n=getPropCount();
+ExtValue v;
+int j;
+for(int i=0;i<n;i++)
+  if ((!(flags(i)&PARAM_READONLY))
+	  && (*type(i)!='p'))
+	{
+	j=src->findId(id(i));
+	if (j<0) continue;
+	src->get(j,v);
+	set(i,v);
+	}
+}
+
+void ParamInterface::quickCopyFrom(ParamInterface *src)
+{
+int n=getPropCount();
+ExtValue v;
+for(int i=0;i<n;i++)
+  if ((!(flags(i)&PARAM_READONLY))
+	  && (*type(i)!='p'))
+	  {
+	  src->get(i,v);
+	  set(i,v);
+	  }
+}
+
+int ParamInterface::getMinMax(int prop,long& minumum,long& maximum,long &def)
+{
+const char* t=type(prop)+1;
+while(*t) if (*t==' ') break; else t++;
+return sscanf(t,"%ld %ld %ld",&minumum,&maximum,&def);
+}
+
+int ParamInterface::getMinMax(int prop,double& minumum,double& maximum,double& def)
+{
+const char* t=type(prop)+1;
+while(*t) if (*t==' ') break; else t++;
+return sscanf(t,"%lg %lg %lg",&minumum,&maximum,&def);
+}
+
+void ParamInterface::setDefault(bool numericonly)
+{
+int n=getPropCount();
+for(int i=0;i<n;i++)
+	setDefault(i,numericonly);
+}
+
+void ParamInterface::setMin()
+{
+int n=getPropCount();
+for(int i=0;i<n;i++)
+	setMin(i);
+}
+
+void ParamInterface::setMax()
+{
+int n=getPropCount();
+for(int i=0;i<n;i++)
+	setMax(i);
+}
+
+void ParamInterface::setDefault(int i,bool numericonly)
+{
+const char *t=type(i);
+switch(*t)
+	{
+	case 'f':
+	{
+	double a=0,b=0,c=0;
+	getMinMax(i,a,b,c);
+	setDouble(i,c);
+	}
+	break;
+	case 'd':
+	{
+	long a=0,b=0,c=0;
+	getMinMax(i,a,b,c);
+	setInt(i,c);
+	}
+	break;
+	default: if (!numericonly) set(i,"");
+	}
+}
+
+void ParamInterface::setMin(int i)
+{
+const char *t=type(i);
+switch(*t)
+	{
+	case 'f':
+	{
+	double a=0,b=0,c=0;
+	getMinMax(i,a,b,c);
+	setDouble(i,a);
+	}
+	break;
+	case 'd':
+	{
+	long a=0,b=0,c=0;
+	getMinMax(i,a,b,c);
+	setInt(i,a);
+	}
+	break;
+	default: set(i,"");
+	}
+}
+
+void ParamInterface::setMax(int i)
+{
+const char *t=type(i);
+switch(*t)
+	{
+	case 'f':
+	{
+	double a=0,b=0,c=0;
+	getMinMax(i,a,b,c);
+	setDouble(i,b);
+	}
+	break;
+	case 'd':
+	{
+	long a=0,b=0,c=0;
+	getMinMax(i,a,b,c);
+	setInt(i,b);
+	}
+	break;
+	default: set(i,"");
+	}
+}
+
+SString ParamInterface::getStringById(const char*prop)
+{int i=findId(prop); if (i>=0) return getString(i); else return SString();}
+long ParamInterface::getIntById(const char*prop)
+{int i=findId(prop); if (i>=0) return getInt(i); else return 0;}
+double ParamInterface::getDoubleById(const char*prop)
+{int i=findId(prop); if (i>=0) return getDouble(i); else return 0;}
+ExtObject ParamInterface::getObjectById(const char*prop)
+{int i=findId(prop); if (i>=0) return getObject(i); else return ExtObject();}
+ExtValue ParamInterface::getExtValueById(const char*prop)
+{int i=findId(prop); if (i>=0) return getExtValue(i); else return ExtValue();}
+
+int ParamInterface::setIntById(const char* prop,long v)
+{int i=findId(prop); if (i>=0) return setInt(i,v); else return PSET_NOPROPERTY;}
+int ParamInterface::setDoubleById(const char* prop,double v)
+{int i=findId(prop); if (i>=0) return setDouble(i,v); else return PSET_NOPROPERTY;}
+int ParamInterface::setStringById(const char* prop,const SString &v)
+{int i=findId(prop); if (i>=0) return setString(i,v); else return PSET_NOPROPERTY;}
+int ParamInterface::setObjectById(const char* prop,const ExtObject &v)
+{int i=findId(prop); if (i>=0) return setObject(i,v); else return PSET_NOPROPERTY;}
+int ParamInterface::setExtValueById(const char* prop,const ExtValue &v)
+{int i=findId(prop); if (i>=0) return setExtValue(i,v); else return PSET_NOPROPERTY;}
+
+int ParamInterface::save(VirtFILE* f,const SString* altname,bool force)
+{
+const char *p;
+SString ws;
+int err=0,i;
+bool withname=false;
+if ((!altname)||(altname->len()))
+	{
+	err|=(fputs(altname?((const char*)(*altname)):getName(),f)==EOF);
+	err|=(fputs(":\n",f)==EOF);
+	withname=true;
+	}
+for (i=0;p=id(i);i++)
+	err|=saveprop(f,i,p,force);
+if (withname)
+	err|=(fputs("\n",f)==EOF);
+return err;
+}
+
+int ParamInterface::saveprop(VirtFILE* f,int i,const char* p,bool force)
+{
+if ((flags(i)&PARAM_DONTSAVE)&&(!force)) return 0;
+const char *typ=type(i);
+if ((*typ=='p')||(*typ=='o')) return 0;
+
+const char *t,*w;
+SString ws;
+int err=0,cr;
+
+err|=(fputs(p,f)==EOF); fputc(':',f);
+cr=0;
+ws=get(i);
+quoteTilde(ws);
+w=ws;
+if (ws.len()>50) cr=1;
+else for (t=w;*t;t++) if ((*t==10)||(*t==13)) {cr=1; break;}
+if (cr) fputs("~\n",f);
+err|=(fputs(w,f)==EOF);
+err|=(fputs(cr ? "~\n" : "\n",f)==EOF);
+return err;
+}
+
+
+int SimpleAbstractParam::isequal(int i,void* defdata)
+{ // defdata->member == object->member ?
+void *backup=object;
+switch(type(i)[0])
+	{
+	case 'd':
+		{
+		select(defdata);
+		long x=getInt(i);
+		select(backup);
+		return x==getInt(i);
+		}
+	case 'f':
+		{
+		select(defdata);
+		double x=getDouble(i);
+		select(backup);
+		return x==getDouble(i);
+		}
+	case 's':
+		{
+		select(defdata);
+		SString x=getString(i);
+		select(backup);
+		return x==getString(i);
+		}
+	}
+return 1;
+}
+
+void SimpleAbstractParam::save2(SString& f,void *defdata,int addcr)
+{ // defdata!=NULL -> nie zapisuje wartosci domyslnych
+const char *p;
+int i;
+int needlabel=0;
+int first=1;
+SString val;
+SString t;
+int fl;
+// t+=SString(getName()); t+=':';
+for (i=0;p=id(i);i++)
+	if (!((fl=flags(i))&PARAM_DONTSAVE))
+	{
+	if (defdata && isequal(i,defdata))
+		needlabel=1;
+	else
+		{
+		if (!first) t+=", ";
+#ifndef SAVE_ALL_NAMES
+#ifdef SAVE_SELECTED_NAMES
+		if (needlabel || !(fl & PARAM_CANOMITNAME))
+#else
+		if (needlabel)
+#endif
+#endif
+			{ t+=p; t+="="; needlabel=0; }
+		if (type(i)[0]=='s')
+			{ // string - special case
+			SString str=getString(i);
+			if (strContainsOneOf(str,", \\\n\r\t"))
+				{
+				t+="\"";
+				sstringQuote(str);
+				t+=str;
+				t+="\"";
+				}
+			else
+				t+=str;
+			}
+		else
+	   		t+=get(i);
+		first=0;
+		}
+	}
+if (addcr)
+	t+="\n";
+f+=t;
+}
+
+void ParamInterface::load(VirtFILE* f)
+{
+char t[100];
+int i;
+const char *p,*p0;
+int p_len;
+bool eol,loaded;
+int ret;
+while(fgets0(t,100,f,eol))
+	{
+	p0=t; while ((*p0==' ')||(*p0=='\t')) p0++;
+	if (!*p0) break;
+	p=strchr(p0,':'); if (!p) continue;
+	p_len=p-p0;
+	loaded=false;
+	if (p_len&&((i=findIdn(p0,p_len))>=0)&&(!(flags(i)&PARAM_DONTLOAD)))
+		{
+		if (p0[p_len+1]=='~')
+			{
+			SString s;
+			czytdotyldy(f,s);
+			int ch; while((ch=fgetc(f))!=EOF) if (ch=='\n') break;
+			unquoteTilde(s);
+			ret=set(i,(const char*)s);
+			}
+		else
+			{
+			if (eol)
+				ret=set(i,p0+p_len+1);
+			else
+				{
+				SString tmp=p0+p_len+1;
+				while(!eol)
+					{
+					if (!fgets0(t,100,f,eol)) break;
+					tmp+=t;
+					}
+				ret=set(i,(const char*)tmp);
+				}
+			}
+		if (ret & (PSET_HITMIN | PSET_HITMAX))
+			FMprintf("Param","load2",FMLV_WARN,"Adjusted '%s' in '%s' (was too %s)",
+				 id(i),getName(),(ret&PSET_HITMAX)?"big":"small");
+		loaded=true;
+		}
+	if ((!loaded) && (p0[p_len+1]=='~'))
+		{ // eat unrecognized multiline field
+		SString s;
+		czytdotyldy(f,s);
+		int ch; while((ch=fgetc(f))!=EOF) if (ch=='\n') break;
+		}
+	}
+}
+
+
+/*
+SString SimpleAbstractParam::getString(int i)
+{
+char *t;
+switch (*(t=type(i)))
+	{
+	case 'd':
+	{
+	for (i=atol(get(i));i>=0;i--) if (t) t=strchr(t+1,'~');
+	if (t)
+		{
+		t++;
+		char *t2=strchr(t,'~');
+		if (!t2) t2=t+strlen(t);
+		SString str;
+		strncpy(str.directWrite(t2-t),t,t2-t);
+		str.endWrite(t2-t);
+		return str;
+		}
+	}
+	}
+return get(i);
+}
+*/
+
+int ParamInterface::findId(const char* n)
+{
+int i; const char *p;
+	for (i=0;p=id(i);i++) if (!strcmp(n,p)) return i;
+return -1;
+}
+
+int ParamInterface::findIdn(const char* naz,int n)
+{
+int i; const char *p;
+	for (i=0;p=id(i);i++) if ((!strncmp(naz,p,n))&&(!p[n])) return i;
+return -1;
+}
+
+void ParamInterface::get(int i,ExtValue &ret)
+{
+switch(type(i)[0])
+	{
+	case 'd':	ret.setInt(getInt(i)); break;
+	case 'f':	ret.setDouble(getDouble(i)); break;
+	case 's':	ret.setString(getString(i)); break;
+	case 'o':	ret.setObject(getObject(i)); break;
+	case 'x':	ret=getExtValue(i); break;
+	default: FMprintf("ParamInterface","get",FMLV_ERROR,"'%s.%s' is not a field",getName(),id(i));
+	}
+}
+
+int ParamInterface::set(int i,const ExtValue &v)
+{
+switch(type(i)[0])
+	{
+	case 'd': return setInt(i,v.getInt());
+	case 'f': return setDouble(i,v.getDouble());
+	case 's': { SString t=v.getString(); return setString(i,t); }
+	case 'o': return setObject(i,v.getObject());
+	case 'x': return setExtValue(i,v);
+	default: FMprintf("ParamInterface","get",FMLV_ERROR,"'%s.%s' is not a field",getName(),id(i));
+	}
+return 0;
+}
+
+int ParamInterface::set(int i,const char *v)
+{
+switch(type(i)[0])
+	{
+	case 'd': return setInt(i,atol(v));
+	case 'f': return setDouble(i,atof(v));
+	case 's': { SString t(v); return setString(i,t); }
+	case 'x':
+	{
+	ExtValue e;
+	if (isdigit(*v)||((*v=='-')&&isdigit(v[1])))
+		{
+		if (strchr(v,'.')) e.setDouble(atof(v));
+		else e.setInt(atol(v));
+		}
+	else
+		{
+		e.setString(SString(v));
+		}
+	return setExtValue(i,e);
+	}
+	}
+return 0;
+}
+
+SString ParamInterface::getText(int i)
+{
+const char *t;
+if ((*(t=type(i)))=='d')
+	{
+	for (int j=getInt(i);j>=0;j--) if (t) t=strchr(t+1,'~');
+	if (t)
+		{
+		t++;
+		const char *t2=strchr(t,'~');
+		if (!t2) t2=t+strlen(t);
+		return SString(t,t2-t);
+		}
+	}
+return get(i);
+}
+
+SString ParamInterface::get(int i)
+{
+switch(type(i)[0])
+	{
+	case 'd':
+		{
+		SString tmp;
+		sprintf(tmp.directWrite(20),"%ld",getInt(i)); tmp.endWrite();
+		return tmp;
+		}
+	case 'f':
+		{
+		SString tmp;
+		sprintf(tmp.directWrite(20),"%lg",getDouble(i)); tmp.endWrite();
+		return tmp;
+		}
+	case 's':
+		return getString(i);
+	}
+ExtValue v;
+get(i,v);
+return v.getString();
+}
+
+
+//////////////////////////////// PARAM ////////////////////////////////////
+
+void *SimpleAbstractParam::getTarget(int i)
+{
+return (void*)(((char*)object)+entry(i)->offset);
+//return &(object->*(entry(i)->fldptr));
+}
+
+///////// get
+
+long SimpleAbstractParam::getInt(int i)
+{
+static ExtValue v;
+ParamEntry *pe=entry(i);
+if (pe->fun1)
+	{
+	(*(void(*)(void*,ExtValue*))pe->fun1)(object,&v);
+	return v.getInt();
+	}
+else
+	{
+	void *target=getTarget(i);
+	return *((long*)target);
+	}
+}
+
+double SimpleAbstractParam::getDouble(int i)
+{
+static ExtValue v;
+ParamEntry *pe=entry(i);
+if (pe->fun1)
+	{
+	(*(void(*)(void*,ExtValue*))pe->fun1)(object,&v);
+	return v.getDouble();
+	}
+else
+	{
+	void *target=getTarget(i);
+	return *((double*)target);
+	}
+}
+
+SString SimpleAbstractParam::getString(int i)
+{
+static ExtValue v;
+ParamEntry *pe=entry(i);
+if (pe->fun1)
+	{
+	(*(void(*)(void*,ExtValue*))pe->fun1)(object,&v);
+	return v.getString();
+	}
+else
+	{
+	void *target=getTarget(i);
+	return *((SString*)target);
+	}
+}
+
+ExtObject SimpleAbstractParam::getObject(int i)
+{
+static ExtValue v;
+ParamEntry *pe=entry(i);
+if (pe->fun1)
+	{
+	(*(void(*)(void*,ExtValue*))pe->fun1)(object,&v);
+	return v.getObject();
+	}
+else
+	{
+	void *target=getTarget(i);
+	return *((ExtObject*)target);
+	}
+}
+
+ExtValue SimpleAbstractParam::getExtValue(int i)
+{
+static ExtValue v;
+ParamEntry *pe=entry(i);
+if (pe->fun1)
+	{
+	(*(void(*)(void*,ExtValue*))pe->fun1)(object,&v);
+	return v;
+	}
+else
+	{
+	void *target=getTarget(i);
+	return *((ExtValue*)target);
+	}
+}
+
+
+//////// set
+
+int SimpleAbstractParam::setInt(int i,long x)
+{
+static ExtValue v;
+ParamEntry *pe=entry(i);
+if (pe->flags&PARAM_READONLY) return PSET_RONLY;
+long a=0,b=0,result=0;
+const char* t=pe->type+1;
+while(*t) if (*t==' ') break; else t++;
+if (sscanf(t,"%ld %ld",&a,&b)==2)
+	if (a<=b) // jezeli max<min to znaczy ze min/max nie obowiazuje
+		{
+		if (x<a) {x=a; result=PSET_HITMIN;}
+		else if (x>b) {x=b; result=PSET_HITMAX;}
+		}
+
+if (pe->fun2)
+	{
+	v.setInt(x);
+	return result | (*(int(*)(void*,const ExtValue*))pe->fun2)(object,&v);
+	}
+else
+	{
+	void *target=getTarget(i);
+	if (dontcheckchanges || (*((long*)target)!=x))
+			{
+			result |= PSET_CHANGED;
+			*((long*)target)=x;
+			}
+	return result;
+	}
+}
+
+int SimpleAbstractParam::setDouble(int i,double x)
+{
+static ExtValue v;
+ParamEntry *pe=entry(i);
+if (pe->flags&PARAM_READONLY) return PSET_RONLY;
+double a=0,b=0; int result=0;
+const char* t=pe->type+1;
+while(*t) if (*t==' ') break; else t++;
+if (sscanf(t,"%lg %lg",&a,&b)==2)
+	if (a<=b) // jezeli max<min to znaczy ze min/max nie obowiazuje
+		{
+		if (x<a) {x=a; result=PSET_HITMIN;}
+		else if (x>b) {x=b; result=PSET_HITMAX;}
+		}
+
+if (pe->fun2)
+	{
+	v.setDouble(x);
+	return result | (*(int(*)(void*,const ExtValue*))pe->fun2)(object,&v);
+	}
+else
+	{
+	void *target=getTarget(i);
+	if (dontcheckchanges || (*((double*)target)!=x))
+		{
+		result|=PSET_CHANGED;
+		*((double*)target)=x;
+		}
+	return result;
+	}
+}
+
+int SimpleAbstractParam::setString(int i,const SString& x)
+{
+static ExtValue v;
+static SString vs;
+const SString *xx=&x;
+ParamEntry *pe=entry(i);
+if (pe->flags&PARAM_READONLY) return PSET_RONLY;
+const char* t=pe->type+1;
+while(*t) if (*t==' ') break; else t++;
+long a=0,b=0,result=0;
+if (sscanf(t,"%ld %ld",&a,&b)==2)
+	{
+	if ((x.len()>b)&&(b>0))
+		{
+		vs=x.substr(0,b);
+		xx=&vs;
+		result|=PSET_HITMAX;
+		}
+	}
+
+if (pe->fun2)
+	{
+	v.setString(*xx);
+	return result | (*(int(*)(void*,const ExtValue*))pe->fun2)(object,&v);
+	}
+else
+	{
+	void *target=getTarget(i);
+	if (dontcheckchanges || (!(*((SString*)target) == *xx)))
+		{
+		result|=PSET_CHANGED;
+		*((SString*)target)=x;
+		}
+	return result;
+	}
+}
+
+int SimpleAbstractParam::setObject(int i,const ExtObject& x)
+{
+static ExtValue v;
+ParamEntry *pe=entry(i);
+if (pe->flags&PARAM_READONLY) return PSET_RONLY;
+if (pe->fun2)
+	{
+	v.setObject(x);
+	return (*(int(*)(void*,const ExtValue*))pe->fun2)(object,&v);
+	}
+else
+	{
+	void *target=getTarget(i);
+	*((ExtObject*)target)=x;
+	return PSET_CHANGED;
+	}
+}
+
+int SimpleAbstractParam::setExtValue(int i,const ExtValue& x)
+{
+ParamEntry *pe=entry(i);
+if (pe->flags&PARAM_READONLY) return PSET_RONLY;
+if (pe->fun2)
+	{
+	return (*(int(*)(void*,const ExtValue*))pe->fun2)(object,&x);
+	}
+else
+	{
+	void *target=getTarget(i);
+	*((ExtValue*)target)=x;
+	return PSET_CHANGED;
+	}
+}
+
+void SimpleAbstractParam::call(int i,ExtValue *args,ExtValue *ret)
+{
+ParamEntry *pe=entry(i);
+if (!pe) return;
+if (pe->fun1 && (pe->type[0]=='p'))
+	(*(void(*)(void*,ExtValue*,ExtValue*))pe->fun1)(object,args,ret);
+else
+	{
+	FMprintf("SimpleAbstractParam","call",FMLV_ERROR,
+		 (*pe->type!='p')?"'%s.%s' is not a function":"internal error - undefined function pointer for '%s.%s'",getName(),pe->id);
+	}
+}
+
+void SimpleAbstractParam::setDefault(bool numericonly)
+{
+bool save=dontcheckchanges;
+dontcheckchanges=1;
+ParamInterface::setDefault(numericonly);
+dontcheckchanges=save;
+}
+
+void SimpleAbstractParam::setDefault(int i,bool numericonly)
+{
+bool save=dontcheckchanges;
+dontcheckchanges=1;
+ParamInterface::setDefault(i,numericonly);
+dontcheckchanges=save;
+}
+
+// zwraca adres poczatku linii
+// len = dlugosc linii (bez \n)
+// 0 moze oznaczac linie dlugosci 0 lub koniec SStringa
+// poz jest przesuwane na poczatek nastepnej linii
+// typowa petla: for(poz=0;poz<s.d;) {line=getline(s,poz,len);...
+static const char *getline(const SString &s,int &poz,int &len)
+{
+const char *beg=(const char*)s+poz;
+if (poz>=s.len()) {poz=s.len(); len=0; return (const char*)s+s.len();}
+const char *lf=strchr(beg,'\n');
+if (!lf) { lf=(const char*)s+s.len()-1; poz=s.len(); }
+else {poz=(lf-(const char*)s)+1; if (poz>s.len()) poz=s.len();}
+while (lf>=beg) if ((*lf=='\n')||(*lf=='\r')) lf--; else break;
+len=lf-beg+1;
+return beg;
+}
+
+void ParamInterface::load2(const SString &s,int &poz)
+{
+int i; // numer akt. parametru
+int tmpi;
+int len;
+int ret;
+const char *t,*lin,*end;
+const char *rownasie,*przecinek;
+char remember;
+const char *quote,*quote2;
+const char *value,*valstop;
+SString tmpvalue;
+if (poz>=s.len()) return;
+t=(const char*)s+poz;
+
+// na razie wszystko musi byc w jednej linii...
+lin=getline(s,poz,len);
+if (!len) return; // pusta linia = koniec
+i=0;
+end=lin+len;
+while(t<end)
+{
+// przetwarzanie jednego par
+while (strchr(" \n\r\t",*t)) if (t<end) t++; else return;
+
+przecinek=strchrlimit(t,',',end); if (!przecinek) przecinek=end;
+quote=strchrlimit(t,'\"',przecinek);
+if (quote)
+	{
+	quote2=skipQuoteString(quote+1,end);
+	if (quote2>przecinek)
+		{
+		przecinek=strchrlimit(quote2+1,',',end);
+		if (!przecinek) przecinek=end;
+		}
+	rownasie=strchrlimit(t,'=',quote);
+	}
+else
+	{
+	rownasie=strchrlimit(t,'=',przecinek);
+	quote2=0;
+	}
+if (rownasie==t) { t++; rownasie=0; }
+if (przecinek==t)	// skip empty value
+	{
+	t++; i++;
+	continue;
+	}
+if (rownasie) // have parameter name
+	{
+	tmpi=findIdn(t,rownasie-t);
+	i=tmpi;
+	if (tmpi<0)
+		FMprintf("Param","load2",FMLV_WARN,"Unknown property name for '%s' (ignored)",getName());
+	t=rownasie+1; // t=value
+	}
+#ifdef WARN_MISSING_NAME
+else
+#ifdef SAVE_SELECTED_NAMES
+if (!(flags(i)&PARAM_CANOMITNAME))
+#endif
+	{
+	FMprintf("Param","load2",FMLV_WARN,"Missing property name in '%s' (assuming '%s')",
+		 getName(),id(i)?id(i):"unknown property?");
+	}
+#endif
+if ((i>=0)&&id(i))
+	{
+	value=t;
+	if (quote)
+		{
+		tmpvalue.copyFrom(quote+1,quote2-quote-1);
+		sstringUnquote(tmpvalue);
+		value=tmpvalue;
+		valstop=quote2;
+		}
+	else
+		if (przecinek<end) valstop=przecinek; else valstop=end;
+
+	remember=*valstop;
+	*(char*)valstop=0;
+	ret=set(i,value);
+	if (ret&(PSET_HITMAX|PSET_HITMIN))
+		FMprintf("Param","load2",FMLV_WARN,"Adjusted '%s' in '%s' (was too %s)",
+			id(i),getName(),(ret&PSET_HITMAX)?"big":"small");
+	*(char*)valstop=remember;
+	}
+
+if (i>=0) i++;
+#ifdef __CODEGUARD__ 
+if (przecinek<end-1) t=przecinek+1; else return;
+#else
+t=przecinek+1;
+#endif
+}
+return;
+}
+
+int Param::grmember(int g,int a)
+{
+if ((getGroupCount()<2)&&(!g))
+	return (a<getPropCount())?a:-9999;
+
+ParamEntry *e=entry(0);
+int x=0,i=0;
+for (;e->id;i++,e++)
+	{
+	if (e->group==g) 
+		if (a==x) return i; else x++;
+	}
+return -9999;
+}
Index: /cpp/gdk/param.h
===================================================================
--- /cpp/gdk/param.h	(revision 5)
+++ /cpp/gdk/param.h	(revision 5)
@@ -0,0 +1,279 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _PARAM_H_
+#define _PARAM_H_
+
+#include <stdio.h>
+#include "sstring.h"
+#include "list.h"
+#include "statrick.h"
+#include "virtfile.h"
+
+class ExtValue;
+class ExtObject;
+
+// ParamInterface flags:
+#define PARAM_READONLY	1
+#define PARAM_DONTSAVE	2
+#define PARAM_SETLEVEL(x) (((x)&3)<<2)
+#define PARAM_LEVEL(x) (((x)>>2)&3)
+#define PARAM_USERREADONLY 16
+#define PARAM_USERHIDDEN 32
+// for mutableparam (private!)
+#define MUTPARAM_ALLOCENTRY 64
+#define MUTPARAM_ALLOCDATA 128
+#define PARAM_NOSTATIC 256
+#define PARAM_CONST 512
+#define PARAM_CANOMITNAME 1024
+#define PARAM_DONTLOAD	2048
+
+// wynik z param::set() to kombinacja bitow:
+
+#define PSET_RONLY	1
+// oznacza,ze nie mozna zmienic
+
+#define PSET_CHANGED	2
+// zaawansowane: wartosc zostala zmieniona
+
+#define PSET_HITMIN	4
+#define PSET_HITMAX	8
+// wartosc zostala dopasowana do min lub max
+
+#define PSET_WARN (PSET_RONLY | PSET_HITMIN | PSET_HITMAX)
+// pozyteczna kombinacja - oznacza, ze nalezy pobrac i wyswietlic
+// wartosc, zeby uzytkownik wiedzial, ze jego propozycja jest odrzucona
+
+#define PSET_NOPROPERTY	16
+
+/** Property get/set interface - runtime access to named properties */
+class ParamInterface
+{
+public:
+virtual int getGroupCount()=0; ///< @return number of property groups
+virtual int getPropCount()=0; ///< @return number of properties
+
+virtual const char* getName()=0;
+virtual const char* getDescription() {return 0;}
+
+int findId(const char *n);	///< find id number for internal name
+int findIdn(const char *naz,int n);
+
+virtual const char *id(int i)=0;	///< get internal name
+virtual const char *name(int i)=0;	///< get human readable name
+
+/** get type description.
+    first character defines basic datatype:
+    - d = integer
+    - f = floating point
+    - s = string
+    - o = ExtObject
+    - x = ExtValue (universal datatype)
+ */
+virtual const char *type(int i)=0;	
+
+virtual const char *help(int i)=0;	///< get long description (tooltip)
+
+virtual int flags(int i)=0;		///< get flags
+
+virtual int group(int i)=0;		///< get group id for a property
+virtual const char *grname(int gi)=0;	///< get group name
+virtual int grmember(int gi,int n)=0;	///< get property id for n'th member of group "gi"
+
+virtual void call(int i,ExtValue* args,ExtValue *ret)=0;
+
+void get(int,ExtValue &retval);	///< most universal get, can be used for every datatype
+
+virtual SString getString(int)=0;	///< get string value, you can only use this for "s" type property
+virtual long getInt(int)=0;	///< get long value, you can only use this for "d" type property
+virtual double getDouble(int)=0;	///< get double value, you can only use this for "f" type property
+virtual ExtObject getObject(int)=0;	///< get object reference, you can only use this for "o" type property
+virtual ExtValue getExtValue(int)=0;	///< get extvalue object, you can only use this for "x" type property
+
+SString get(int);		///< old style get, can convert long or double to string
+SString getText(int);		///< like getString, returns enumeration label for subtype "d 0 n ~enum1~enum2...
+
+SString getStringById(const char*prop);  ///< get string value, you can only use this for "s" type property
+long getIntById(const char* prop);    ///< get long value, you can only use this for "d" type property
+double getDoubleById(const char* prop);///< get double value, you can only use this for "f" type property
+ExtObject getObjectById(const char* prop);///< get object reference, you can only use this for "o" type property
+ExtValue getExtValueById(const char* prop);///< get extvalue object, you can only use this for "x" type property
+ExtValue getById(const char* prop);
+
+virtual int setInt(int,long)=0;		///< set long value, you can only use this for "d" type prop
+virtual int setDouble(int,double)=0;	///< set double value, you can only use this for "f" type prop
+virtual int setString(int,const SString &)=0; 	///< set string value, you can only use this for "s" type prop
+virtual int setObject(int,const ExtObject &)=0; 	///< set object reference, you can only use this for "o" type prop
+virtual int setExtValue(int,const ExtValue &)=0;	///< 4 in 1
+
+int set(int,const ExtValue &);///< most universal set, can be used for every datatype
+
+int set(int,const char*);		///< oldstyle set, can convert string to long or double
+
+int setIntById(const char* prop,long);///< set long value, you can only use this for "d" type prop
+int setDoubleById(const char* prop,double);///< set double value, you can only use this for "f" type prop
+int setStringById(const char* prop,const SString &);///< set string value, you can only use this for "s" type prop
+int setObjectById(const char* prop,const ExtObject &);///< set object reference, you can only use this for "o" type prop
+
+int setExtValueById(const char* prop,const ExtValue &);	///< 4 in 1
+
+/** get valid minimum, maximum and default value for property 'prop'
+    @return 0 if min/max/def information is not available */
+int getMinMax(int prop,long& minumum,long& maximum,long& def);
+/** get valid minimum, maximum and default value for property 'prop'
+    @return 0 if min/max/def information is not available */
+int getMinMax(int prop,double& minumum,double& maximum,double& def);
+
+virtual void setDefault(bool numericonly=false);
+virtual void setDefault(int i,bool numericonly=false);
+void setMin();
+void setMax();
+void setMin(int i);
+void setMax(int i);
+
+/** copy all property values from other ParamInterface object */
+void copyFrom(ParamInterface *src);
+
+/** copy all property values from compatible ParamInterface object.
+    this method is more efficient than copyFrom,
+    but can be used only if the other object has the same properties sequence, eg:
+    - any two Param objects having common paramtab
+    - any ParamInterface object and the Param with paramtab constructed by ParamObject::makeParamTab
+ */
+void quickCopyFrom(ParamInterface *src);
+
+int save(VirtFILE*,const SString* altname=0,bool force=0);
+int saveprop(VirtFILE*,int i,const char* p,bool force=0);
+void load(VirtFILE*);
+void load2(const SString &,int &);
+};
+
+// implementations:
+
+extern char MakeCodeGuardHappy;
+
+#define PROCOFFSET(_proc_) ( (void (*)(void*,ExtValue*,ExtValue*)) &(FIELDSTRUCT :: _proc_ ## _statrick))
+#define STATICPROCOFFSET(_proc_) ( (void (*)(void*,ExtValue*,ExtValue*)) &(FIELDSTRUCT :: _proc_))
+#define GETOFFSET(_proc_) ( (void (*)(void*,ExtValue*)) &(FIELDSTRUCT :: _proc_ ## _statrick))
+#define SETOFFSET(_proc_) ( (int (*)(void*,const ExtValue*)) &(FIELDSTRUCT :: _proc_ ## _statrick))
+
+#define FIELDOFFSET(_fld_) ((long)((char*)(&((FIELDSTRUCT*)&MakeCodeGuardHappy)->_fld_)-((char*)((FIELDSTRUCT*)&MakeCodeGuardHappy))))
+
+#define FIELD(_fld_) FIELDOFFSET(_fld_),0,0
+#define LONGOFFSET(_o_) (_o_),0,0
+#define PROCEDURE(_proc_) 0,(void*)PROCOFFSET(_proc_),0
+#define STATICPROCEDURE(_proc_) 0,(void*)STATICPROCOFFSET(_proc_),0
+#define GETSET(_proc_) 0,(void*)GETOFFSET(get_ ## _proc_),(void*)SETOFFSET(set_ ## _proc_)
+#define GETFIELD(_proc_) FIELDOFFSET(_proc_),(void*)GETOFFSET(get_ ## _proc_),0
+#define SETFIELD(_proc_) FIELDOFFSET(_proc_),0,(void*)SETOFFSET(set_ ## _proc_)
+#define GETONLY(_proc_) 0,(void*)GETOFFSET(get_ ## _proc_),0
+#define SETONLY(_proc_) 0,0,(void*)SETOFFSET(set_ ## _proc_)
+
+#define PARAMPROCARGS ExtValue* args,ExtValue* ret
+#define PARAMSETARGS const ExtValue* arg
+#define PARAMGETARGS ExtValue* ret
+
+#define PARAMPROCDEF(name) STATRICKDEF2(name,ExtValue*,ExtValue*)
+#define PARAMGETDEF(name) STATRICKDEF1(get_ ## name,ExtValue*)
+#define PARAMSETDEF(name) STATRICKRDEF1(int,set_ ## name,const ExtValue*)
+
+///////////////////////////////
+
+struct ParamEntry
+{
+const char *id;
+short group,flags;
+const char *name,*type;
+long offset;
+void *fun1; ///< procedure or get
+void *fun2; ///< set
+const char *help;
+};
+
+struct ParamEntryConstructor: public ParamEntry
+{
+public:
+ParamEntryConstructor(const char *_id,short _group=0,short _flags=0,const char *_name=0,const char *_type=0,long _offset=0,void *_fun1=0, void *_fun2=0, const char *_help=0)
+{id=_id;group=_group;flags=_flags;name=_name;type=_type;offset=_offset;fun1=_fun1;fun2=_fun2;help=_help;}
+};
+
+class SimpleAbstractParam: public virtual ParamInterface
+{
+protected:
+virtual void *getTarget(int i);
+virtual ParamEntry *entry(int i)=0;
+const char* myname;
+bool dontcheckchanges;
+
+public:
+void *object;
+
+const char* getName() {return myname;}
+void setName(const char* n) {myname=n;}
+
+/**
+	@param t ParamEntry table
+	@param o controlled object
+	@param n Param's name
+*/
+SimpleAbstractParam(void* o=0,const char*n=0):object(o),myname(n),dontcheckchanges(0) {}
+
+void select(void *o) {object=o;}
+void* getSelected() {return object;}
+
+const char *id(int i) {return (i>=getPropCount())?0:entry(i)->id;}
+const char *name(int i) {return entry(i)->name;}
+const char *type(int i) {return entry(i)->type;}
+const char *help(int i) {return entry(i)->help;}
+int flags(int i) {return entry(i)->flags;}
+int group(int i) {return entry(i)->group;}
+void call(int i,ExtValue* args,ExtValue *ret);
+
+SString getString(int);
+long getInt(int);
+double getDouble(int);
+ExtObject getObject(int);
+ExtValue getExtValue(int);
+
+int setInt(int,long);
+int setDouble(int,double);
+int setString(int,const SString &);
+int setObject(int,const ExtObject &);
+int setExtValue(int,const ExtValue &);
+
+int isequal(int i,void* defdata);
+void save2(SString&,void *defdata,int addcr=1);
+
+virtual void setDefault(bool numericonly=false);
+virtual void setDefault(int i,bool numericonly=false);
+};
+
+class Param: public SimpleAbstractParam
+{
+protected:
+ParamEntry *entry(int i) {return tab+tab[0].group+i;}
+public:
+ParamEntry *tab;
+/**
+	@param t ParamEntry table
+	@param o controlled object
+	@param n Param's name
+*/
+
+Param(ParamEntry *t=0,void* o=0,const char*n=0):SimpleAbstractParam(o,n),tab(t)
+{if (!n&&tab) myname=tab[0].name;}
+
+const char* getDescription() {return tab[0].type;}
+
+int getGroupCount() {return tab[0].group;}
+int getPropCount() {return tab[0].flags;}
+const char *grname(int i) {return (i<getGroupCount())?tab[i].id:0;}
+int grmember(int,int);
+void setParamTab(ParamEntry *t,int dontupdatename=0) {tab=t; if ((!dontupdatename)&&tab) myname=tab[0].name; }
+ParamEntry *getParamTab() const {return tab;}
+};
+
+extern ParamEntry empty_paramtab[];
+
+#endif
Index: /cpp/gdk/paramobj.cpp
===================================================================
--- /cpp/gdk/paramobj.cpp	(revision 5)
+++ /cpp/gdk/paramobj.cpp	(revision 5)
@@ -0,0 +1,159 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "paramobj.h"
+#include "extvalue.h"
+
+static const char* maybedup(bool dup,const char* src)
+{ return dup ? (src?strdup(src):0) : src; }
+static void maybefree(void* mem)
+{ if (mem) free(mem); }
+
+ParamEntry* ParamObject::makeParamTab(ParamInterface *pi,bool stripgroups,bool stripproc,
+				      int firstprop, int maxprops, bool dupentries, int flagsexclude)
+{
+ParamEntry *tab,*t;
+int i,n,offs;
+static ExtValue ex;
+int count=0,gcount=1;
+if (!stripgroups) gcount=pi->getGroupCount();
+if (stripproc||flagsexclude)
+for (int i=firstprop;i < pi->getPropCount();i++)
+	{
+	const char*t=pi->type(i);
+	if ((!stripproc)||(strchr("dfsox",*t)))
+		if ((!flagsexclude)||(!(pi->flags(i)&flagsexclude)))
+			if (++count >= maxprops) break;
+	}
+else count=pi->getPropCount()-firstprop;
+t=tab=(ParamEntry*)malloc(sizeof(ParamEntry)*(count+gcount+1));
+t->group=gcount;
+t->flags=count;
+t->name=maybedup(dupentries,pi->getName());
+t->type=maybedup(dupentries,pi->getDescription());
+for(i=0;i<gcount;i++)
+	{
+	t->id=maybedup(dupentries,pi->grname(i));
+	t->offset=0;
+	t++;
+	}
+n=1; offs=1;
+for (i=firstprop;i < pi->getPropCount();i++)
+	{
+	if ((!stripproc)||(strchr("dfsox",*pi->type(i))))
+		{
+		if ((!flagsexclude)||(!(pi->flags(i)&flagsexclude)))
+			{
+			t->offset=offs*sizeof(ExtValue);
+			if (*pi->type(i)!='x') t->offset+=(((char*)&ex.data[0])-((char*)&ex));
+			t->group=stripgroups?0:pi->group(i);
+			t->flags=pi->flags(i);
+			t->fun1=0;
+			t->fun2=0;
+			t->id=maybedup(dupentries,pi->id(i));
+			t->name=maybedup(dupentries,pi->name(i));
+			t->type=maybedup(dupentries,pi->type(i));
+			t->help=maybedup(dupentries,pi->help(i));
+			t++;
+			n++;
+			if (n>count) break;
+			}
+		offs++;
+		}
+	}
+t->id=0; t->group=0; t->flags=dupentries?MUTPARAM_ALLOCENTRY:0;
+return tab;
+}
+
+void ParamObject::freeParamTab(ParamEntry *pe)
+{
+if (pe[pe->flags+pe->group].flags & MUTPARAM_ALLOCENTRY)
+	{
+	int i;
+	ParamEntry *e;
+	maybefree((void*)pe->name);
+	maybefree((void*)pe->type);
+	for (i=0,e=pe;i<pe->group;i++,e++) 
+		maybefree((void*)e->id);
+	for (i=pe->group,e=pe+i;i<pe->group+pe->flags;i++,e++) 
+		{
+		maybefree((void*)e->id);
+		maybefree((void*)e->name);
+		maybefree((void*)e->type);
+		maybefree((void*)e->help);
+		}
+	}
+free(pe);
+}
+
+void* ParamObject::makeObject(ParamEntry *tab)
+{
+if (!tab) return 0;
+int n=tab->flags;
+if (!n) return 0;
+ExtValue *ret,*v;
+ret=v=(ExtValue*)malloc( sizeof(ExtValue)*(n+1) );
+for (int i=0;i<=n;i++,v++)
+	new(v) ExtValue;
+ret->setInt(n);
+v=ret+1;
+tab+=tab->group;
+for (;n>0;n--,v++,tab++)
+	switch(*tab->type)
+	{
+	case 'd': v->setInt(0); break;
+	case 'f': v->setDouble(0); break;
+	case 's': v->setString(SString::empty); break;
+	case 'o': v->setObject(ExtObject()); break;
+	case 'x': break;
+	}
+return ret;
+}
+
+void ParamObject::copyObject(void* dst,void* src)
+{
+if ((!dst)||(!src)) return;
+ExtValue *s=(ExtValue *)src;
+ExtValue *d=(ExtValue *)dst;
+int n=min(s->getInt(),d->getInt());
+s++; d++;
+for (int i=0;i<n;i++,d++,s++)
+	*d=*s;
+}
+
+void* ParamObject::dupObject(void* src)
+{
+if (!src) return 0;
+ExtValue *s=(ExtValue *)src;
+int n=s->getInt();
+
+ExtValue *ret=new ExtValue[n+1];
+ExtValue *d=ret;
+d->setInt(n);
+d++; s++;
+
+for (int i=0;i<n;i++,d++,s++)
+	*d=*s;
+
+return ret;
+}
+
+void ParamObject::freeObject(void* obj)
+{
+if (!obj) return;
+ExtValue *o=(ExtValue *)obj,*t=o+1;
+int n=o->getInt();
+for (int i=0;i<n;i++,t++)
+	t -> ~ExtValue();
+free(obj);
+}
+
+
+
+
+
+
+
+
+
Index: /cpp/gdk/paramobj.h
===================================================================
--- /cpp/gdk/paramobj.h	(revision 5)
+++ /cpp/gdk/paramobj.h	(revision 5)
@@ -0,0 +1,48 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _PARAMOBJ_H_
+#define _PARAMOBJ_H_
+
+#include "param.h"
+
+class ParamObject
+{
+  public:
+/** make a ParamEntry* array for use with Param object.
+    offsets in the array are calculated for the ExtObject array as the target.
+    valid array can be created with makeObject().
+    sample code:
+    @code
+    ParamInterface *pi=...; // any param interface
+    ParamEntry *tab=ParamObject::makeParamTab(pi);
+    void* obj=ParamObject::makeObject(tab);
+    void* obj2=ParamObject::makeObject(tab);
+    Param par(tab,obj);
+    par.set(...), par.get(...), par.load(...), par.save(...);
+    par.select(obj);
+    par.select(obj2);
+    ParamObject::freeObject(obj);
+    ParamObject::freeObject(obj2);
+ */
+static ParamEntry* makeParamTab(ParamInterface *pi,bool stripgroups=0,bool stripproc=0,int firstprop=0,int maxprops=9999,bool dupentries=false, int flagsexclude=0);
+
+/** deallocate paramtab obtained from makeParamTab() */
+static void freeParamTab(ParamEntry *pe);
+
+/** @return the object, suitable for Param.select(...).
+    @return NULL if 'pi' has no usable properties */
+static void* makeObject(ParamEntry *tab);
+
+/** copy data from src to dst  */
+static void copyObject(void* dst,void* src);
+
+/** duplicate object */
+static void* dupObject(void* obj);
+
+/** delete all data in the array and deallocate it  */
+static void freeObject(void* obj);
+};
+
+#endif
Index: /cpp/gdk/paramtabobj.cpp
===================================================================
--- /cpp/gdk/paramtabobj.cpp	(revision 5)
+++ /cpp/gdk/paramtabobj.cpp	(revision 5)
@@ -0,0 +1,38 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "paramtabobj.h"
+
+int ParamTab::measureTab(const ParamEntry *pe)
+{
+int i=0;
+while(pe->id) {i++;pe++;}
+return i;
+}
+
+void ParamTab::resize(int s)
+{
+if (s==siz) return;
+tab=(ParamEntry*)realloc(tab,sizeof(ParamEntry)*(s+1));
+siz=s;
+}
+
+int ParamTab::add(const ParamEntry* p,int count)
+{
+if (count<0) count=measureTab(p);
+resize(siz+count);
+memmove(tab+siz-count,p,sizeof(ParamEntry)*count);
+memset(tab+siz,0,sizeof(ParamEntry));
+if (siz>0) tab[0].flags=siz-tab[0].group;
+return siz-1;
+}
+
+void ParamTab::remove(int i,int count)
+{
+memmove(tab+i,tab+i+count,sizeof(ParamEntry)*count);
+resize(siz-count);
+memset(tab+siz,0,sizeof(ParamEntry));
+if (siz>0) tab[0].flags=siz-tab[0].group;
+}
+
Index: /cpp/gdk/paramtabobj.h
===================================================================
--- /cpp/gdk/paramtabobj.h	(revision 5)
+++ /cpp/gdk/paramtabobj.h	(revision 5)
@@ -0,0 +1,34 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _PARAMTABOBJ_H_
+#define _PARAMTABOBJ_H_
+
+#include "param.h"
+
+class ParamTab
+{
+ParamEntry *tab;
+int siz;
+void init() {siz=0; tab=(ParamEntry*)calloc(sizeof(ParamEntry),1);}
+void resize(int s);
+int measureTab(const ParamEntry *pe);
+
+  public:
+ParamTab(const ParamEntry* pe=0,int maxcount=-1) {init(); if (pe) add(pe,maxcount);}
+ParamTab(const ParamTab& src) {init(); add(src);}
+~ParamTab() {clear();}
+
+int size() const {return siz;}
+ParamEntry* getParamTab() const {return tab;}
+ParamEntry* operator()() const {return tab;}
+
+/** @return position of the last added entry */
+int add(const ParamEntry*,int count=1);
+int add(const ParamTab& src) {return add(src.getParamTab(), src.size());}
+void remove(int i,int count=1);
+void clear() {resize(-1);}
+};
+
+#endif
Index: /cpp/gdk/printconvmap.cpp
===================================================================
--- /cpp/gdk/printconvmap.cpp	(revision 5)
+++ /cpp/gdk/printconvmap.cpp	(revision 5)
@@ -0,0 +1,96 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "printconvmap.h"
+#include <stdio.h>
+#include "multimap.h"
+
+#define GEN1MAX 15
+
+void printN(const char* t,int maxlen)
+{
+while(maxlen-- > 0)
+	if (*t) putchar(*(t++));
+	else putchar(' ');
+}
+
+void printN(char t,int maxlen)
+{
+while(maxlen-- > 0) putchar(t);
+}
+
+void printmapping(const char* gen1, int len1,const MultiRange &mr,const char* gen2,int len2)
+{
+printN(' ',GEN1MAX-len1);
+printN(gen1,len1);
+printf(" : ");
+int i;
+for(i=0;i<len2;i++)
+	if (mr.contains(i))
+		putchar(gen2[i]);
+	else
+		putchar('.');
+putchar('\n');
+}
+
+void stripstring(SString &str)
+{
+char *t=str.directWrite();
+for(;*t;t++)
+	if (strchr("\n\r\t",*t)) *t=' ';
+}
+
+void printConvMap(const SString& gen1,const SString& gen2,const MultiMap& map)
+{
+int y,y2,len1;
+int id=0;
+if (map.isEmpty())
+	{
+	printf("{ empty }\n");
+	return;
+	}
+len1=gen1.len();
+SString g1=gen1;
+stripstring(g1);
+SString g2=gen2;
+stripstring(g2);
+const char* g=g1;
+y=0;
+MultiRange *mr;
+MultiRange emptyrange;
+printN(' ',GEN1MAX);
+printf("   %s\n",(const char*)g2);
+int begin=map.getBegin();
+int end=map.getEnd();
+while(y<len1)
+	{
+	if (y<begin)
+		{
+		mr=&emptyrange;
+		y2=begin;
+		}
+	else if (y>end)
+		{
+		mr=&emptyrange;
+		y2=len1;
+		}
+	else	{
+		id=map.findMappingId(y);
+		mr=&map.getMapping(id)->to;
+		y2=map.getMapping(id+1)->begin;
+		}
+	if ((y2-y) > GEN1MAX) y2=y+GEN1MAX;
+	if (y2>(y+len1)) y2=y+len1;
+	printmapping(g+y,y2-y,*mr,g2,g2.len());
+	y=y2;
+	}
+}
+
+void printModelMap(const SString& gen1,const MultiMap& map)
+{
+SString g2("012345678901234567890123456789");
+printN(' ',GEN1MAX);
+printf("   Parts     Joints    Neurons\n");
+printConvMap(gen1,g2,map);
+}
Index: /cpp/gdk/printconvmap.h
===================================================================
--- /cpp/gdk/printconvmap.h	(revision 5)
+++ /cpp/gdk/printconvmap.h	(revision 5)
@@ -0,0 +1,15 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _PRINTCONVMAP_H_
+#define _PRINTCONVMAP_H_
+
+#include "sstring.h"
+
+class MultiMap;
+
+void printConvMap(const SString& gen1,const SString& gen2,const MultiMap& map);
+void printModelMap(const SString& gen1,const MultiMap& map);
+
+#endif
Index: /cpp/gdk/sstring.cpp
===================================================================
--- /cpp/gdk/sstring.cpp	(revision 5)
+++ /cpp/gdk/sstring.cpp	(revision 5)
@@ -0,0 +1,323 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+
+#include "sstring.h"
+#include "nonstd.h"
+
+
+static int guessMemSize(int request, int memhint)
+{
+if (memhint>=0)
+	return request+memhint;
+else
+	return request+min(request/2,10000)+8;
+}
+
+SBuf::SBuf()
+{
+txt="";
+size=used=0;
+refcount=1;
+}
+
+SBuf::SBuf(int initsize, int memhint)
+{
+size=guessMemSize(initsize,memhint);
+if (size>0)	{ txt=(char*)malloc(size+1); txt[0]=0; }
+	else	txt="";
+used=0;
+refcount=1;
+}
+
+SBuf::~SBuf()
+{
+freeBuf();
+}
+
+void SBuf::initEmpty()
+{
+txt="";
+used=size=0;
+refcount=1;
+}
+
+void SBuf::freeBuf()
+{
+if (!size) return;
+free(txt); used=0;
+}
+
+void SBuf::copyFrom(const char *ch,int chlen,int memhint)
+{
+if (chlen==-1) chlen=strlen(ch);
+if (chlen>0)
+{
+if (chlen<size)
+	{
+	memcpy(txt,ch,chlen);
+	}
+else
+	{
+	size=guessMemSize(chlen,memhint);
+	char *newtxt=(char*)malloc(size+1);
+	memcpy(newtxt,ch,chlen);
+	free(txt);
+	txt=newtxt;
+	}
+}
+txt[chlen]=0;
+used=chlen;
+}
+
+void SBuf::append(const char *ch,int chlen)
+{ // doesn't check anything!
+memcpy(txt+used,ch,chlen);
+used+=chlen;
+txt[used]=0;
+}
+
+void SBuf::ensureSize(int needed, int memhint)
+{
+if (size>=needed) return;
+needed=guessMemSize(needed,memhint);
+txt=(char*)realloc(txt,needed+1);
+size=needed;
+}
+
+/////////////////////////////////////////////
+
+SString::SString()
+{
+initEmpty();
+}
+
+SString::~SString()
+{
+detach();
+}
+
+SString::SString(int x)
+{
+buf=new SBuf(x);
+}
+
+SString::SString(const char *t,int t_len)
+{
+initEmpty();
+if (!t) return;
+copyFrom(t,t_len);
+}
+
+SString::SString(const SString &from)
+{
+buf=from.buf;
+if (buf->size) buf->refcount++;
+memhint=-1;
+}
+
+void SString::initEmpty()
+{
+buf=&SBuf::empty;
+memhint=-1;
+}
+
+void SString::memoryHint(int howbig)
+{
+memhint=howbig;
+}
+	
+void SString::detachEmpty(int ensuresize)
+{
+if (buf==&SBuf::empty) { buf=new SBuf(ensuresize,memhint); return; }
+if (buf->refcount<2) buf->ensureSize(ensuresize,memhint);
+else
+	{
+	buf->refcount--;
+	buf=new SBuf(ensuresize,memhint);
+	}
+}
+
+void SString::detach()
+{
+if (buf==&SBuf::empty) return;
+if (!--buf->refcount) delete buf;
+}
+
+void SString::detachCopy(int ensuresize)
+{
+if (buf==&SBuf::empty) { buf=new SBuf(ensuresize,memhint); return; }
+if (buf->refcount<2)
+	{
+	buf->ensureSize(ensuresize,memhint);
+	return;
+	}
+buf->refcount--;
+SBuf *newbuf=new SBuf(ensuresize,memhint);
+newbuf->copyFrom(buf->txt,min(ensuresize,buf->used),memhint);
+buf=newbuf;
+}
+
+char *SString::directWrite(int ensuresize)
+{
+if (ensuresize<0) ensuresize=len();
+detachCopy(ensuresize);
+appending=buf->used;
+return buf->txt;
+}
+
+/*
+char *SString::directWrite()
+{
+return directWrite(buf->used);
+}
+*/
+char *SString::directAppend(int maxappend)
+{
+detachCopy(buf->used+maxappend);
+appending=buf->used;
+return buf->txt+appending;
+}
+
+void SString::endWrite(int newlength)
+{
+if (newlength<0) newlength=strlen(buf->txt);
+else buf->txt[newlength]=0;
+buf->used=newlength;
+}
+
+void SString::endAppend(int newappend)
+{
+if (newappend<0) newappend=strlen(buf->txt+appending);
+else buf->txt[appending+newappend]=0;
+buf->used=appending+newappend;
+}
+
+////////////// append /////////////////
+
+void SString::operator+=(const char *s)
+{
+if (!s) return;
+int x=strlen(s);
+if (!x) return;
+append(s,x);
+}
+
+void SString::append(const char *txt,int count)
+{
+if (!count) return;
+detachCopy(buf->used+count);
+buf->append(txt,count);
+}
+
+void SString::operator+=(const SString&s)
+{
+append((const char*)s,s.len());
+}
+
+SString SString::operator+(const SString& s) const
+{
+SString ret(*this);
+ret+=s;
+return ret;
+}
+
+/////////////////////////////
+
+void SString::copyFrom(const char *ch,int chlen)
+{
+if (!ch) chlen=0;
+else if (chlen<0) chlen=strlen(ch);
+detachEmpty(chlen);
+memcpy(buf->txt,ch,chlen);
+buf->txt[chlen]=0; buf->used=chlen;
+}
+
+void SString::operator=(const char *ch)
+{
+copyFrom(ch);
+}
+
+void SString::operator=(const SString&s)
+{
+if (s.buf==buf) return;
+detach();
+buf=s.buf;
+if (buf->size) buf->refcount++;
+}
+///////////////////////////////////////
+
+SString SString::substr(int begin, int length) const
+{
+if (begin<0) { length+=begin; begin=0; }
+if (length>=(len()-begin)) length=len()-begin;
+if (length<=0) return SString();
+if (length==len()) return *this;
+return SString((*this)(begin),length);
+}
+
+///////////////////////////////////////
+
+int SString::equals(const SString& s) const
+{
+if (s.buf==buf) return 1;
+return !strcmp(buf->txt,s.buf->txt);
+}
+
+///////////////////////////////////////
+
+int SString::indexOf(int character,int start) const
+{
+const char *found=strchr(buf->txt+start,character);
+return found?found-buf->txt:-1;
+}
+
+int SString::indexOf(const char *substring,int start) const
+{
+char *found=strstr(buf->txt+start,substring);
+return found?found-buf->txt:-1;
+}
+
+int SString::indexOf(const SString & substring,int start) const
+{
+char *found=strstr(buf->txt+start,((const char*)substring));
+return found?found-buf->txt:-1;
+}
+
+int SString::getNextToken (int& pos,SString &token,char separator) const
+{
+if (pos>=len()) {token=0;return 0;}
+int p1=pos,p2;
+const char *t1=buf->txt+pos;
+const char *t2=strchr(t1,separator);
+if (t2) pos=(p2=(t2-buf->txt))+1; else p2=pos=len();
+strncpy(token.directWrite(p2-p1),t1,p2-p1);
+token.endWrite(p2-p1);
+return 1;
+}
+
+int SString::startsWith(const char *pattern) const
+{
+const char *t=(const char*)(*this);
+for (;*pattern;pattern++,t++)
+	if (*t != *pattern) return 0;
+return 1;
+}
+
+const SString& SString::valueOf(int i)
+{
+static SString t;
+sprintf(t.directWrite(20),"%d",i); t.endWrite();
+return t;
+}
+const SString& SString::valueOf(double d)
+{
+static SString t;
+sprintf(t.directWrite(20),"%g",d); t.endWrite();
+return t;
+}
+
+
+SString SString::empty;
+SBuf SBuf::empty;
Index: /cpp/gdk/sstring.h
===================================================================
--- /cpp/gdk/sstring.h	(revision 5)
+++ /cpp/gdk/sstring.h	(revision 5)
@@ -0,0 +1,162 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _SSTRING_H_
+#define _SSTRING_H_
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+class SBuf
+{
+char *txt;
+int used;	///< data size
+int size;	///< buffer size, not including \0, special case: 0==buffer not allocated
+int refcount;	///< buffer is used by 'refcount' objects.
+void initEmpty();
+void ensureSize(int wantsize, int memhint);
+void copyFrom(const char* ch, int chlen=-1, int memhint=-1);
+void freeBuf();
+void append(const char* ch, int chlen=-1);
+static SBuf empty;
+SBuf(int initsize, int memhint=-1);
+friend class SString;
+SBuf(const SBuf& b) {}
+public:
+SBuf();
+~SBuf();
+};
+
+/// (not so) simple text string class
+
+class SString
+{
+private:
+SBuf *buf;	///< buffer
+int appending;  ///< append mode, changes can occur after character # 'appending'
+int memhint;	///< sstring will allocate bigger chunks of memory
+
+void initEmpty();
+int guessMemSize(int request);
+void copyFrom(SString &from); ///< copy from SString, reference if possible
+void detach(); ///< detach from shared buffer, if any
+void detachEmpty(int ensuresize=0); ///< detach and make empty
+void detachCopy(int ensuresize=0); ///< detach and make private copy
+
+public:
+SString(); ///< make an empty string
+SString(const char*t,int t_len=-1); ///< make a string from char*
+SString(int x); ///< string with initial buffer size
+SString(const SString& from); ///< duplicate string
+~SString();
+
+void copyFrom(const char* ch, int chlen=-1); ///< copy string, length of -1 == unknown
+
+void* operator new(size_t s, void* mem) {return mem;}
+#ifdef _MSC_VER
+void operator delete(void* mem, void* t) {}
+#endif
+void* operator new(size_t s) {return malloc(sizeof(SString));}
+void operator delete(void* mem) {free(mem);}
+
+int len() const {return buf->used;} ///< get string length
+void shrink(); ///< free unnecessary buffer
+
+/// after this call, you can modify sstring directly.
+/// returned value is the pointer to the internal buffer.
+/// <B>ensuresize</B> is minimal value of bytes you need,
+/// the buffer will be resized as needed.
+/// all "direct" operations have to leave the buffer with trailing '\0'
+/// at the end. endWrite() will search for this value in order to determine
+/// new string length.
+/// <P>Sample:<CODE>
+/// SString t;
+/// sprintf(t.directWrite(50),"a=%d,b=%f",a,b);
+/// t.endWrite();</CODE>
+char *directWrite(int ensuresize=-1);
+//char *directWrite();
+/// like directWrite, but it returns the pointer to the first char after current string
+/// for easy appending. <B>maxappend</B> is minimum of character in buffer
+/// that can be appended after this call.
+/// <P>Sample:<CODE>
+/// SString t;
+/// sprintf(t.directAppend(10),"c=%d",c);
+/// t.endAppend();</CODE>
+char *directAppend(int maxappend=0);
+/// update string length, after directWrite.
+/// you don't have to to call endWrite after directWrite if the string's length doesn't change.
+/// optional <B>newlength</B> parameter gives a chance to further optimize
+/// this operation if you know exact length of resulting string.
+/// <P>Sample:<CODE>
+/// SString t("samplestring");
+/// strncpy(t.directWrite(50),src,bytecount);
+/// t.endWrite(bytecount);</CODE>
+void endWrite(int newlength=-1);
+/// update string length, after directAppend.
+/// you will usually need to call endAppend (or endWrite) after directAppend,
+/// because the purpose of directAppend is to change string's length.
+/// optional <B>appendlength</B> parameter gives a chance to further optimize
+/// this operation if you know exact length of the appended string.
+/// <P>Sample:<CODE>
+/// SString t("samplestring");
+/// strncpy(t.directAppend(50),src,bytecount);
+/// t.endAppend(bytecount);</CODE>
+void endAppend(int appendlength=-1);
+/// argument is the amount of memory, that will be probably used
+/// by this string instance. string can use this value
+/// to optimize memory allocation (bigger chunks will be allocated).
+void memoryHint(int howbig);
+
+/// find a character in SString.
+/// return index if the character was found or -1 otherwise.
+int indexOf(int character,int start=0) const;
+
+/// find a substring.
+/// return index if the substring was found or -1 otherwise.
+int indexOf(const char *substring,int start=0) const;
+
+/// find a substring.
+/// return index if the substring was found or -1 otherwise.
+int indexOf(const SString & substring,int start=0) const;
+
+operator const char*() const {return buf->txt;} ///< get SString's readonly buffer
+//operator char*() {detachCopy(len()); return buf->txt;} ///< get SString's writable buffer
+void operator=(const char*t); ///< assign from const char*
+//void operator=(int x) {free(txt);nowy(x);} ///< clear string and make new empty one
+void operator=(const SString &s);
+
+void append(const char *txt,int count);
+SString operator+(const SString &s) const;
+void operator+=(int x); ///< append x spaces after current string
+void operator+=(const char*); ///< append char* contents
+void operator+=(const SString&); ///< append other SString
+
+int equals(const SString &s) const; ///< TRUE if equal
+int operator==(const SString &s) const {return equals(s);} ///< TRUE if equal
+const char* operator()(int p) const {return buf->txt+p;} ///< pointer to p'th character in SString
+char operator[](int i) {return buf->txt[i];} ///< get char like in array
+
+/// return a substring of the current string
+SString substr(int begin, int length=1<<30) const;
+
+/// simple tokenization:
+/// starting at <B>pos</B>, get next substring delimited by <B>separator</B> character
+/// and put it in output parameter <B>token</B>.
+/// <B>pos</B> is moved accordingly.
+/// returns <B>false</B> if no more tokens are available or <B>true</B> otherwise.
+int getNextToken(int& pos,SString &token,char separator) const;
+
+void operator+=(char ch) {directAppend(1)[0]=ch;endAppend(1);} ///< append single character
+
+int startsWith(const char *pattern) const;
+char charAt(int pos) const {return buf->txt[pos];}
+
+static const SString& valueOf(int);
+static const SString& valueOf(double);
+
+static SString empty;
+};
+
+#endif
Index: /cpp/gdk/sstringutils.cpp
===================================================================
--- /cpp/gdk/sstringutils.cpp	(revision 5)
+++ /cpp/gdk/sstringutils.cpp	(revision 5)
@@ -0,0 +1,234 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "sstringutils.h"
+#include "virtfile.h"
+#include "framsg.h"
+
+int loadSString(const char* filename,SString& s,const char* framsgmodule,const char* error)
+{
+VirtFILE *f;
+int ret=0;
+if (f=Vfopen(filename,"rb"))
+	{
+	loadSString(f,s);
+	ret=1;
+	fclose(f);
+	}
+else if (framsgmodule)
+	FMprintf(framsgmodule,"loadSString",FMLV_WARN,error?error:"can't open file \"%s\"",filename);
+return ret;
+}
+
+void loadSString(VirtFILE *f,SString& s)
+{
+static char buf[4000];
+int len;
+while(!f->Veof())
+	{
+	len=fread(buf,1,4000,f);
+	s.append(buf,len);
+	}
+}
+
+//////////////////////////
+
+/** "x~xx~xxx" -> "x\~xx\~xxx"  */
+int quoteTilde(SString &target)
+{
+const char* x=target;
+SString tmp;
+char *f;
+while(1)
+	{
+	f=strchr((char*)x,'~');
+	if (f)
+		{
+		tmp.append(x,f-x);
+		tmp+="\\~";
+		x=f+1;
+		}
+	else
+		{
+		if (tmp.len()==0) return 0; // nothing was changed!
+		tmp+=x;
+		target=tmp;
+		return 1;
+		}
+	}
+}
+
+/** "x\~xx\~xxx" -> "x~xx~xxx"  */
+int unquoteTilde(SString &target)
+{
+const char* x=target;
+SString tmp;
+char *f;
+while(1)
+	{
+	f=strchr((char*)x,'\\');
+	if (f)
+		{
+		tmp.append(x,f-x);
+		if (f[1]=='~')
+			{
+			tmp+='~';
+			x=f+2;
+			}
+		else
+			{
+			tmp+="\\";
+			x=f+1;
+			}
+		}
+	else
+		{
+		if (tmp.len()==0) return 0; // nothing was changed!
+		tmp+=x;
+		target=tmp;
+		return 1;
+		}
+	}
+}
+
+/////////////////
+
+bool strContainsOneOf(const char* str,const char* chars)
+{
+while(*str)
+	{
+	if (strchr(chars,*str)) return 1;
+	str++;
+	}
+return 0;
+}
+
+//////////////
+
+bool sstringQuote(SString& target)
+{
+const char* x=target;
+bool changed=0;
+SString tmp;
+tmp.memoryHint(target.len());
+while(*x)
+	{
+	switch(*x)
+		{
+		case '\n': tmp+="\\n"; changed=1; break;
+		case '\r': tmp+="\\r"; changed=1; break;
+		case '\t': tmp+="\\t"; changed=1; break;
+		case '\"': tmp+="\\\""; changed=1; break;
+		default: tmp+=*x;
+		}
+	x++;
+	}
+if (changed) target=tmp;
+return changed;
+}
+
+const char* skipQuoteString(const char* txt, const char* limit)
+{
+while(*txt)
+	{
+	if (*txt=='\"') return txt;
+	if (*txt=='\\') txt++;
+	txt++;
+	if (txt==limit) break;
+	}
+return txt;
+}
+
+int sstringUnquote(SString &target)
+{
+const char* x=target;
+SString tmp;
+char *f;
+while(1)
+	{
+	f=strchr((char*)x,'\\');
+	if (f)
+		{
+		tmp.append(x,f-x);
+		switch(f[1])
+			{
+			case 'n': tmp+='\n'; break;
+			case 'r': tmp+='\r'; break;
+			case 't': tmp+='\t'; break;
+			case '\"': tmp+='\"'; break;
+			default: tmp+=f[1];
+			}
+		x=f+2;
+		}
+	else
+		{
+		if (tmp.len()==0) return 0; // nothing was changed!
+		tmp+=x;
+		target=tmp;
+		return 1;
+		}
+	}
+}
+
+int strFindField(const SString& txt,const SString& name,int &end)
+{
+const char* t=txt,*n;
+int pos=0;
+while(1)
+	{
+	n=strchr(t+pos,',');
+	if ((!strncmp(t+pos,name,name.len()))&&(t[pos+name.len()]=='='))
+		{
+		if (n) end=n-t; else end=txt.len();
+		return pos;
+		}
+	if (n) pos=n-t+1; else break;
+	}
+return -1;
+}
+
+SString strGetField(const SString& txt,const SString& name)
+{
+int p,e;
+p=strFindField(txt,name,e);
+if (p<0) return SString();
+p+=name.len()+1;
+return SString(txt.substr(p,e-p));
+}
+
+void strSetField(SString& txt,const SString& name,const SString& value)
+{
+int p,e;
+p=strFindField(txt,name,e);
+if (p<0)
+	{
+	if (!value.len()) return;
+	char *t=txt.directAppend(1+name.len()+value.len());
+	char *b=t;
+	if (txt.len()) *(t++)=',';
+	strcpy(t,name); t+=name.len();
+	*(t++)+='=';
+	strcpy(t,value); t+=value.len();
+	txt.endAppend(t-b);
+	}
+else
+	{
+	if (!value.len())
+		{
+		if (p>0) p--; else if (e<txt.len()) e++;
+		char *t=txt.directWrite(0);
+		memmove(t+p,t+e,txt.len()-e);
+		txt.endWrite(txt.len()+value.len()-(e-p));
+		}
+	else
+		{
+		p+=name.len()+1;
+		char *t=txt.directWrite(txt.len()+value.len()-(e-p));
+		memmove(t+p+value.len(),t+e,txt.len()-e);
+		memmove(t+p,value,value.len());
+		txt.endWrite(txt.len()+value.len()-(e-p));
+		}
+	}
+}
+
Index: /cpp/gdk/sstringutils.h
===================================================================
--- /cpp/gdk/sstringutils.h	(revision 5)
+++ /cpp/gdk/sstringutils.h	(revision 5)
@@ -0,0 +1,28 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _SSTRINGUTILS_H_
+#define _SSTRINGUTILS_H_
+
+#include "sstring.h"
+#include "virtfile.h"
+
+/// return: 1=ok 0=error
+int loadSString(const char* filename,SString& s,const char* framsgmodule=0,const char* error=0);
+void loadSString(VirtFILE *f,SString& s);
+
+int quoteTilde(SString &target);
+int unquoteTilde(SString &target);
+
+bool strContainsOneOf(const char* str,const char* chars);
+bool sstringQuote(SString& target);
+const char* skipQuoteString(const char* txt, const char* limit);
+int sstringUnquote(SString &target);
+
+int strFindField(const SString& txt,const SString& name,int &end);
+SString strGetField(const SString& txt,const SString& name);
+void strSetField(SString& txt,const SString& name,const SString& value);
+
+#endif
+
Index: /cpp/gdk/statrick.h
===================================================================
--- /cpp/gdk/statrick.h	(revision 5)
+++ /cpp/gdk/statrick.h	(revision 5)
@@ -0,0 +1,117 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _STATRICK_H_
+#define _STATRICK_H_
+
+/**
+ @file
+ CALLING METHODS WITH "STATIC TRICK" (="STATRICK")
+
+ each trick-callable method has the static counterpart defined by the STATRICKDEF macro
+
+\code
+ static void Class::method_statrick(Class* instance,otherparams)
+    { instance->method(otherparams); }
+
+------ class.h -----------
+ class Class
+ {
+ #define STATRICKCLASS Class
+ STATRICKDEF(method_x)
+ STATRICKDEF1(method_y,argtype1)
+ STATRICKDEF2(method_z,argtype1,argtype2)
+ STATRICKIMPL(method_a)
+   {
+   ...implementation...
+   }
+ STATRICKIMPL1(method_b,argtype1)
+   {
+   ...implementation...
+   }
+ STATRICKIMPL2(method_c,argtype1,argtype2)
+   {
+   ...implementation...
+   }
+ #undef STATRICKCLASS
+ }
+------ class.cpp ---------
+ Class::method_x()
+  {
+  ...implementation
+  }
+ Class::method_y(type1 arg1)
+  {
+  ...implementation
+  }
+ Class::method_z(type1 arg1,type2 arg2)
+  {
+  ...implementation
+  }
+--------------------------
+\endcode
+
+ usage:
+
+\code 
+ void* methodptr=STATRICKPTR(Class::method);
+ STATRICKCALL(method,anyobject);
+\endcode
+
+ */
+
+#define STATRICKNAME(name) (name ## _statrick)
+#define STATRICKCALL(method,anyobject) (*method(anyobject))
+#define STATRICKCALL1(method,anyobject,a) (*method(anyobject,a))
+#define STATRICKCALL2(method,anyobject,a,b) (*method(anyobject,a,b))
+
+#define STATRICKSTUB(cls,method)				\
+static void method ## _statrick (cls * instance)	\
+{ instance -> method (); }
+
+#define STATRICKSTUB1(cls,method,type1) \
+static void method ## _statrick (cls * instance, type1 arg1)	\
+{ instance -> method (arg1); }
+
+#define STATRICKSTUB2(cls,method,type1,type2)							\
+static void method ## _statrick (cls * instance, type1 arg1, type2 arg2) \
+{ instance -> method (arg1,arg2); }
+
+#define STATRICKRSTUB(cls,ret,method)				\
+static ret method ## _statrick (cls * instance)	\
+{ return instance -> method (); }
+
+#define STATRICKRSTUB1(cls,ret,method,type1) \
+static ret method ## _statrick (cls * instance, type1 arg1)	\
+{ return instance -> method (arg1); }
+
+#define STATRICKRSTUB2(cls,ret,method,type1,type2)							\
+static ret method ## _statrick (cls * instance, type1 arg1, type2 arg2) \
+{ return instance -> method (arg1,arg2); }
+
+#define STATRICKDEF(method)			\
+ STATRICKSTUB(STATRICKCLASS,method)		 \
+void method ()
+
+#define STATRICKRDEF(ret,method)	\
+ STATRICKRSTUB(STATRICKCLASS,ret,method)		 \
+ret method ()
+
+#define STATRICKDEF1(method,type1)	\
+ STATRICKSTUB1(STATRICKCLASS,method,type1)             \
+void method (type1 arg1)
+
+#define STATRICKRDEF1(ret,method,type1)	\
+ STATRICKRSTUB1(STATRICKCLASS,ret,method,type1)             \
+ret method (type1 arg1)
+
+#define STATRICKDEF2(method,type1,type2)	\
+STATRICKSTUB2(STATRICKCLASS,method,type1,type2)                \
+void method (type1 arg1,type2 arg2)
+
+#define STATRICKRDEF2(ret,method,type1,type2)	\
+STATRICKRSTUB2(STATRICKCLASS,ret,method,type1,type2)                \
+ret method (type1 arg1,type2 arg2)
+
+#endif
Index: /cpp/gdk/stdiofile-autoinit.cpp
===================================================================
--- /cpp/gdk/stdiofile-autoinit.cpp	(revision 5)
+++ /cpp/gdk/stdiofile-autoinit.cpp	(revision 5)
@@ -0,0 +1,20 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "stdiofile.h"
+
+static StdioFileSystem filesys;
+
+class StdioFile_autoinit
+{
+public:
+StdioFile_autoinit()
+	{
+   //StdioFILE::setStdio();
+	VirtFILE::selectFileSystem(&filesys);
+	}
+};
+
+
+static StdioFile_autoinit ai;
Index: /cpp/gdk/stdiofile.cpp
===================================================================
--- /cpp/gdk/stdiofile.cpp	(revision 5)
+++ /cpp/gdk/stdiofile.cpp	(revision 5)
@@ -0,0 +1,42 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "stdiofile.h"
+#include "nonstd.h"
+#include "nonstd_io.h"
+
+VirtFILE* StdioFileSystem::Vfopen(const char* path,const char*mode)
+{
+FILE *f=fopen(path,mode);
+if (f) return new StdioFILE(f,path); else return 0;
+}
+
+VirtDIR* StdioFileSystem::Vopendir(const char* path)
+{
+#ifndef _MSC_VER
+DIR *d=opendir(path);
+if (d) return new StdioDIR(d); else
+#endif
+return 0;
+}
+
+int StdioFileSystem::Vfexists(const char* path)
+{return fileExists(path);}
+
+void StdioFILE::setStdio()
+{
+static StdioFILEDontClose si(stdin);
+static StdioFILEDontClose so(stdout);
+static StdioFILEDontClose se(stderr);
+setVstdin(&si);
+setVstdout(&so);
+setVstderr(&se);
+}
+
+#ifndef _MSC_VER
+dirent* StdioDIR::Vreaddir()
+{
+return readdir(dir);
+}
+#endif
Index: /cpp/gdk/stdiofile.h
===================================================================
--- /cpp/gdk/stdiofile.h	(revision 5)
+++ /cpp/gdk/stdiofile.h	(revision 5)
@@ -0,0 +1,67 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _STDIOFILE_H_
+#define _STDIOFILE_H_
+
+#include "virtfile.h"
+#include "sstring.h"
+#include <stdio.h>
+#ifndef _MSC_VER
+#include <dirent.h>
+#endif
+
+class StdioFileSystem: public VirtFileSystem
+{
+public:
+VirtFILE *Vfopen(const char* path,const char*mode);
+int Vfexists(const char* path);
+VirtDIR *Vopendir(const char* path);
+};
+
+class StdioFILE: public VirtFILE
+{
+  protected:
+FILE *file;
+SString path;
+  public:
+StdioFILE(FILE *f) {file=f;}
+StdioFILE(FILE *f,const SString& p) {file=f;path=p;}
+static void setStdio();
+int Vread(void *ptr, size_t size, size_t nmemb) {return fread(ptr,size,nmemb,file);}
+int Vwrite(const void *ptr, size_t size, size_t nmemb) {return fwrite(ptr,size,nmemb,file);}
+int Veof() {return feof(file);}
+int Vputc(int c) {return fputc(c,file);}
+int Vputs(const char *s) {return fputs(s,file);}
+int Vgetc() {return fgetc(file);}
+char *Vgets(char *s, int size) {return fgets(s,size,file);}
+int Vprintf(const char *format, va_list args) { return vfprintf(file,format,args); }
+int Vseek(long offset, int whence) {return fseek(file,offset,whence);}
+int Vtell() {return ftell(file);}
+void Vrewind() {rewind(file);}
+int Vflush() {return fflush(file);}
+const char* VgetPath() {return path;}
+
+~StdioFILE() {if (file) fclose(file);}
+};
+
+class StdioDIR: public VirtDIR
+{
+#ifndef _MSC_VER
+DIR *dir;
+  public:
+StdioDIR(DIR* d):dir(d) {}
+~StdioDIR() {if (dir) closedir(dir);}
+dirent* Vreaddir();
+#endif
+};
+
+class StdioFILEDontClose: public StdioFILE
+{
+  public:
+StdioFILEDontClose(FILE *f):StdioFILE(f) {}
+~StdioFILEDontClose() {file=0;}
+};
+
+#endif
Index: /cpp/gdk/stdouterr.cpp
===================================================================
--- /cpp/gdk/stdouterr.cpp	(revision 5)
+++ /cpp/gdk/stdouterr.cpp	(revision 5)
@@ -0,0 +1,13 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "stdouterr.h"
+#include <stdio.h>
+
+void StdoutErrorHandler::handle(const char *o,const char *m,const char *bl,int w)
+{
+static char* level[]={"DEBUG","INFO","WARN","ERROR","CRITICAL"};
+if (w<-1) w=-1; else if (w>3) w=3;
+printf("[%s] %s::%s - %s\n",level[w+1],o,m,bl);
+}
Index: /cpp/gdk/stdouterr.h
===================================================================
--- /cpp/gdk/stdouterr.h	(revision 5)
+++ /cpp/gdk/stdouterr.h	(revision 5)
@@ -0,0 +1,17 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _STDOUTERRORHANDLER_H_
+#define _STDOUTERRORHANDLER_H_
+
+#include "errmanager.h"
+
+class StdoutErrorHandler: public ErrorHandlerBase
+{
+  public:
+StdoutErrorHandler(int opts=DontBlock):ErrorHandlerBase(opts) {}
+void handle(const char *o,const char *m,const char *bl,int w);
+};
+
+#endif
Index: /cpp/gdk/syntparam.cpp
===================================================================
--- /cpp/gdk/syntparam.cpp	(revision 5)
+++ /cpp/gdk/syntparam.cpp	(revision 5)
@@ -0,0 +1,57 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "nonstd.h"
+#include "syntparam.h"
+#include "paramobj.h"
+#include <math.h>
+
+SyntParam::SyntParam(ParamEntry *init_pe,SString* autostr)
+	:autostring(autostr)
+{
+Param::setParamTab(init_pe);
+pe=ParamObject::makeParamTab(this);
+Param::setParamTab(pe);
+obj=ParamObject::makeObject(pe);
+Param::select(obj);
+Param::setDefault();
+revert();
+}
+
+SyntParam::SyntParam(const SyntParam& src)
+	:autostring(src.autostring)
+{
+Param::setParamTab(src.pe);
+pe=ParamObject::makeParamTab(this);
+Param::setParamTab(pe);
+obj=ParamObject::dupObject(src.obj);
+Param::select(obj);
+}
+
+SyntParam::~SyntParam()
+{
+update();
+ParamObject::freeParamTab(pe);
+ParamObject::freeObject(obj);
+}
+
+void SyntParam::update(SString *s)
+{
+if (!s) s=autostring;
+if (s) {*s=""; Param::save2(*s,0,0);}
+}
+
+void SyntParam::revert(SString *s)
+{
+if (!s) s=autostring;
+if (s)	{
+	int p=0;
+	Param::load2(*s,p);
+	}
+}
+
+
+
+
+
Index: /cpp/gdk/syntparam.h
===================================================================
--- /cpp/gdk/syntparam.h	(revision 5)
+++ /cpp/gdk/syntparam.h	(revision 5)
@@ -0,0 +1,24 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _SYNTPATAM_H_
+#define _SYNTPATAM_H_
+
+#include "param.h"
+
+class SyntParam: public Param
+{
+void* obj;
+ParamEntry *pe;
+SString* autostring;
+  public:
+SyntParam(ParamEntry *pe,SString* autostring=0);
+SyntParam(const SyntParam& src);
+~SyntParam();
+void setAutoUpdate(SString* autostr) {autostring=autostr;}
+void update(SString *s=0);
+void revert(SString *s=0);
+};
+
+#endif
Index: /cpp/gdk/usertags.h
===================================================================
--- /cpp/gdk/usertags.h	(revision 5)
+++ /cpp/gdk/usertags.h	(revision 5)
@@ -0,0 +1,71 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _USERTAGS_H_
+#define _USERTAGS_H_
+
+/**
+  UserTags is the fast way to associate custom data with general purpose objects.
+  Objects don't have to know about their users and we can add more users later without recompilation.
+  For example: MechObject is general physical object in MechaStick engine.
+  In Framsticks simulator every MechObject is connected with Model object, MechParts and MechJoints are
+  connected with their counterparts in the Model as well, but the MechObject doesn't even know about it.
+  If the SSG visualisation is used, the same MechObject is also connected with SSGFramObject.
+  UserTags class is implemented as array, therefore the access is very fast but we have to define
+  maximum possible number of tags for every object:
+
+  UserTags<anyclass,datatype,maximumtags> object;
+  (all UserTags object for a given 'anyclass' will share registered id's)
+
+  usage:
+    1.allocate private id:
+       int id=object->userdata.newID();
+    'id' is shared across all objects of that class (in this example)
+    and therefore you need to allocate it only once.
+    0 is illegal here and means that we run out of id values.
+       
+    2.now you can use id to access your private data inside UserTags:
+       object->userdata[id]=...;
+       ...=object->userdata[id];
+       ...
+    3.you can also assign/access object->userdata (which is a shortcut for 
+    object->userdata[0]). no id here, so in that case it is your responsibility
+    to avoid conflicts.
+       object->userdata=...;
+       ...=object->userdata;
+       ...
+
+    4.free your id when finished:
+       object->userdata.freeID(id);
+ */
+
+template<class ID,class T,int N> class UserTags
+{
+static char reg[N];
+T data[N];
+  public:
+UserTags() {memset(data,0,sizeof(data));}
+
+/** allocate new id */
+static int newID() 
+	{ for(int i=1;i<N;i++) if (!reg[i]) {reg[i]=1; return i;}
+	DB(printf("Warning: UserTags run out of ids!\n"));
+	  return 0; }
+static void freeID(int id) 
+	{ reg[id]=0; }
+T& operator[](int id)
+	{
+	DB(if (!id) printf("Warning: UserTags @ %p is using id=0\n",this);)
+	return data[id]; 
+	}
+operator T() { return data[0]; }
+void operator=(T x) { data[0]=x; }
+};
+
+#endif
+
+
+
+
+
Index: /cpp/gdk/virtfile.cpp
===================================================================
--- /cpp/gdk/virtfile.cpp	(revision 5)
+++ /cpp/gdk/virtfile.cpp	(revision 5)
@@ -0,0 +1,93 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#include "virtfile.h"
+
+VirtFILE *VirtFILE::Vstdin=0;
+VirtFILE *VirtFILE::Vstdout=0;
+VirtFILE *VirtFILE::Vstderr=0;
+
+VirtFileSystem *VirtFILE::vfs=0;
+
+VirtFILE *Vfopen(const char* path,const char*mode)
+{
+return VirtFILE::vfs ? VirtFILE::vfs->Vfopen(path,mode) : 0;
+}
+
+VirtDIR *Vopendir(const char* path)
+{
+return VirtFILE::vfs ? VirtFILE::vfs->Vopendir(path) : 0;
+}
+
+int Vfexists(const char* path)
+{
+return VirtFILE::vfs ? VirtFILE::vfs->Vfexists(path) : 0;
+}
+
+VirtFILE::~VirtFILE()
+{}
+
+void VirtFILE::selectFileSystem(VirtFileSystem *s) {vfs=s;}
+
+int VirtFILE::printf(const char *format, ...)
+{
+int ret; va_list argptr;
+va_start(argptr,format);
+ret=Vprintf(format,argptr);
+va_end(argptr);
+return ret;
+}
+
+void VirtFILE::setVstdin(VirtFILE *f) {Vstdin=f;}
+void VirtFILE::setVstdout(VirtFILE *f) {Vstdout=f;}
+void VirtFILE::setVstderr(VirtFILE *f) {Vstderr=f;}
+VirtFILE* VirtFILE::getVstdin() {return Vstdin;}
+VirtFILE* VirtFILE::getVstdout() {return Vstdout;}
+VirtFILE* VirtFILE::getVstderr() {return Vstderr;}
+//////////////////////////////////////////////////////////////////////////
+
+VirtFILE* VirtFileSystem::Vfopen(const char* path,const char*mode) {return 0;}
+int VirtFileSystem::Vfexists(const char* path) {return 0;}
+VirtDIR* VirtFileSystem::Vopendir(const char* path) {return 0;}
+
+//////////////////////////////////////////////////////////////////////////
+
+
+
+int fread(void *ptr, size_t size, size_t nmemb, VirtFILE* f) {return f->Vread(ptr,size,nmemb);}
+int fwrite(const void *ptr, size_t size, size_t nmemb, VirtFILE* f) {return f->Vwrite(ptr,size,nmemb);}
+#ifdef __BORLANDC__
+#undef feof
+#endif
+#ifdef _MSC_VER
+#undef feof
+#endif
+int feof(VirtFILE* f) {return f->Veof();}
+#ifdef __BORLANDC__
+#define feof(__f)     ((__f)->flags & _F_EOF)
+#endif
+#ifdef _MSC_VER
+#define feof(_stream)     ((_stream)->_flag & _IOEOF)
+#endif
+
+int fputc(int c,VirtFILE* f) {return f->Vputc(c);}
+int fputs(const char *s,VirtFILE* f) {return f->Vputs(s);}
+int fgetc(VirtFILE* f) {return f->Vgetc();}
+int fseek(VirtFILE* f,long offset, int whence) {return f->Vseek(offset,whence);}
+int ftell(VirtFILE* f) {return f->Vtell();}
+void rewind(VirtFILE* f) {f->Vrewind();}
+int fflush(VirtFILE* f) {return f->Vflush();}
+char *fgets(char *s, int size, VirtFILE* f) {return f->Vgets(s,size);}
+int fprintf(VirtFILE* f,const char *format, ...)
+	{
+	int ret; va_list argptr;
+	va_start(argptr,format);
+	ret=f->Vprintf(format,argptr);
+	va_end(argptr);
+	return ret;
+	}
+int fclose(VirtFILE* f) {delete f; return 0;}
+
+int closedir(VirtDIR* d) {delete d; return 0;}
+dirent* readdir(VirtDIR* d) {return d->Vreaddir();}
Index: /cpp/gdk/virtfile.h
===================================================================
--- /cpp/gdk/virtfile.h	(revision 5)
+++ /cpp/gdk/virtfile.h	(revision 5)
@@ -0,0 +1,99 @@
+// This file is a part of Framsticks GDK library.
+// Copyright (C) 2002-2006  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.frams.alife.pl/ for further information.
+
+#ifndef _VIRTFILE_H_
+#define _VIRTFILE_H_
+
+#include <stdio.h>
+#include <stdarg.h>
+//#include <dirent.h>
+struct dirent;
+
+#ifdef DLLEXPORTACTIVE  //tylko w tym pliku uzyte
+#define DLLEXP __declspec(dllexport)
+#else
+#define DLLEXP
+#endif
+
+class DLLEXP VirtFileSystem;
+
+class DLLEXP VirtFILE
+{
+  public:
+virtual int Vread(void *ptr, size_t size, size_t nmemb)=0;
+virtual int Vwrite(const void *ptr, size_t size, size_t nmemb)=0;
+virtual int Veof()=0;
+virtual int Vputc(int c)=0;
+virtual int Vputs(const char *s)=0;
+virtual int Vgetc()=0;
+virtual int Vseek(long offset, int whence)=0;
+virtual int Vtell()=0;
+virtual void Vrewind()=0;
+virtual int Vflush()=0;
+virtual char *Vgets(char *s, int size)=0;
+virtual int Vprintf(const char *format, va_list args)=0;
+int printf(const char *format, ...);
+virtual const char *VgetPath() {return 0;} // 0=unspecified path
+virtual ~VirtFILE();
+static VirtFILE *Vstdin,*Vstdout,*Vstderr;
+static void setVstdin(VirtFILE *);
+static void setVstdout(VirtFILE *);
+static void setVstderr(VirtFILE *);
+static VirtFILE* getVstdin();
+static VirtFILE* getVstdout();
+static VirtFILE* getVstderr();
+static VirtFileSystem *vfs;
+static void selectFileSystem(VirtFileSystem *s);
+};
+
+class DLLEXP VirtDIR
+{
+  public:
+virtual ~VirtDIR() {}
+virtual dirent* Vreaddir() {return 0;}
+};
+
+class DLLEXP VirtFileSystem
+{
+public:
+virtual VirtFILE *Vfopen(const char* path,const char*mode);
+virtual int Vfexists(const char* path);
+virtual VirtDIR *Vopendir(const char* path);
+};
+
+DLLEXP VirtFILE *Vfopen(const char* path,const char*mode);
+DLLEXP VirtDIR *Vopendir(const char* path);
+DLLEXP int Vfexists(const char* path);
+
+DLLEXP int fread(void *ptr, size_t size, size_t nmemb, VirtFILE* f);
+DLLEXP int fwrite(const void *ptr, size_t size, size_t nmemb, VirtFILE* f);
+#ifdef __BORLANDC__
+#undef feof
+#endif
+#ifdef _MSC_VER
+#undef feof
+#endif
+DLLEXP int feof(VirtFILE* f);// {return f->Veof();}
+#ifdef __BORLANDC__
+#define feof(__f)     ((__f)->flags & _F_EOF)
+#endif
+#ifdef _MSC_VER
+#define feof(_stream)     ((_stream)->_flag & _IOEOF)
+#endif
+
+DLLEXP int fputc(int c,VirtFILE* f);
+DLLEXP int fputs(const char *s,VirtFILE* f);
+DLLEXP int fgetc(VirtFILE* f);
+DLLEXP int fseek(VirtFILE* f,long offset, int whence);
+DLLEXP int ftell(VirtFILE* f);
+DLLEXP void rewind(VirtFILE* f);
+DLLEXP int fflush(VirtFILE* f);
+DLLEXP char *fgets(char *s, int size, VirtFILE* f);
+DLLEXP int fprintf(VirtFILE* f,const char *format, ...);
+DLLEXP int fclose(VirtFILE* f);
+
+DLLEXP dirent* readdir(VirtDIR* d);
+DLLEXP int closedir(VirtDIR* d);
+
+#endif
