Index: cpp/common/nonstd.h
===================================================================
--- cpp/common/nonstd.h	(revision 131)
+++ cpp/common/nonstd.h	(revision 135)
@@ -55,16 +55,4 @@
   #define stricmp(a,b) strcasecmp(a,b)
  #endif
-#ifdef INITIAL_DIR_IS_HOME
- #include "cwd.h"
- #define GET_APP_HOME getAppHome()
-#else
- #define GET_APP_HOME "./"
-#endif
-#ifdef INITIAL_DIR_IS_RES
- #include "cwd.h"
- #define GET_APP_RESOURCES getAppResources()
-#else
- #define GET_APP_RESOURCES "./"
-#endif
 #endif
 
@@ -96,4 +84,9 @@
 #endif
 
+#ifdef LINUX
+ #define GET_APP_HOME "./"
+ #define GET_APP_RESOURCES "./"
+#endif
+
 #if defined(_WIN32) && !defined(SHP)
     #define GET_APP_HOME ".\\"
@@ -101,6 +94,19 @@
 #endif
 
+#ifdef INITIAL_DIR_IS_HOME
+ #include "cwd.h"
+ #ifdef GET_APP_HOME
+  #undef GET_APP_HOME
+ #endif
+ #define GET_APP_HOME getAppHome()
+#endif
 
-
+#ifdef INITIAL_DIR_IS_RES
+ #include "cwd.h"
+ #ifdef GET_APP_RESOURCES
+  #undef GET_APP_RESOURCES
+ #endif
+ #define GET_APP_RESOURCES getAppResources()
+#endif
 
 //typedef unsigned char boolean; //niestety nie mozna uzyc 'bool' bo VC w rpcndr.h wlasnie tak definiuje booleana, jako unsigned char
Index: cpp/common/nonstd_math.cpp
===================================================================
--- cpp/common/nonstd_math.cpp	(revision 131)
+++ cpp/common/nonstd_math.cpp	(revision 135)
@@ -14,6 +14,6 @@
 
 
-#ifdef _WIN32 //http://stackoverflow.com/questions/2170385/c-math-functions
-double round(double val)
+#if defined __BORLANDC__ || (_MSC_VER <= 1700)
+double round(double val) //http://stackoverflow.com/questions/2170385/c-math-functions
 {    
     return floor(val + 0.5);
Index: cpp/common/nonstd_math.h
===================================================================
--- cpp/common/nonstd_math.h	(revision 131)
+++ cpp/common/nonstd_math.h	(revision 135)
@@ -17,6 +17,6 @@
 #endif
 
-#ifdef _WIN32 //http://stackoverflow.com/questions/2170385/c-math-functions
-double round(double val);
+#if defined __BORLANDC__ || (_MSC_VER <= 1700)
+double round(double val);  //http://stackoverflow.com/questions/2170385/c-math-functions
 #endif
 
Index: cpp/frams/Makefile-GDK
===================================================================
--- cpp/frams/Makefile-GDK	(revision 131)
+++ cpp/frams/Makefile-GDK	(revision 135)
@@ -5,5 +5,5 @@
 include frams/Makefile-GDK-files
 
-GDK_TESTS=conv_test gdk_test geno_test neuro_test loader_test serial_test multiline_f0_test f0_variants_test full_props part_shapes
+GDK_TESTS=conv_test gdk_test geno_test neuro_test loader_test serial_test multiline_f0_test f0_variants_test full_props part_shapes neuro_layout_test
 
 gdk_tests: $(GDK_TESTS)
@@ -44,7 +44,10 @@
 	$(CXX) $(PART_SHAPES_OBJS) -o $@
 
+neuro_layout_test: $(NEURO_LAYOUT_TEST_OBJS)
+	$(CXX) $(NEURO_LAYOUT_TEST_OBJS) -o $@
+
 #############################################
 
-ALL_OBJS=$(GDK_TEST_OBJS) $(CONV_TEST_OBJS) $(GENO_TEST_OBJS) $(NEURO_TEST_OBJS) $(LOADER_TEST_OBJS) $(SERIAL_TEST_OBJS) $(MULTILINE_F0_OBJS) $(F0_VARIANTS_OBJS) $(FULL_PROPS_OBJS) $(PART_SHAPES_OBJS)
+ALL_OBJS=$(GDK_TEST_OBJS) $(CONV_TEST_OBJS) $(GENO_TEST_OBJS) $(NEURO_TEST_OBJS) $(LOADER_TEST_OBJS) $(SERIAL_TEST_OBJS) $(MULTILINE_F0_OBJS) $(F0_VARIANTS_OBJS) $(FULL_PROPS_OBJS) $(PART_SHAPES_OBJS) $(NEURO_LAYOUT_TEST_OBJS)
 
 include frams/Makefile-maintain
Index: cpp/frams/Makefile-GDK-files
===================================================================
--- cpp/frams/Makefile-GDK-files	(revision 131)
+++ cpp/frams/Makefile-GDK-files	(revision 135)
@@ -2,5 +2,5 @@
 
 # ALL_DIRS is later expanded by the shell, no spaces/newlines allowed, or it breaks
-ALL_DIRS={common,frams,frams/config,frams/errmgr,frams/genetics,frams/genetics/f0,frams/genetics/f1,frams/genetics/f2,frams/genetics/f3,frams/genetics/f4,frams/genetics/f5,frams/genetics/f6,frams/genetics/f7,frams/genetics/f8,frams/genetics/f9,frams/model,frams/neuro,frams/neuro/impl,frams/param,frams/test,frams/util,frams/vm/classes,frams/virtfile,frams/_demos}
+ALL_DIRS={common,frams,frams/canvas,frams/config,frams/errmgr,frams/genetics,frams/genetics/f0,frams/genetics/f1,frams/genetics/f2,frams/genetics/f3,frams/genetics/f4,frams/genetics/f5,frams/genetics/f6,frams/genetics/f7,frams/genetics/f8,frams/genetics/f9,frams/model,frams/neuro,frams/neuro/impl,frams/param,frams/test,frams/util,frams/vm/classes,frams/virtfile,frams/_demos}
 
 GENOCONV_GDK_OBJS=frams/genetics/f1/conv_f1.o frams/genetics/f9/conv_f9.o
@@ -33,2 +33,3 @@
 PART_SHAPES_OBJS= frams/_demos/part_shapes.o frams/virtfile/virtfile.o  $(GDK_OBJS) $(GENOCONV_GDK_OBJS)
 
+NEURO_LAYOUT_TEST_OBJS= frams/_demos/neuro_layout_test.o frams/virtfile/virtfile.o frams/errmgr/stdouterr.o $(GDK_OBJS) $(GENOCONV_GDK_OBJS) frams/canvas/nn_layout_model.o frams/canvas/nn_simple_layout.o frams/canvas/nn_smart_layout.o
Index: cpp/frams/_demos/neuro_layout_test.cpp
===================================================================
--- cpp/frams/_demos/neuro_layout_test.cpp	(revision 135)
+++ cpp/frams/_demos/neuro_layout_test.cpp	(revision 135)
@@ -0,0 +1,139 @@
+// This file is a part of the Framsticks GDK.
+// Copyright (C) 2002-2014  Maciej Komosinski and Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.framsticks.com/ for further information.
+
+#include <frams/genetics/geno.h>
+#include <frams/virtfile/stdiofile.h>
+#include <frams/util/sstringutils.h>
+#include <frams/genetics/defgenoconv.h>
+#include <frams/model/model.h>
+#include <frams/errmgr/stdouterr.h>
+#include <frams/canvas/nn_layout_model.h>
+
+#include <algorithm>
+
+/**
+ @file
+ Sample code: Neuron layout tester
+
+ Hint: Use loader_test to extract genotypes from framsticks *.gen files:
+ loader_test "data/walking.gen" "Walking Lizard" | neuro_layout_test -
+*/
+
+StdoutErrorHandler err; //redirect model-related errors to stdout
+DefaultGenoConvManager gcm; //without this object the application would only handle "format 0" genotypes
+
+// stl is fun? ;-) ForwardIterator implementation for element coordinates (required by min_element/max_element)
+template <int MEMBER> struct NNIter //MEMBER: 0..3=x/y/w/h
+{
+NNLayoutState *nn; int index;
+NNIter() {}
+NNIter(NNLayoutState *_nn, int _index):nn(_nn),index(_index) {}
+int operator*() {return nn->GetXYWH(index)[MEMBER];}
+NNIter& operator++() {index++; return *this;}
+bool operator!=(const NNIter& it) {return index!=it.index;}
+bool operator==(const NNIter& it) {return index==it.index;}
+
+static NNIter begin(NNLayoutState *_nn) {return NNIter(_nn,0);}
+static NNIter end(NNLayoutState *_nn) {return NNIter(_nn,_nn->GetElements());}
+};
+
+class Screen
+{
+int min_x,max_x,min_y,max_y,scale_x,scale_y;
+int rows,columns;
+char* screen;
+
+public:
+
+Screen(int _min_x,int _max_x,int _min_y,int _max_y,int _scale_x,int _scale_y)
+	:min_x(_min_x),max_x(_max_x),min_y(_min_y),max_y(_max_y),scale_x(_scale_x),scale_y(_scale_y)
+		{
+		columns=(max_x-min_x+scale_x-1)/scale_x;
+		rows=(max_y-min_y+scale_y-1)/scale_y;
+		screen=new char[rows*columns];
+		memset(screen,' ',rows*columns);
+		}
+
+~Screen()
+		{
+		delete[] screen;
+		}
+
+void put(int x,int y,const char *str)
+	{
+	x=(x-min_x)/scale_x;
+	y=(y-min_y)/scale_y;
+	if (x<0) return;
+	if (y<0) return;
+	if (y>=rows) return;
+	for(;*str;str++,x++)
+		{
+		if (x>=columns) return;
+		screen[columns*y+x]=*str;
+		}
+	}
+
+void print()
+	{
+	for(int y=0;y<rows;y++)
+		{
+		fwrite(&screen[columns*y],1,columns,stdout);
+		printf("\n");
+		}
+	}
+};
+
+int main(int argc,char*argv[])
+{
+if (argc<=1)
+	{
+		puts("Parameters:\n"
+		     " 1. Genotype (or - character indicating the genotype will be read from stdin)\n"
+		     " 2. (Optional) layout type (the only useful layout is 2, which is the default, see nn_simple_layout.cpp");
+	  return 10;
+	}
+SString gen(argv[1]);
+if (!strcmp(gen,"-"))
+	{
+	gen=0;
+	StdioFILEDontClose in(stdin);
+	loadSString(&in,gen);
+	}
+int layout_type=2;
+if (argc>2) layout_type=atol(argv[2]);
+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());
+
+NNLayoutState_Model nn_layout(&m);
+struct NNLayoutFunction &nnfun=nn_layout_functions[layout_type];
+printf(" using layout type=%d (%s)\n",layout_type,nnfun.name);
+nnfun.doLayout(&nn_layout);
+
+for(int i=0;i<nn_layout.GetElements();i++)
+	{
+	int *xywh=nn_layout.GetXYWH(i);
+	printf("#%-3d %s\t%d,%d\t%dx%d\n",i,(const char*)m.getNeuro(i)->getClassName(),
+	       xywh[0],xywh[1],xywh[2],xywh[3]);
+	}
+
+Screen screen(*std::min_element(NNIter<0>::begin(&nn_layout),NNIter<0>::end(&nn_layout))-30,
+	      *std::max_element(NNIter<0>::begin(&nn_layout),NNIter<0>::end(&nn_layout))+70,
+	      *std::min_element(NNIter<1>::begin(&nn_layout),NNIter<1>::end(&nn_layout)),
+	      *std::max_element(NNIter<1>::begin(&nn_layout),NNIter<1>::end(&nn_layout))+30,
+	      10,35);
+
+printf("===========================================\n");
+for(int i=0;i<nn_layout.GetElements();i++)
+	{
+	int *xywh=nn_layout.GetXYWH(i);
+	SString label=SString::sprintf("%d:%s",i,(const char*)m.getNeuro(i)->getClassName());
+	screen.put(xywh[0],xywh[1],(const char*)label);
+	}
+screen.print();
+printf("===========================================\n");
+
+}
Index: cpp/frams/canvas/nn_layout.h
===================================================================
--- cpp/frams/canvas/nn_layout.h	(revision 135)
+++ cpp/frams/canvas/nn_layout.h	(revision 135)
@@ -0,0 +1,32 @@
+#ifndef _NN_LAYOUT_H_
+#define _NN_LAYOUT_H_
+
+/// abstract neural network layout state
+class NNLayoutState
+{
+public:
+
+	// layout function calls these to inquire about neuron connections:
+	virtual int GetElements() = 0;		///< @return number of elements (neurons)
+	virtual int GetInputs(int el) = 0;	///< @return number of inputs in element 'el' (referred to as 'N' in subsequent descriptions)
+	virtual int GetLink(int el, int i) = 0;	///< @return index of element connected with i-th input of el-th element, or -1 if there is no connection
+
+	// could be useful to refine element placement, but not really used by any layout function:
+	virtual int *GetLinkXY(int el, int i) = 0;	///< @return relative coordinates of i-th input (or output when i==number of inputs) in el-th element (ret[0],[1]=x,y). unlike other methods, this information depends on the specific neuron drawing code, that's why NNLayoutState is abstract and can be implemented in context of a network drawing component.
+
+	// layout function calls this to place neurons:
+	virtual void SetXYWH(int el, int x, int y, int w, int h) = 0;	// set element position and size
+
+	// layout function user can use this to retrieve the resulting element layout:
+	virtual int *GetXYWH(int el) = 0;		///< @return current element (el=0..N-1) position and size ret[0],[1],[2],[3]=x,y,w,h
+};
+
+struct NNLayoutFunction
+{
+	const char *name;
+	void(*doLayout)(NNLayoutState*);
+};
+
+extern struct NNLayoutFunction nn_layout_functions[];
+
+#endif
Index: cpp/frams/canvas/nn_layout_model.cpp
===================================================================
--- cpp/frams/canvas/nn_layout_model.cpp	(revision 135)
+++ cpp/frams/canvas/nn_layout_model.cpp	(revision 135)
@@ -0,0 +1,47 @@
+#include "nn_layout_model.h"
+
+NNLayoutState_Model::NNLayoutState_Model(Model* m)
+{
+	model = m;
+	neuron_pos = (m->getNeuroCount() > 0) ? new NeuronPos[m->getNeuroCount()] : NULL;
+}
+
+NNLayoutState_Model::~NNLayoutState_Model()
+{
+	if (neuron_pos) delete[] neuron_pos;
+}
+
+int NNLayoutState_Model::GetElements()
+{
+	return model->getNeuroCount();
+}
+
+int *NNLayoutState_Model::GetXYWH(int el)
+{
+	return &neuron_pos[el].x;
+}
+
+void NNLayoutState_Model::SetXYWH(int el, int x, int y, int w, int h)
+{
+	NeuronPos &np = neuron_pos[el];
+	np.x = x; np.y = y; np.w = w; np.h = h;
+}
+
+int NNLayoutState_Model::GetInputs(int el)
+{
+	return model->getNeuro(el)->getInputCount();
+}
+
+int NNLayoutState_Model::GetLink(int el, int i)
+{
+	return model->getNeuro(el)->getInput(i)->refno;
+}
+
+int *NNLayoutState_Model::GetLinkXY(int el, int i)
+{
+	static int XY[2];
+	int *xywh = GetXYWH(el);
+	XY[0] = 0;
+	XY[1] = ((1 + i)*xywh[3]) / (GetInputs(el) + 1);
+	return XY;
+}
Index: cpp/frams/canvas/nn_layout_model.h
===================================================================
--- cpp/frams/canvas/nn_layout_model.h	(revision 135)
+++ cpp/frams/canvas/nn_layout_model.h	(revision 135)
@@ -0,0 +1,27 @@
+#ifndef _NN_LAYOUT_MODEL_H_
+#define _NN_LAYOUT_MODEL_H_
+
+#include "nn_layout.h"
+#include <frams/model/model.h>
+
+class NNLayoutState_Model : public NNLayoutState
+{
+public:
+
+	struct NeuronPos { int x, y, w, h; };
+
+	Model *model;
+	NeuronPos *neuron_pos;
+
+	NNLayoutState_Model(Model *m);
+	~NNLayoutState_Model();
+
+	int GetElements();
+	int *GetXYWH(int el);
+	void SetXYWH(int el, int x, int y, int w, int h);
+	int GetInputs(int el);
+	int GetLink(int el, int i);
+	int *GetLinkXY(int el, int i);
+};
+
+#endif
Index: cpp/frams/canvas/nn_simple_layout.cpp
===================================================================
--- cpp/frams/canvas/nn_simple_layout.cpp	(revision 135)
+++ cpp/frams/canvas/nn_simple_layout.cpp	(revision 135)
@@ -0,0 +1,40 @@
+#include "nn_layout.h"
+#include "common/nonstd_math.h"
+#include <stdlib.h>
+
+static void randomlayout(NNLayoutState*);
+static void arraylayout(NNLayoutState*);
+
+extern void smartlayout(NNLayoutState*);
+
+struct NNLayoutFunction nn_layout_functions[] =
+{
+	{ "Random", randomlayout, },
+	{ "Dumb array", arraylayout, },
+	{ "Smart", smartlayout, },
+	{ 0, }
+};
+
+static void randomlayout(NNLayoutState*nn)
+{
+	int i;
+	int N = nn->GetElements();
+	for (i = 0; i < N; i++)
+	{
+		nn->SetXYWH(i, (int)rnd0N(300), (int)rnd0N(300), 50, 50);
+	}
+}
+
+static void arraylayout(NNLayoutState*nn)
+{
+	int e = 0, i, j;
+	int N = nn->GetElements();
+	int a = ((int)(sqrt(double(N)) - 0.0001)) + 1;
+	for (j = 0; j < a; j++)
+		for (i = 0; i < a; i++)
+		{
+			if (e >= N) return;
+			nn->SetXYWH(e, 70 * i + ((i + j) & 3) * 4, 70 * j + ((2 + i + j) & 3) * 4, 50, 50);
+			e++;
+		}
+}
Index: cpp/frams/canvas/nn_smart_layout.cpp
===================================================================
--- cpp/frams/canvas/nn_smart_layout.cpp	(revision 135)
+++ cpp/frams/canvas/nn_smart_layout.cpp	(revision 135)
@@ -0,0 +1,317 @@
+#include "nn_layout.h"
+#include <vector>
+#include "common/nonstd_stl.h"
+
+#define DB(x) 
+
+#if DB(1)+0
+#include <assert.h>
+#endif
+
+class block;
+
+/** Information about a single element (neuron). There are N einfo objects in an array called "einfo" */
+struct einfo
+{
+	/** Element's owner */
+	class block *block;
+
+	/** Integer coordinates (neurons are simply placed in a grid, (x,y) is a grid cell) */
+	int x, y;
+};
+
+/** Array[0..N-1] - one einfo for each neuron */
+static struct einfo* einfo;
+
+/** Array[0..N-1] - initially each neuron resides in its own block. The algorithm merges blocks until one single block is created */
+static block **blocks;
+
+/** N = number of neurons */
+static int N;
+
+/** Provides neuron connections information and receives the layout result */
+static NNLayoutState *nn;
+
+static char *JEDEN = (char*)"1";
+
+/** Block is a group of neurons.
+	After "blocking" some neurons, their relative location will not change. */
+class block
+{
+public:
+
+	/** Block's id is its index in the "blocks" array */
+	int id;
+
+	/** Block members (neurons), or actually neuron indexes (0..N-1 ints)  */
+	std::vector<int> elementy;
+
+	/** Block's bounding box (a rectangle containing all elemens)
+		w=maxx-minx+1; h=maxy-miny+1;
+		*/
+	int w, h;
+	int minx, miny, maxx, maxy;
+
+	/** 2d array, w*h cells, indicating if a given (x,y) location is taken.
+		This speeds up checking if neurons from two blocks overlap.
+		*/
+	char *map;
+
+	/** Creating an initial block consisting of a single neuron */
+	block(int nr) : id(nr), w(1), h(1), minx(0), miny(0), maxx(0), maxy(0)
+	{
+		DB(printf("new block(%d)\n", nr));
+		dodajelement(nr, 0, 0);
+		blocks[id] = this;
+		map = JEDEN;
+	}
+
+	~block()
+	{
+		DB(printf("~ block(%d)\n", id));
+		blocks[id] = 0;
+		zwolnijmape();
+	}
+
+	void zwolnijmape(void)
+	{
+		if (map)
+		{
+			if (map != JEDEN) free(map);
+			map = 0;
+		}
+	}
+
+	void potrzebnamapa(void)
+	{
+		if (map) return;
+		odtworzmape();
+	}
+
+	void odtworzmape(void)
+	{
+		zwolnijmape();
+		w = maxx - minx + 1;
+		h = maxy - miny + 1;
+		map = (char*)calloc(1, w*h);
+		int i, e;
+		DB(printf("mapa bloku #%ld\n", id));
+		for (i = 0; i < elementy.size(); i++)
+		{
+			e = elementy[i];
+			map[w*(einfo[e].y - miny) + (einfo[e].x - minx)] = 1;
+		}
+		DB(for (i = 0; i < h; i++){ for (e = 0; e < w; e++)printf("%c", map[w*i + e] ? '*' : '.'); printf("\n"); })
+	}
+
+	/** Add a neuron to a block at location(x,y) */
+	void dodajelement(int nr, int x, int y)
+	{
+		elementy.push_back(nr);
+		einfo[nr].x = x;
+		einfo[nr].y = y;
+		einfo[nr].block = this;
+	}
+};
+
+static int moznadolaczyc(block *b, block *b2, int dx, int dy)
+{
+	/* Check if block b2 can be merged with b with b2 shifted by (dx,dy) so no overlap occurs.
+	   All coordinates are relative to b->minx/miny
+	   */
+	int x1, y1, x2, y2; // union rectangle
+	x1 = max(0, b2->minx - b->minx + dx);
+	x2 = min(b->maxx - b->minx, -b->minx + dx + b2->maxx);
+	if (x1 > x2) return 1;
+	y1 = max(0, b2->miny - b->miny + dy);
+	y2 = min(b->maxy - b->miny, -b->miny + dy + b2->maxy);
+	if (y1 > y2) return 1;
+	int x, y;
+	dx += b2->minx - b->minx; //dx,dy relative to minx,miny
+	dy += b2->miny - b->miny;
+	b->potrzebnamapa();
+	b2->potrzebnamapa();
+	for (y = y1; y <= y2; y++)
+	{
+		for (x = x1; x <= x2; x++)
+			if (b->map[b->w*y + x] && b2->map[b2->w*(y - dy) + (x - dx)]) return 0;
+	}
+	return 1;
+}
+
+/** Merge b2 with b shifting b2 by (dx,dy) - adds all b2's neurons to b and deletes b2 */
+static int dolaczblock(block *b, block *b2, int dx, int dy)
+{ // return 1 if successful
+	if (!moznadolaczyc(b, b2, dx, dy)) return 0; // merging causes no collision
+	DB(printf("#%ld(%ld,%ld,%ld,%ld) + #%ld(%ld,%ld,%ld,%ld)<%ld,%ld>", b->id, b->minx, b->miny, b->maxx, b->maxy, b2->id, b2->minx, b2->miny, b2->maxx, b2->maxy, dx, dy));
+
+	b->zwolnijmape();
+	int i, e;
+	for (i = 0; i < b2->elementy.size(); i++)
+	{
+		e = b2->elementy[i];
+		b->dodajelement(e, einfo[e].x + dx, einfo[e].y + dy);
+	}
+	b->minx = min(b->minx, dx + b2->minx);
+	b->miny = min(b->miny, dy + b2->miny);
+	b->maxx = max(b->maxx, dx + b2->maxx);
+	b->maxy = max(b->maxy, dy + b2->maxy);
+
+	DB(printf(" -> (%ld,%ld,%ld,%ld)\n", b->minx, b->miny, b->maxx, b->maxy));
+
+	DB(printf(" ...#%ld...(%ld)...", b->id, b->elementy.size()));
+	for (i = 0; i < b->elementy.size(); i++)
+	{
+		e = b->elementy[i];
+		DB(assert(einfo[e].x >= b->minx);)
+			DB(assert(einfo[e].x <= b->maxx);)
+			DB(assert(einfo[e].y >= b->miny);)
+			DB(assert(einfo[e].y <= b->maxy);)
+			DB(printf("(%ld)%ld,%ld ", e, einfo[e].x, einfo[e].y));
+	}
+
+	DB(printf("\n"));
+
+	delete b2;
+	return 1;
+}
+
+/** e2 neuron will be connected to e neuron's input:
+	- e and e2 belong to different blocks: shift/merge the blocks so e2 is to the left of e
+	- same block: nothing can be done
+	*/
+static void polaczjakowejscie(int e, int e2)
+{
+	block *b, *b2;
+	b = einfo[e].block;
+	if (!einfo[e2].block) new block(e2);
+	b2 = einfo[e2].block;
+	if (b == b2)
+	{
+		DB(printf("--- b==b2 -> cancel\n"));
+		return;
+	}
+	int dx, dy;
+	dx = einfo[e].x - einfo[e2].x;
+	dy = einfo[e].y - einfo[e2].y;
+	DB(printf("  elem.%ld (%ld,%ld@%ld) + elem.%ld (%ld,%ld@%ld)...\n", e, einfo[e].x, einfo[e].y, b->id, e2, einfo[e2].x, einfo[e2].y, b2->id));
+	if (dolaczblock(b, b2, dx - 1, dy)) return;
+	int proba; // retry - increasing the y offset (keeps x offset at -1)
+	for (proba = 1;; proba++)
+	{
+		if (dolaczblock(b, b2, dx - 1, dy - proba)) return;
+		if (dolaczblock(b, b2, dx - 1, dy + proba)) return;
+	}
+}
+
+/** Retrieve the information about neuron e inputs and place the input neurons accordingly
+	unless they are already processed
+	*/
+static void ustawelement(int e)
+{
+	if (einfo[e].block)
+	{
+		DB(printf("block#%ld exists\n", e));
+		return;
+	}
+	new block(e);
+	int we;
+	int n = nn->GetInputs(e);
+	for (we = 0; we < n; we++)
+	{
+		int e2 = nn->GetLink(e, we);
+		if (e2 < 0) continue;
+		if (e == e2) continue;
+		ustawelement(e2);
+		polaczjakowejscie(e, e2);
+	}
+}
+
+/**
+   The algorithm:
+   1. Phase one
+    - for each neuron, place its input neurons to the left
+      (at relative location (-1,dy), where dy is any number, ideally 0)
+    - the neuron's location in a block is never changed after the initial assignment
+    - which means that any further connections within a given block are ignored (neurons are already fixed in place)
+    - foreign block connections cause block merges, shifting the blocks so the (-1,dy) condition is met
+      (which also affects all neurons in the other block, since their relative positions are fixed)
+    - the final result is a set of blocks corresponding to the "islands" in the neural network
+   2. Phase two
+    - "islands" are merged into one final block. Any relative offsets can be used, as their neurons
+      are not connected anyway. Here a simple method is used: placing the islands in a vertical stack.
+ */
+void smartlayout(NNLayoutState *nnlayout)
+{
+	DB(printf("\n >>>>>>>>> smartlayout <<<<<<<<<<<\n"));
+	nn = nnlayout;
+	N = nn->GetElements();
+	einfo = (struct einfo*)calloc(N, sizeof(struct einfo));
+	blocks = (class block**)calloc(N, sizeof(class block*));
+
+	int el;
+	for (el = 0; el < N; el++) ustawelement(el);
+
+	DB(printf(" - - merging blocks - -\n"));
+
+	block *first;
+	for (el = 0; el < N; el++) if (blocks[el]) { first = blocks[el]; el++; break; }
+	while (el<N)
+	{
+		if ((first->maxx - first->minx)>(first->maxy - first->miny))
+		{
+			int y = first->maxy + 2;
+			int x = first->minx;
+			int ex = first->maxx;
+			while (el<N)
+			{
+				if (blocks[el])
+				{
+					int dx = blocks[el]->maxx - blocks[el]->minx + 2;
+					dolaczblock(first, blocks[el], x - blocks[el]->minx, y - blocks[el]->miny);
+					x += dx;
+					if (x>ex) break;
+				}
+				el++;
+			}
+		}
+		else
+		{
+			int x = first->maxx + 2;
+			int y = first->miny;
+			int ey = first->maxy;
+			while (el<N)
+			{
+				if (blocks[el])
+				{
+					int dy = blocks[el]->maxy - blocks[el]->miny + 2;
+					dolaczblock(first, blocks[el], x - blocks[el]->minx, y - blocks[el]->miny);
+					y += dy;
+					if (y>ey) break;
+				}
+				el++;
+			}
+		}
+	}
+	/*
+	for (;el<N;el++)
+	if (blocks[el])
+	dolaczblock(first,blocks[el],first->minx-blocks[el]->minx,first->maxy-blocks[el]->miny+1);
+	*/
+	if (first) // at this stage we have a single block containing all neurons
+	{
+		DB(printf(" - - setting coordinates - -\n"));
+		int i;
+		DB(first->odtworzmape());
+		for (i = 0; i < first->elementy.size(); i++)
+		{
+			el = first->elementy[i];
+			nn->SetXYWH(el, einfo[el].x * 70, -einfo[el].y * 70, 50, 50);
+		}
+		delete first;
+	}
+
+	free(blocks);
+	free(einfo);
+	DB(printf("--------------------------------\n\n"));
+}
