/*
* $Id: VRUTSerialization.h 2838 2013-08-27 20:02:07Z antonin.misek-skoda-auto.cz $
*
* Description  : One line description of file.
* Author       : Antonin Misek <antonin.misek@skoda-auto.cz>
*
* Purpose      :
*     Long description of what the file is for.
*/
#ifndef VRUTSERIALIZATION_H
#define VRUTSERIALIZATION_H


#if LUKAS_RUZICKA_DEBUG
#define LUKAS_RUZICKA_DEBUG2 0
#define LUKAS_RUZICKA_DEBUG3 0
#endif

//#include <wx/sstream.h>
//#include <string.h>
//#include "common.h"
//#include <limits>
//#include "flexilog.h"
#include "kernel.h"
#include "events.h"
#include <wx/mstream.h>
#include <wx/zstream.h>
#include "scenemanager.h"
#include "imagecommon.h"
#include "imagedds.h"
#include "imageHDR.h"
#include "geometrytext.h"
#include "RenderTileData.h"
#include "VRUTCompression.h"
#include "eventhandler.h"
#include "VehicleSimulationData.h"
#include "TrafficInfoData.h"
#include "module.h"

#define USE_HALF_PRECISION 1
#define USE_EXTRA_LOGGING 0


namespace VRUT {

#if USE_HALF_PRECISION
	typedef union {
		struct {
			unsigned short m : 10;
			unsigned short e : 5;
			unsigned short s : 1;
		} bits;
	} float16_s;

	typedef union {
		float v;
		struct {
			unsigned long m : 23;
			unsigned long e : 8;
			unsigned long s : 1;
		} bits;
	} float32_s;

	inline void float32to16(float x, float16_s * f16) {
		float32_s f32 = {x};
		// sign bit
		f16->bits.s = f32.bits.s;
		// exponent
		f16->bits.e = std::max(-15, std::min(16, (int)(f32.bits.e - 127))) + 15;
		// mantisa
		f16->bits.m = f32.bits.m >> 13;
	}

	inline float float16to32(float16_s f16) {
		float32_s f32;
		// sign bit
		f32.bits.s = f16.bits.s;
		// exponent
		f32.bits.e = (f16.bits.e - 15) + 127;
		// mantisa
		f32.bits.m = ((uint32_t)f16.bits.m) << 13;

		return f32.v;
	}

	struct Vector4Float16 {
		union {
			struct {
				float16_s x, y, z, w;
			};
			float16_s _v[4];
		};

		//Vector4Float16() : Vector4Float16(0.0f, 0.0f, 0.0f, 0.0f) {}
		Vector4Float16() {
			float32to16(0.0f, &x);
			float32to16(0.0f, &y);
			float32to16(0.0f, &z);
			float32to16(0.0f, &w);
		}
		Vector4Float16(float16_s _x, float16_s _y, float16_s _z, float16_s _w) : x(_x), y(_y), z(_z), w(_w) {
		}
		Vector4Float16(float _x, float _y, float _z, float _w) {
			float16_s nx, ny, nz, nw;
			float32to16(_x, &nx);
			float32to16(_y, &ny);
			float32to16(_z, &nz);
			float32to16(_w, &nw);
			x = nx;
			y = ny;
			z = nz;
			w = nw;
		}
	};


#endif


	//Some messages have assigned direct number, it is because of backward compatibility of IOVrut module and TCP/IP server.
	//Please don't change these messages without preservation of backward compatibility (for example increasing IOVrut version number and adding special code for "old" files).
	enum SerializerDataType {
		SDT_SCENE_NODE_INSERT = 0,				//1B - sceneID; 1B - node type; 4B - node ID; 4B - node parent; 1B - is active; string - nodeName
		SDT_SCENE_NODE_TRANSFORM_SET = 1,		//1B - sceneID; 4B - node ID; 4*16 float array - matrix
		SDT_SCENE_GEOMETRY_TRIANGLES_ADD = 2,	//1B - sceneID; 4B - geometry ID; 4B - vertices.size; 4*3*v.size float array; 4B - normals.size;
												//4*3*n.size float array; 4B - texCoords.size; 4*2*v.size float array; 4B - indices.size;
												//4*v.size ulong array; 4B - triDesc.size; (4+1)*v.size ulong+ulong array
												//when experimental compression is enabled, then all arrays are in zlib block at the end (4B - length; zlib data)
		SDT_SCENE_NODE_GEOMETRY_SET = 3,		//1B - sceneID; 4B - node ID; 4B - geometryID
		SDT_SCENE_MATERIAL_ADD = 4,				//1B - sceneID; material name; 4*float - ambient, diffuse, specular, emmision; float shininess; float reflection;
												//4B - depthFunc; float - textureMix; 4B - flags; 4B - texFlags; string - imageName; 4B - blendSrc, 4B - blendDst
												//1B - shader type;
												//LANG_NONE: has not shader
												//LANG_GLSL: string - fsSource, fsFileName, vsSource, vsFileName
												//LANG_CGFX: string - vsSource, vsFileName
												//1B - parameters count; string - parameter name; 1B - parameter type;
												//BOOL: 1B; FLOAT1: float; FLOAT2: 2xfloat; FLOAT3: 3xfloat; FLOAT4: 4xfloat; SAMPLER and SAMPLERCUBE string
		SDT_SCENE_NODE_MATERIAL_SET = 5,		//1B - sceneID; 4B - node ID; string - materialName
		SDT_SCENE_NODE_SWITCH_ACTIVECHILD_SET = 6,//1B - sceneID; 4B - node ID; 4B - activeChild
		SDT_SCENE_NODE_LIGHT_SET = 7,			//1B - sceneID; 4B - node ID; 1B - type; float - angle; float - exponent; 4*float diffuse; 3*float attenuation; float intensity; string IES
		SDT_SCENE_NODE_LOD_DISTANCE_SET = 8,	//1B - sceneID; 4B - parent ID; 4B - node ID; float - distance
		SDT_IMAGE_ADD = 9,						//string - imageName; 1B - cube map; 1B - cube side; if (cubeSide!=-1) string - sideName, 1B - imageType (0-WXIMAGE, 1-DDSIMAGE, 2-raw file WXIMAGE, 3-HDRIMAGE as file);
												//WXIMAGE: 2B - height, 2B - width, height*width*3 - RGB data; 1B - has Alpha; height*width - alpha
												//DDSIMAGE: header, 4B - dataSize, data
												//raw file WXIMAGE: 4B - fileSize, data
												//HDRIMAGE as file: 4B - fileSize, data
		SDT_INTERPRETER_PROCESS_COMMANDS = 10,	//string - command
		SDT_SCENE_GEOMETRY_ADD = 11,			//1B - sceneID; 4B - geometry ID; 1B - type;
												//GEOMETRY_TEXT: string - text; float - size; float - spacing; 1B - majorJustify; 1B - minorJustify; 1B - font family; string - font name, 1B - font style
												//GEOMETRY_TRIANGLES: not implemented yet, it will contain also NURBS
		SDT_SCENE_VARIANT_ADD = 12,				//1B - sceneID; 4B - variant ID; string - name, 1B - type, 4B - stateCount, string[stateCount] - state names, 4B - activeState;
												//VARIANT_GEOMETRY: 4B - nodesList.size; nodesList.size*4B - nodesList; stateCount*nodesList.size*1B - node visible
												//VARIANT_MATERIAL: nothing special necessary
												//VARIANT_SET: 4B - detailsList.size; detailsList.size*(1B+4B) - detailsTypes + detailsList; stateCount*(4B+4B) - Shotrcuts (keyCode+modifiers); stateCount*detailsList.size*string - stateDetailsTable
		SDT_SCENE_NODE_SOUND_SET = 13,			//1B -  sceneID; 4B - nodeID; float gain; 1B - looping; 1B - state; float minGain, maxGain, referenceDistance, rollOffFactor, maxDistance, pitch;
												//Vector3 direction; float coneInnerAngle, coneOuterAngle, coneOuterGain, secOffset; string dataSource;
		SDT_REGISTER_EVENT_LISTENER = 14,		//1B - Event::EVENT_TYPE - register serializer for event listening, 1B - transformed (converts *ED, to *)
		SDT_INPUT_TRACKING = 15,				// DeviceData: 4B - id, 4B - type, float - quality, matrix - transformation, 4B - buttons, 4B - number of controls, array of floats - controls, 4B - number of fingers,
												//array of: matrix - transformation, 3xfloat - lengths, 2xfloat - angles, float - radius
		SDT_EXIT,								//without data
		SDT_SCENE_ADD,							//1B - sceneID; string - sceneName
		SDT_SCENE_MATERIAL_REMOVE,				//1B - sceneID; string - material name
		SDT_SCENE_GEOMETRY_REMOVE,				//1B - sceneID; 4B - geometry ID
		SDT_SCENE_NODE_MOVE,					//1B - sceneID; 4B - node ID; 4B - node parent
		SDT_SCENE_NODE_INDEX_CHANGE,			//1B - sceneID; 4B - node ID; 4B - newIndex
		SDT_SCENE_NODE_REMOVE,					//1B - sceneID; 4B - node ID
		SDT_SCENE_NODE_NAME_SET, 				//1B - sceneID; 4B - node ID; string - new name
		SDT_SCENE_NODE_ACTIVE_SET,				//1B - sceneID; 4B - node ID; 1B - active
		SDT_SCENE_CAM_PROJECTION_SET,			//1B - sceneID; 4B - camera ID; float - near plane; float - far plane; float - FOV; float lastWidth; float lastHeight; 1B - upFix; 1B - projectionType
												//if (projectionType==Camera::PERSPECTIVE_GENERIC) then float[3] offset; 1B - eye; float eyeSeparation; float[3] pa; float[3] pb; float[3] pc; float[3] eyeAxis; float[3] lookAt
		SDT_SCENE_ENVIRONMENT_PROBE_ADD,		//4B - sceneID; 4B - environmentProbe ID; 4B - environmentProbe attached node ID; float - near plane; float - far plane; 4B - texture resolution; 1B - enabled; 1B - single shot
		SDT_SCENE_ENVIRONMENT_PROBE_ENABLE,		//4B - sceneID; 4B - environmentProbe ID; 1B - enabled
		SDT_SCENE_ENVIRONMENT_PROBE_SET_SINGLE_SHOT, //4B - sceneID; 4B - environmentProbe ID; 1B - singleShot
		SDT_SCENE_CLIPPING_PLANE_ADD,			//1B - sceneID; 4B - clippingPlane ID; 4 float array - plane; 1B - enabled
		SDT_RENDER_SCENE,						//1B - sceneID; 4B - camera ID; 2B - windowID; 1B - activeStereo, string - node name
		SDT_RENDER_FULLSCREEN_SET,				//2B - window ID, 1B - fsMode, 4B - positionX, 4B - positionY, 4B - sizeX, 4B - sizeY, 4B - colorRGB, String - node name
		SDT_RENDER_WIN_FOCUS,					//2B - window ID
		SDT_RENDER_WIN_CLOSE,					//2B - window ID
		SDT_RENDER_UPDATE,						//2B - window ID, 4B - renderState
		SDT_RENDER_SYNCHRONIZATION_REGISTER,	//2B - window ID, 2B - master window ID
		SDT_RENDER_SYNCHRONIZATION_UNREGISTER,	//2B - window ID*/
		SDT_RENDER_SYNCHRONIZATION_FINISHED_RENDERING, //1B - window ID, 4B - renderState
		SDT_RENDER_SYNCHRONIZATION_BARRIER_RELEASE, //1B - window ID, 4B - renderState
		SDT_RENDER_TILE,						//1B - sceneID, 4B - cameraID, xx bytes RenderTileData
		SDT_RENDER_TILE_DONE,					//1B - sceneID, 4B - cameraID, xx bytes RenderTileData, 4B - size of compressed pixels, yy bytes compressed tile pixels
		SDT_RENDER_TILE_DONE_SYNC,				//1B - sceneID, 4B - cameraID, xx bytes RenderTileData, 4B - size of compressed pixels, yy bytes compressed tile pixels
		SDT_VEHICLE_SIMULATION_DATA = 64,		//4B - sceneID, x bytes binary message
		SDT_TRAFFIC_INFO_DATA = 65,				//4B - sceneID, x bytes binary message
		SDT_COMPRESSION_LEVEL_SET,				//1B - compressionLevel
		SDT_AR_HUD_DATA = 67,					// x bytes binary message
	//#if LUKAS_RUZICKA_DEBUG
		STD_ESTABLISH_CONNECTION,				//4B - port, 4B - address size in bytes, ?B - IPAdress (string)
	//#endif

	#if LUKAS_RUZICKA_DEBUG2
		SDT_NETWORK_TOPOLOGY,
		SDT_CONNECTION_INFORMATION,
	#endif

		SDT_CONNECTION_ERROR,					//0B - The connection is not functional - keep as last entry in the enum

	};
	template <typename DataTarget> class VRUTSerializer {
	private:
		VRUTCompressor compressor;
		/// compression level expected by client - this number should be always equal to client's decompressor comrpession level
		unsigned char expectedCompressionLevel;
		/// compression level for next message - first of all, it has to send anouncemet about this parameter changing (with current expected comrpession level)
		unsigned char desiredCompressionLevel;
		DataTarget *dataTarget;
		VRUTSerializer* Write(const char *buf, int numBytes) {
			if (this->expectedCompressionLevel > 0)
				compressor.Write(buf, numBytes);
			else
				dataTarget->Write(buf, numBytes);
			return this;
		}
		VRUTSerializer* Write(const char *buf) {
			Write(buf, strlen(buf) + 1);
			return this;
		}
		VRUTSerializer* Write(char val) {
			Write(&val, 1);
			return this;
		}
		VRUTSerializer* Write(unsigned long val, int numBytes) {
			for (int i = 0; i < numBytes; i++) {
				char tmp = (char)(val & 0xFF);
				Write(&tmp, 1);
				val >>= 8;
			}
			return this;
		}
		VRUTSerializer* Write(const float *values, int num) {
			Write((char*)values, num * sizeof(float));
			return this;
		}
	public:
		void IncreaseCompressionLevel(void) {
			this->desiredCompressionLevel = (this->compressor.MaxCompressionLevel() <= this->expectedCompressionLevel + 1) ? this->compressor.MaxCompressionLevel() : this->expectedCompressionLevel + 1;
			this->CheckCompressionLevel();
			return;
		}
		void SetCompressionLevel(const unsigned char newCompLvl) {
			this->desiredCompressionLevel = newCompLvl;
			this->CheckCompressionLevel();
			return;
		}
		unsigned char GetCurrentCompressionLevel(void) const {
			return this->expectedCompressionLevel;
		}
		unsigned char GetMaxCompressionLevel(void) const {
			return this->compressor.MaxCompressionLevel();
		}
		CompressionStatisticsCollection<10> compressionStatistics;
		VRUTSerializer(DataTarget *dataTarget) : dataTarget(dataTarget), expectedCompressionLevel(0), desiredCompressionLevel(0) {
			this->compressor.SetCompressionLevel(this->expectedCompressionLevel);
		}
		~VRUTSerializer() {
		}
		size_t TotalRawDataLength() const {
			return this->compressor.GetUncompressedSize() + this->dataTarget->GetSize();
		}
		void CheckCompressionLevel() {
			this->Send(true);
			return;
		}
		VRUTSerializer* Send(const bool checkCompressionLevel = true) {
			assert(sizeof(int) == 4);
			//check compression level
			if (checkCompressionLevel && (this->desiredCompressionLevel != this->expectedCompressionLevel)) {
				this->COMPRESSION_LEVEL_SET(this->desiredCompressionLevel); //in this function call, expectedCompressionLevel is set: expectedCompressionLevel = desiredCompressionLevel
				this->compressor.SetCompressionLevel(this->desiredCompressionLevel);
			} else if ((this->expectedCompressionLevel > 0) && this->compressor.GetUncompressedSize()) { //compress data
				size_t compressedSize = 0;
				const char * data = (const char*)this->compressor.Sync(compressedSize);
				int size = (int)compressedSize;
				this->dataTarget->Write((char*)&size, sizeof(int));
				int uncompressedSize = this->compressor.GetUncompressedSize();
				this->dataTarget->Write((char*)&uncompressedSize, sizeof(int));
				this->dataTarget->Write(data, compressedSize);
				//this->compressionStatistics.EmplaceBack( CompressionStatistics{(size_t)uncompressedSize, compressedSize, this->compressor.GetTimeSpentOnCompression()}, this->expectedCompressionLevel );
				this->compressor.Clear();
			}
			this->dataTarget->Send();
			return this;
		}
		void SCENE_NODE_INSERT(SCENE_ID sceneID, smart_pointer<SceneNode> &node, NODE_ID parentID) {
			if (!node)
				return;
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_SCENE_NODE_INSERT Write"));
		#endif
			//send basic SceneNode
			Write(SDT_SCENE_NODE_INSERT);
			Write(dataTarget->ConvertSID(sceneID))->Write(node->GetType())->Write(dataTarget->ConvertID(node->GetID()), 4)->Write(dataTarget->ConvertID(parentID), 4)->Write(node->IsActive() ? 1 : 0)->Write(node->GetName().utf8_str());
		}
		void SCENE_NODE_TRANSFORM_SET(SCENE_ID sceneID, NODE_ID nodeID, const Matrix *matrix) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_SCENE_NODE_TRANSFORM_SET Write"));
		#endif
			Write(SDT_SCENE_NODE_TRANSFORM_SET)->Write(dataTarget->ConvertSID(sceneID))->Write(dataTarget->ConvertID(nodeID), 4)->Write(matrix->_m, 16);
		}
		void SCENE_GEOMETRY_ADD(SCENE_ID sceneID, const smart_pointer<Geometry> &geom) {
			if (!geom)
				return;
			switch (geom->type) {
			case Geometry::GEOMETRY_TRIANGLE:
			{
				const smart_pointer<GeometryTriangles> geoTri = (const smart_pointer<GeometryTriangles>)geom;
			#if USE_EXTRA_LOGGING
				LOG(wxString::Format(wxT("SDT_SCENE_GEOMETRY_TRIANGLES_ADD Write gid=%lu, vertices=%lu, normals=%lu, texCoords=%lu, indices=%lu, triDescList=%lu"),
					(unsigned long)geom->GetID(), (unsigned long)geoTri->vertices.size(), (unsigned long)geoTri->normals.size(), (unsigned long)geoTri->texCoords.size(),
					(unsigned long)geoTri->indices.size(), (unsigned long)geoTri->triDescList.size()));
			#endif
				Write(SDT_SCENE_GEOMETRY_TRIANGLES_ADD);
				auto geometryID = dataTarget->ConvertGID(geoTri->GetID());
				Write(dataTarget->ConvertSID(sceneID))->Write(geometryID, 4)->Write((unsigned long)geoTri->vertices.size(), 4);

			#if 1
				if (!geoTri->vertices.empty())
					Write((const char *)&geoTri->vertices[0]._v, 3 * sizeof(float)*geoTri->vertices.size());
				Write((unsigned long)geoTri->normals.size(), 4);
				if (!geoTri->normals.empty())
					Write((const char *)&geoTri->normals[0]._v, 3 * sizeof(float)*geoTri->normals.size());
				Write((unsigned long)geoTri->texCoords.size(), 4);
				if (!geoTri->texCoords.empty())
					Write((const char *)&geoTri->texCoords[0]._v, 2 * sizeof(float)*geoTri->texCoords.size());

				Write((unsigned long)geoTri->indices.size(), 4);
				unsigned int bytesPerInd = 1 + ((geoTri->vertices.size()>256) ? 1 : 0) + ((geoTri->vertices.size()>65536) ? 1 : 0) + ((geoTri->vertices.size()>16777216) ? 1 : 0);
				/*for(size_t i=0; i<geoTri->indices.size(); i++)
				Write((unsigned long)geoTri->indices.at(i), bytesPerInd);*/
				{
					unsigned char *buffer = new unsigned char[geoTri->indices.size()*bytesPerInd];
					unsigned char *pos = buffer;
					switch (bytesPerInd) {
					case 1:
						for (auto index : geoTri->indices)
							*pos++ = (unsigned char)index;
						break;
					case 2:
						for (auto index : geoTri->indices) {
							*pos++ = (unsigned char)index;
							*pos++ = (unsigned char)(index >> 8);
						}
						break;
					case 3:
						for (auto index : geoTri->indices) {
							*pos++ = (unsigned char)index;
							*pos++ = (unsigned char)(index >> 8);
							*pos++ = (unsigned char)(index >> 16);
						}
						break;
					case 4:
						for (auto index : geoTri->indices) {
							*pos++ = (unsigned char)index;
							*pos++ = (unsigned char)(index >> 8);
							*pos++ = (unsigned char)(index >> 16);
							*pos++ = (unsigned char)(index >> 24);
						}
						break;
					default:
						for (auto index : geoTri->indices) {
							unsigned int ind = index;
							for (unsigned int i = 0; i<bytesPerInd; ++i) {
								*pos++ = (unsigned char)ind;
								ind >>= 8;
							}
						}
						break;
					}
					Write((const char *)buffer, geoTri->indices.size()*bytesPerInd);
					delete[] buffer;
				}

				Write((unsigned long)geoTri->triDescList.size(), 4);
				int bytesPerTri = 1 + ((geoTri->indices.size()>256) ? 1 : 0) + ((geoTri->indices.size()>65536) ? 1 : 0) + ((geoTri->indices.size()>16777216) ? 1 : 0);
				unsigned char * buffer = new unsigned char[geoTri->triDescList.size() * (bytesPerTri + 1)];
				unsigned char * pos = buffer;
				for (auto &triDesc : geoTri->triDescList) {
					*pos++ = (unsigned char)triDesc.first;
					if (bytesPerTri >= 2)
						*pos++ = (unsigned char)(triDesc.first >> 8);
					if (bytesPerTri >= 3)
						*pos++ = (unsigned char)(triDesc.first >> 16);
					if (bytesPerTri >= 4)
						*pos++ = (unsigned char)(triDesc.first >> 24);
					*pos++ = (unsigned char)triDesc.second;
				}
				Write((const char*)buffer, geoTri->triDescList.size() * (bytesPerTri + 1));
				delete[] buffer;
			#else
				wxMemoryOutputStream mos;
				wxZlibOutputStream zos(mos, 9, 0);
				for (size_t i = 0; i<geoTri->vertices.size(); i++)
					zos.Write(geoTri->vertices.at(i)._v, 3 * 4);

				Write((unsigned long)geoTri->normals.size(), 4);
				for (size_t i = 0; i<geoTri->normals.size(); i++)
					zos.Write(geoTri->normals.at(i)._v, 3 * 4);

				Write((unsigned long)geoTri->texCoords.size(), 4);
				for (size_t i = 0; i<geoTri->texCoords.size(); i++)
					zos.Write(geoTri->texCoords.at(i)._v, 2 * 4);

				Write((unsigned long)geoTri->indices.size(), 4);
				int bytesPerInd = 1 + ((geoTri->vertices.size()>256) ? 1 : 0) + ((geoTri->vertices.size()>65536) ? 1 : 0) + ((geoTri->vertices.size()>16777216) ? 1 : 0);
				unsigned char tmp[4] = {0,0,0,0};
				for (size_t i = 0; i<geoTri->indices.size(); i++) {
					ULongToBytes((unsigned long)geoTri->indices.at(i), tmp);
					zos.Write(tmp, bytesPerInd);
				}
				//m_sendMeasurement+=(size_t)((log((float)geoTri->vertices.size())/log(2.0f))*(float)geoTri->indices.size()/8.0f);

				Write((unsigned long)geoTri->triDescList.size(), 4);
				int bytesPerTri = 1 + ((geoTri->indices.size()>256) ? 1 : 0) + ((geoTri->indices.size()>65536) ? 1 : 0) + ((geoTri->indices.size()>16777216) ? 1 : 0);
				for (size_t i = 0; i<geoTri->triDescList.size(); i++) {
					ULongToBytes((unsigned long)geoTri->triDescList.at(i).first, tmp);
					zos.Write(tmp, bytesPerTri);
					tmp[0] = geoTri->triDescList.at(i).second & 0xFF;
					zos.Write(tmp, 1);
				}
				//m_sendMeasurement+=geoTri->triDescList.size()*(bytesPerTri);

				zos.Close();
				wxStreamBuffer* theBuffer = mos.GetOutputStreamBuffer();
				Write((unsigned long)mos.GetSize(), 4);
				Write((const char *)theBuffer->GetBufferStart(), (int)mos.GetSize());
			#endif
				break;
			}
			case Geometry::GEOMETRY_TEXT:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_SCENE_GEOMETRY_ADD Write"));
			#endif
				const smart_pointer<GeometryText> geoTex = (const smart_pointer<GeometryText>)geom;

				Write(SDT_SCENE_GEOMETRY_ADD);
				float sizeSpacing[2];
				sizeSpacing[0] = geoTex->GetSize();
				sizeSpacing[1] = geoTex->GetSpacing();
				Write(dataTarget->ConvertSID(sceneID))->Write(dataTarget->ConvertGID(geoTex->GetID()), 4)->Write(geom->type)->Write(geoTex->GetText().utf8_str())->Write(sizeSpacing, 2)->Write(geoTex->GetMajorJustify());
				Write(geoTex->GetMinorJustify())->Write(geoTex->GetFontFamily())->Write(geoTex->GetFontName().utf8_str())->Write(geoTex->GetFontStyle());
				break;
			}
			default:
				LOGWARNING(wxString::Format(wxT("<VRUTSerializer>SCENE_GEOMETRY_ADD: unsupported geometry type %i"), geom->type));
				break;
			}
			Send();
		}
		void SCENE_VARIANT_ADD(SCENE_ID sceneID, const smart_pointer<Variant> &var) {
			if (!var)
				return;
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_SCENE_VARIANT_ADD Write"));
		#endif
			Write(SDT_SCENE_VARIANT_ADD);
			Write(dataTarget->ConvertSID(sceneID))->Write(dataTarget->ConvertVID(var->GetID()), 4)->Write(var->GetName().utf8_str());
			Write(var->type);
			Write(var->statesList.size(), 4);
			for (auto &state : var->statesList)
				Write(state.utf8_str());
			Write(var->activeState, 4);
			switch (var->type) {
			case Variant::VARIANT_GEOMETRY:
			{
				VariantGeometry *varG = (VariantGeometry *)var.getPtr();
				Write(varG->nodesList.size(), 4);
				for (auto &nodeID : varG->nodesList)
					Write(dataTarget->ConvertID(nodeID), 4);
				for (auto &stateNodes : varG->stateNodesTable)
					for (auto nodeVisible : stateNodes)
						Write(nodeVisible ? 1 : 0);
				break;
			}
			case Variant::VARIANT_MATERIAL:
				//nothing special is necessary
				break;
			case Variant::VARIANT_SET:
			{
				VariantSet *varS = (VariantSet *)var.getPtr();
				Write(varS->detailsList.size(), 4);
				for (size_t i = 0; i < varS->detailsTypes.size(); ++i) {
					Write(varS->detailsTypes[i]);
					switch (varS->detailsTypes[i]) {
					case VariantSet::VARIANT_SET_DETAIL_VARIANT:
						Write(dataTarget->ConvertVID(varS->detailsList[i]), 4);
						break;
					case VariantSet::VARIANT_SET_DETAIL_SWITCH:
						Write(dataTarget->ConvertID(varS->detailsList[i]), 4);
						break;
					case VariantSet::VARIANT_SET_DETAIL_SCRIPT:
						Write(varS->detailsList[i], 4);
						break;
					default:
						LOGERROR(wxString::Format(wxT("<VRUTSerializer>SCENE_VARIANT_ADD: unsupported VariantSet::VariantSetDetailType %i"), varS->detailsTypes[i]));
						break;
					}
				}
				for (auto &shortCut : varS->shortCuts)
					Write(shortCut.keyCode, 4)->Write(shortCut.modifiers, 4);
				for (auto &stateDetails : varS->stateDetailsTable)
					for (auto &detail : stateDetails)
						Write(detail.utf8_str());
				break;
			}
			case Variant::VARIANT_CAMERA:
			{
				VariantCamera *varC = (VariantCamera *)var.getPtr();
				if (!varC->statesList.empty()) {
					Write((const char *)&varC->transformations[0], 16 * sizeof(float)*varC->transformations.size());
					Write((const char *)&varC->FOVs[0], sizeof(float)*varC->FOVs.size());
				}
				break;
			}
			default:
				LOGERROR(wxString::Format(wxT("<VRUTSerializer>SCENE_VARIANT_ADD: unsupported variant type %i"), var->type));
			}
			Send();
		}
		void SCENE_NODE_SOUND_SET(const SCENE_ID sceneID, const NODE_ID nodeID, const float gain, const bool looping, const SoundSourceNode::SoundSourceState state,
			const float minGain, const float maxGain, const float referenceDistance, const float rollOffFactor, const float maxDistance, const float pitch, const Vector3 &direction,
			const float coneInnerAngle, const float coneOuterAngle, const float coneOuterGain, const float secOffset, const wxString &soundDataSource) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_SCENE_NODE_SOUND_SET Write"));
		#endif
			Write(SDT_SCENE_NODE_SOUND_SET);
			Write(dataTarget->ConvertSID(sceneID))->Write(dataTarget->ConvertID(nodeID), 4)->Write(&gain, 1)->Write(looping ? 1 : 0)->Write(state)->Write(&minGain, 1)->Write(&maxGain, 1)->Write(&referenceDistance, 1);
			Write(&rollOffFactor, 1)->Write(&maxDistance, 1)->Write(&pitch, 1)->Write(direction._v, 3)->Write(&coneInnerAngle, 1)->Write(&coneInnerAngle, 1)->Write(&coneOuterGain, 1);
			Write(&secOffset, 1)->Write(soundDataSource.utf8_str());
		}
		void SCENE_NODE_GEOMETRY_SET(SCENE_ID sceneID, NODE_ID nodeID, GEOMETRY_ID gid) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_SCENE_NODE_GEOMETRY_SET Write"));
		#endif
			Write(SDT_SCENE_NODE_GEOMETRY_SET)->Write(dataTarget->ConvertSID(sceneID))->Write(dataTarget->ConvertID(nodeID), 4)->Write(dataTarget->ConvertGID(gid), 4);
		}
		void SCENE_MATERIAL_ADD(SCENE_ID sceneID, const smart_pointer<Material> &mat, bool localPaths = false) {
			if (!mat)
				return;
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_SCENE_MATERIAL_ADD Write"));
		#endif
			Write(SDT_SCENE_MATERIAL_ADD);
			Write(dataTarget->ConvertSID(sceneID))->Write(mat->name.utf8_str());
			Write(mat->ambient._v, 4)->Write(mat->diffuse._v, 4)->Write(mat->specular._v, 4)->Write(mat->emission._v, 4)->Write(&mat->shininess, 1)->Write(&mat->reflectivity, 1);
			Write(mat->depthFunc, 4)->Write(&mat->textureMix, 1)->Write(mat->flags, 4)->Write(mat->texFlags, 4);
			if (localPaths)
				Write(wxFileName(mat->imageName).GetFullName().utf8_str());
			else
				Write(mat->imageName.utf8_str());
			Write(mat->blendSrc, 4)->Write(mat->blendDst, 4);
			if (mat->shader) {
				Write(mat->shader->type);
				switch (mat->shader->type) {
				case ShaderProgram::LANG_GLSL:
					if (localPaths)
						Write(mat->shader->fsSource.utf8_str())->Write(wxFileName(mat->shader->fsFileName).GetFullName().utf8_str())->Write(mat->shader->vsSource.utf8_str())->Write(wxFileName(mat->shader->vsFileName).GetFullName().utf8_str());
					else
						Write(mat->shader->fsSource.utf8_str())->Write(mat->shader->fsFileName.utf8_str())->Write(mat->shader->vsSource.utf8_str())->Write(mat->shader->vsFileName.utf8_str());
					break;
				case ShaderProgram::LANG_CGFX:
					if (localPaths)
						Write(mat->shader->vsSource.utf8_str())->Write(wxFileName(mat->shader->vsFileName).GetFullName().utf8_str());
					else
						Write(mat->shader->vsSource.utf8_str())->Write(mat->shader->vsFileName.utf8_str());
					break;
				case ShaderProgram::LANG_OPENRT:
					break;
				case ShaderProgram::LANG_NONE:
					break;
				}
				char shaderParamsCount = 0;
				for (auto &param : mat->shader->paramList)
					if (!mat->shader->IsDefaultParam(param))
						++shaderParamsCount;
				Write(shaderParamsCount);
				for (auto &param : mat->shader->paramList) {
					if (mat->shader->IsDefaultParam(param))
						continue;
					Write(param.name.utf8_str())->Write(param.type);
					switch (param.type) {
					case ShaderParam::BOOL:
						Write(param.iVal);
						break;
					case ShaderParam::INT:
						Write((unsigned long)param.iVal, 4);
						break;
					case ShaderParam::FLOAT1:
						Write(param.fVals, 1);
						break;
					case ShaderParam::FLOAT2:
						Write(param.fVals, 2);
						break;
					case ShaderParam::FLOAT3:
						Write(param.fVals, 3);
						break;
					case ShaderParam::FLOAT4:
						Write(param.fVals, 4);
						break;
					case ShaderParam::SAMPLER:
					case ShaderParam::SAMPLERCUBE:
					case ShaderParam::SAMPLER3D:
						if (localPaths)
							Write(wxFileName(param.imageName).GetFullName().utf8_str());
						else
							Write(param.imageName.utf8_str());
						break;
					}
				}
			} else
				Write(ShaderProgram::LANG_NONE)->Write((char)0);
			Send();
		}
		void SCENE_NODE_MATERIAL_SET(SCENE_ID sceneID, NODE_ID nodeID, const wxString &materialName) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_SCENE_NODE_MATERIAL_SET Write"));
		#endif
			Write(SDT_SCENE_NODE_MATERIAL_SET)->Write(dataTarget->ConvertSID(sceneID))->Write(dataTarget->ConvertID(nodeID), 4)->Write(materialName.utf8_str());
		}
		void SCENE_NODE_SWITCH_ACTIVECHILD_SET(SCENE_ID sceneID, NODE_ID nodeID, size_t activeChild) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_SCENE_NODE_SWITCH_ACTIVECHILD_SET Write"));
		#endif
			Write(SDT_SCENE_NODE_SWITCH_ACTIVECHILD_SET)->Write(dataTarget->ConvertSID(sceneID))->Write(dataTarget->ConvertID(nodeID), 4)->Write((unsigned long)activeChild, 4);
		}
		void SCENE_NODE_LIGHT_SET(SCENE_ID sceneID, NODE_ID nodeID, const Light &light) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_SCENE_NODE_LIGHT_SET Write"));
		#endif
			Write(SDT_SCENE_NODE_LIGHT_SET)->Write(dataTarget->ConvertSID(sceneID))->Write(dataTarget->ConvertID(nodeID), 4);
			Write(light.type)->Write(&light.angle, 1)->Write(&light.exponent, 1)->Write(light.diffuse._v, 4);
			Write(light.attenuation._v, 3)->Write(&light.diffuse.w, 1)->Write(light.ies.utf8_str());
		}
		void SCENE_NODE_LOD_DISTANCE_SET(SCENE_ID sceneID, NODE_ID parentID, NODE_ID nodeID, float distance) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_SCENE_NODE_LOD_DISTANCE_SET Write"));
		#endif
			Write(SDT_SCENE_NODE_LOD_DISTANCE_SET)->Write(dataTarget->ConvertSID(sceneID))->Write(dataTarget->ConvertID(parentID), 4)->Write(dataTarget->ConvertID(nodeID), 4)->Write(&distance, 1);
		}
		void SCENE_IMAGE_ADD(const wxString &imageName, int cubeSide = -1, bool localPaths = false) {
			const_smart_pointer<Image> image = KERNEL->sceneManager->GetImage(imageName, false);
			if (!image || !image->IsOk())
				return;
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_IMAGE_ADD Write"));
		#endif
			Write(SDT_IMAGE_ADD);
			if (localPaths)
				Write(wxFileName(imageName).GetFullName().utf8_str());
			else
				Write(imageName.utf8_str());
			Write((char)image->IsCube())->Write((char)cubeSide);
			if (cubeSide != -1)
				Write(image->GetCubeSideName(cubeSide).utf8_str());
			switch (image->GetType()) {
			case Image::WXIMAGE:
			{
				const ImageCommon *imcommon = static_cast<const ImageCommon *>(image.getPtr());
				unsigned long height = imcommon->GetHeight();
				unsigned long width = imcommon->GetWidth();
				bool hasAlpha = imcommon->GetWxImage(cubeSide)->HasAlpha();
				wxFFileInputStream *file = NULL;
				size_t fileSize = 0;
				if (wxFileExists((cubeSide == -1) ? imageName : image->GetCubeSideName(cubeSide))) {
					file = new wxFFileInputStream((cubeSide == -1) ? imageName : image->GetCubeSideName(cubeSide));
					if (file && file->IsOk())
						fileSize = file->GetSize();
				}
				if ((fileSize == 0) || (height*width*(3 + (hasAlpha ? 1 : 0)))<fileSize) {
					Write((char)0)->Write(height, 2)->Write(width, 2);
					Write((char*)(imcommon->GetWxImage(cubeSide)->GetData()), height*width * 3);
					Write(hasAlpha ? 1 : 0);
					if (hasAlpha)
						Write((char*)(imcommon->GetWxImage(cubeSide)->GetAlpha()), height*width);
				} else {
					//send as file
					char *buff = new char[fileSize];
					file->Read(buff, fileSize);
					Write((char)2)->Write((unsigned long)fileSize, 4)->Write(buff, fileSize);
					delete[] buff;
				}
				SAFE_DELETE(file);
			}
			break;
			case Image::DDSIMAGE:
			{
				const ImageDDS *imDDS = static_cast<const ImageDDS *>(image.getPtr());
				unsigned long dataSize = imDDS->GetImage().dataSize;
				Write((char)1)->Write((char*)&(imDDS->GetImage().header), sizeof(imDDS->GetImage().header));
				Write(dataSize, 4)->Write((char*)imDDS->GetImage().data, dataSize);
			}
			break;
			case Image::HDRIMAGE:
			{
				wxFFileInputStream file((cubeSide == -1) ? imageName : image->GetCubeSideName(cubeSide));
				size_t fileSize = file.GetSize();
				//send as file
				char *buff = new char[fileSize];
				file.Read(buff, fileSize);
				Write((char)3)->Write((unsigned long)fileSize, 4)->Write(buff, fileSize);
				delete[] buff;
			}
			break;
			case Image::UNKNOWN:
				break;
			}
			Send();
		}
		void INTERPRETER_PROCESS_COMMANDS(const wxString &commands) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_INTERPRETER_PROCESS_COMMANDS Write"));
		#endif
			Write(SDT_INTERPRETER_PROCESS_COMMANDS)->Write(commands.utf8_str());
		}
		void EXIT() {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_EXIT Write"));
		#endif
			Write(SDT_EXIT);
		}
		void SCENE_ADD(const wxString &sceneName, SCENE_ID sceneID) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_SCENE_ADD Write"));
		#endif
			Write(SDT_SCENE_ADD)->Write(dataTarget->ConvertSID(sceneID))->Write(sceneName.utf8_str());
		}
		void SCENE_MATERIAL_REMOVE(SCENE_ID sceneID, const wxString &materialName) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_SCENE_MATERIAL_REMOVE Write"));
		#endif
			Write(SDT_SCENE_MATERIAL_REMOVE)->Write(dataTarget->ConvertSID(sceneID))->Write(materialName.utf8_str());
		}
		void SCENE_GEOMETRY_REMOVE(SCENE_ID sceneID, GEOMETRY_ID gid) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_SCENE_GEOMETRY_REMOVE Write"));
		#endif
			Write(SDT_SCENE_GEOMETRY_REMOVE)->Write(dataTarget->ConvertSID(sceneID))->Write(dataTarget->ConvertGID(gid), 4);
		}
		void SCENE_NODE_MOVE(SCENE_ID sceneID, NODE_ID nodeID, NODE_ID targetID) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_SCENE_NODE_MOVE Write"));
		#endif
			Write(SDT_SCENE_NODE_MOVE)->Write(dataTarget->ConvertSID(sceneID))->Write(dataTarget->ConvertID(nodeID), 4)->Write(dataTarget->ConvertID(targetID), 4);
		}
		void SCENE_NODE_INDEX_CHANGE(SCENE_ID sceneID, NODE_ID nodeID, size_t newIndex) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_SCENE_NODE_INDEX_CHANGE Write"));
		#endif
			Write(SDT_SCENE_NODE_INDEX_CHANGE)->Write(dataTarget->ConvertSID(sceneID))->Write(dataTarget->ConvertID(nodeID), 4)->Write(newIndex, 4);
		}
		void SCENE_NODE_REMOVE(SCENE_ID sceneID, NODE_ID nodeID) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_SCENE_NODE_REMOVE Write"));
		#endif
			Write(SDT_SCENE_NODE_REMOVE)->Write(dataTarget->ConvertSID(sceneID))->Write(dataTarget->ConvertID(nodeID), 4);
		}
		void SCENE_NODE_NAME_SET(SCENE_ID sceneID, NODE_ID nodeID, const wxString & newName) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_SCENE_NODE_NAME_SET Write"));
		#endif
			Write(SDT_SCENE_NODE_NAME_SET)->Write(dataTarget->ConvertSID(sceneID))->Write(dataTarget->ConvertID(nodeID), 4)->Write(newName.utf8_str());
		}
		void SCENE_NODE_ACTIVE_SET(SCENE_ID sceneID, NODE_ID nodeID, bool active) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_SCENE_NODE_ACTIVE_SET Write"));
		#endif
			Write(SDT_SCENE_NODE_ACTIVE_SET)->Write(dataTarget->ConvertSID(sceneID))->Write(dataTarget->ConvertID(nodeID), 4)->Write(active ? 1 : 0);
		}
		void SCENE_CAM_PROJECTION_SET(SCENE_ID sceneID, smart_pointer<Camera> &camera) {
			if (!camera || (camera->GetType() != SceneNode::CAMERA))
				return;
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_SCENE_CAM_PROJECTION_SET Write"));
		#endif
			float nearPlane = camera->GetNearPlane();
			float farPlane = camera->GetFarPlane();
			float FOV = camera->GetFOV();
			Camera::UP_FIX upFix = camera->GetUpFix();
			unsigned int lastWidth = camera->GetLastWidth();
			unsigned int lastHeight = camera->GetLastHeight();
			Vector3 lookAt = camera->GetLookAt();
			Camera::PROJECTION_TYPE projectionType = camera->GetProjectionType();
			Write(SDT_SCENE_CAM_PROJECTION_SET)->Write(dataTarget->ConvertSID(sceneID))->Write(dataTarget->ConvertID(camera->GetID()), 4)->Write(&nearPlane, 1)->Write(&farPlane, 1)->Write(&FOV, 1);
			Write((unsigned long)lastWidth, 4)->Write((unsigned long)lastHeight, 4)->Write((char)upFix)->Write((char)projectionType);
			if (projectionType == Camera::PERSPECTIVE_GENERIC) {
				Camera::EYE_TYPE eye = camera->GetEye();
				Vector3 offset(camera->GetOffset());
				float eyeSeparation = camera->GetEyeSeparation();
				Vector3 pa, pb, pc;
				camera->GetPabc(pa, pb, pc);
				Vector3 eyeAxis(camera->GetEyeAxis());
				Write(offset._v, 3)->Write((char)eye)->Write(&eyeSeparation, 1)->Write(pa._v, 3)->Write(pb._v, 3)->Write(pc._v, 3)->Write(eyeAxis._v, 3)->Write(lookAt._v, 3);
			}
			Send();
		}
		void SCENE_ENVIRONMENT_PROBE_ADD(SCENE_ID sceneID, const smart_pointer<EnvironmentProbe> &environmentProbe) {
			if (!environmentProbe)
				return;
			float nearp(environmentProbe->GetNearPlaneDistance());
			float farp(environmentProbe->GetFarPlaneDistance());
			Write(SDT_SCENE_ENVIRONMENT_PROBE_ADD)->Write(dataTarget->ConvertSID(sceneID), 4)->Write(dataTarget->ConvertEID(environmentProbe->GetID()), 4)->Write(dataTarget->ConvertID(environmentProbe->GetAttachedNodeID()), 4)->
				Write(&nearp, 1)->Write(&farp, 1)->Write(environmentProbe->GetTextureDimension(), 4)->Write(environmentProbe->IsEnabled(), 1)->Write(environmentProbe->GetSingleShot(), 1);
		}
		void SCENE_ENVIRONMENT_PROBE_ENABLE(SCENE_ID sceneID, const ENVIRONMENT_PROBE_ID environmentProbeID, bool enable) {
			Write(SDT_SCENE_ENVIRONMENT_PROBE_ENABLE)->Write(dataTarget->ConvertSID(sceneID), 4)->Write(dataTarget->ConvertEID(environmentProbeID), 4)->Write(enable, 1);
		}
		void SCENE_ENVIRONMENT_PROBE_SET_SINGLE_SHOT(SCENE_ID sceneID, const ENVIRONMENT_PROBE_ID environmentProbeID, bool singleShot) {
			Write(SDT_SCENE_ENVIRONMENT_PROBE_SET_SINGLE_SHOT)->Write(dataTarget->ConvertSID(sceneID), 4)->Write(dataTarget->ConvertEID(environmentProbeID), 4)->Write(singleShot, 1);
		}
		void SCENE_CLIPPING_PLANE_ADD(SCENE_ID sceneID, const ClippingPlane &clippingPlane) {
			Write(SDT_SCENE_CLIPPING_PLANE_ADD)->Write(dataTarget->ConvertSID(sceneID))->Write(dataTarget->ConvertCID(clippingPlane.cpid), 4)->Write(clippingPlane.plane._v, 4)->Write(clippingPlane.enabled, 1);
		}
		void RENDER_SCENE(SCENE_ID sceneID, NODE_ID cameraID, RENDER_WINDOW_ID windowID, int activeStereo, wxString nodeName) {
			Write(SDT_RENDER_SCENE)->Write(dataTarget->ConvertSID(sceneID))->Write(dataTarget->ConvertID(cameraID), 4)->Write(dataTarget->ConvertWID(windowID), sizeof(RENDER_WINDOW_ID))->Write(activeStereo)->Write(nodeName.utf8_str());
		}
		void RENDER_FULLSCREEN_SET(const RENDER_WINDOW_ID windowID, const int fsMode, const int positionX, const int positionY, const int sizeX, const int sizeY, const unsigned long colorRGB, const wxString &nodeName) {
			Write(SDT_RENDER_FULLSCREEN_SET)->Write(dataTarget->ConvertWID(windowID), sizeof(RENDER_WINDOW_ID))->Write(fsMode)->Write((unsigned long)positionX, 4)->Write((unsigned long)positionY, 4)->Write((unsigned long)sizeX, 4)
				->Write((unsigned long)sizeY, 4)->Write(colorRGB, 4)->Write(nodeName.utf8_str());
		}
		void RENDER_WIN_FOCUS(RENDER_WINDOW_ID windowID) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_RENDER_WIN_FOCUS Write"));
		#endif
			Write(SDT_RENDER_WIN_FOCUS)->Write(dataTarget->ConvertWID(windowID), sizeof(RENDER_WINDOW_ID));
		}
		void RENDER_WIN_CLOSE(RENDER_WINDOW_ID windowID) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_RENDER_WIN_CLOSE Write"));
		#endif
			Write(SDT_RENDER_WIN_CLOSE)->Write(dataTarget->ConvertWID(windowID), sizeof(RENDER_WINDOW_ID));
		}
		void RENDER_UPDATE(RENDER_WINDOW_ID windowID, int renderState) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_RENDER_UPDATE Write"));
		#endif
			Write(SDT_RENDER_UPDATE)->Write(dataTarget->ConvertWID(windowID), sizeof(RENDER_WINDOW_ID))->Write(renderState, 4);
		}
		void RENDER_SYNCHRONIZATION_REGISTER(RENDER_WINDOW_ID windowID, RENDER_WINDOW_ID masterWindowID) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_RENDER_SYNCHRONIZATION_REGISTER Write"));
		#endif
			Write(SDT_RENDER_SYNCHRONIZATION_REGISTER)->Write(dataTarget->ConvertWID(windowID), sizeof(RENDER_WINDOW_ID))->Write(dataTarget->ConvertWID(masterWindowID), sizeof(RENDER_WINDOW_ID));
		}
		void RENDER_SYNCHRONIZATION_UNREGISTER(RENDER_WINDOW_ID windowID) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_RENDER_SYNCHRONIZATION_UNREGISTER Write"));
		#endif
			Write(SDT_RENDER_SYNCHRONIZATION_UNREGISTER)->Write(dataTarget->ConvertWID(windowID), sizeof(RENDER_WINDOW_ID));
		}
		void RENDER_SYNCHRONIZATION_FINISHED_RENDERING(RENDER_WINDOW_ID windowID, int renderState) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_RENDER_SYNCHRONIZATION_FINISHED_RENDERING Write"));
		#endif
		#ifdef SYNC_DEBUG
			LOG(wxString::Format(wxT("Sending EVT_RENDER_SYNCHRONIZATION_FINISHED_RENDERING (windowID=%i, renderState=%i)"), (int)dataTarget->ConvertWID(windowID), (int)renderState));
		#endif
			Write(SDT_RENDER_SYNCHRONIZATION_FINISHED_RENDERING)->Write(dataTarget->ConvertWID(windowID), sizeof(RENDER_WINDOW_ID))->Write(renderState, 4);
		}
		void RENDER_SYNCHRONIZATION_BARRIER_RELEASE(RENDER_WINDOW_ID windowID, int renderState) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_RENDER_SYNCHRONIZATION_BARRIER_RELEASE Write"));
		#endif
		#ifdef SYNC_DEBUG
			LOG(wxString::Format(wxT("Sending SDT_RENDER_SYNCHRONIZATION_BARRIER_RELEASE (windowID=%lu, barrier=%i)"), (unsigned long)dataTarget->ConvertWID(windowID), renderState));
		#endif
			Write(SDT_RENDER_SYNCHRONIZATION_BARRIER_RELEASE)->Write(dataTarget->ConvertWID(windowID), sizeof(RENDER_WINDOW_ID))->Write(renderState, 4);
		}
		void RENDER_TILE(SCENE_ID sceneID, NODE_ID cameraID, const RenderTileData &data) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_RENDER_TILE Write"));
		#endif
			Write(SDT_RENDER_TILE);

		#if LUKAS_RUZICKA_DEBUG
			unsigned long long totalTime = data.totalTime.GetValue();
			Write((char*)&totalTime, sizeof(unsigned long long));
		#endif

			Write(dataTarget->ConvertSID(sceneID))->Write(dataTarget->ConvertID(cameraID), 4)->Write(data.frameId, 4)->Write(data.tileIndex, 4)->Write(data.LOD, 2)->Write(data.skip, 2)->Write(data.cameraIndex, 4)->Write(data.antialiasing ? 1 : 0)->Write(data.minVal.x, 4)->Write(data.minVal.y, 4);
			Write(data.maxVal.x, 4)->Write(data.maxVal.y, 4)->Write(data.imageWidth, 2)->Write(data.imageHeight, 2)->Write(data.workerId, 4)->Write(data.samples, 4)->Write(data.numPixels, 4);

			Send();
		}
		void RENDER_TILE_DONE(SCENE_ID sceneID, NODE_ID cameraID, const RenderTileData & data) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_RENDER_TILE_DONE Write"));
		#endif
			Write(SDT_RENDER_TILE_DONE);

		#if LUKAS_RUZICKA_DEBUG
			unsigned long long totalTime = data.totalTime.GetValue();
			Write((char*)&totalTime, sizeof(unsigned long long));
		#endif

			Write(dataTarget->ConvertSID(sceneID))->Write(dataTarget->ConvertID(cameraID), 4)->Write(data.frameId, 4)->Write(data.tileIndex, 4)->Write(data.LOD, 2)->Write(data.skip, 2)->Write(data.cameraIndex, 4)->Write(data.antialiasing ? 1 : 0)->Write(data.minVal.x, 4)->Write(data.minVal.y, 4);
			Write(data.maxVal.x, 4)->Write(data.maxVal.y, 4)->Write(data.imageWidth, 2)->Write(data.imageHeight, 2)->Write(data.workerId, 4)->Write(data.samples, 4);
			if (data.numPixels > 0) {
				if (data.pixels) {
					Write(data.numPixels, 4);
				#if USE_HALF_PRECISION
					Vector4Float16 v;
					for (int i = 0; i < data.numPixels; ++i) {
						float32to16(data.pixels.get()[i].x, &v.x);
						float32to16(data.pixels.get()[i].y, &v.y);
						float32to16(data.pixels.get()[i].z, &v.z);
						float32to16(data.pixels.get()[i].w, &v.w);

						Write((const char*)&v, sizeof(Vector4Float16));
					}
				#else
					Write((const char*)data.pixels.get(), sizeof(Vector4) * data.numPixels);
				#endif

				} else {
					LOGERROR(wxT("VRUTSerializer: RENDER_TILE_DONE non zero numPixels but pixels is NULL"));
					int nula = 0;
					Write(nula, 4);
				}
			} else {
				int nula = 0;
				Write(nula, 4);
			}
			Send();
		}
		void RENDER_TILE_DONE_SYNC(SCENE_ID sceneID, NODE_ID cameraID, const RenderTileData & data) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_RENDER_TILE_DONE_SYNC Write"));
		#endif
			Write(SDT_RENDER_TILE_DONE_SYNC);

		#if LUKAS_RUZICKA_DEBUG
			unsigned long long totalTime = data.totalTime.GetValue();
			Write((char*)&totalTime, sizeof(unsigned long long));
		#endif

			Write(dataTarget->ConvertSID(sceneID))->Write(dataTarget->ConvertID(cameraID), 4)->Write(data.frameId, 4)->Write(data.tileIndex, 4)->Write(data.LOD, 2)->Write(data.skip, 2)->Write(data.cameraIndex, 4)->Write(data.antialiasing ? 1 : 0)->Write(data.minVal.x, 4)->Write(data.minVal.y, 4);
			Write(data.maxVal.x, 4)->Write(data.maxVal.y, 4)->Write(data.imageWidth, 2)->Write(data.imageHeight, 2)->Write(data.workerId, 4)->Write(data.samples, 4);
			if (data.numPixels > 0) {
				if (data.pixels) {
					Write(data.numPixels, 4);
				#if USE_HALF_PRECISION
					Vector4Float16 v;
					for (int i = 0; i < data.numPixels; ++i) {
						float32to16(data.pixels.get()[i].x, &v.x);
						float32to16(data.pixels.get()[i].y, &v.y);
						float32to16(data.pixels.get()[i].z, &v.z);
						float32to16(data.pixels.get()[i].w, &v.w);

						Write((const char*)&v, sizeof(Vector4Float16));
					}
				#else
					Write((const char*)data.pixels.get(), sizeof(Vector4) * data.numPixels);
				#endif
				} else {
					LOGERROR(wxT("VRUTSerializer: RENDER_TILE_DONE_SYNC non zero numPixels but pixels is NULL"));
					int nula = 0;
					Write(nula, 4);
				}
			} else {
				int nula = 0;
				Write(nula, 4);
			}
			Send();
		}
		void COMPRESSION_LEVEL_SET(const unsigned char newCompressionLevel) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_COMPRESSION_LEVEL_SET Write"));
		#endif
			LOG(wxString::Format(wxT("VRUTSerializer::COMPRESSION_LEVEL_SET(unsigned char) from %i to %i"), this->expectedCompressionLevel, newCompressionLevel));
			Write(SDT_COMPRESSION_LEVEL_SET)->Write(newCompressionLevel)->Send(false);
			this->expectedCompressionLevel = newCompressionLevel;
		}
		void REGISTER_EVENT_LISTENER(const Event::EVENT_TYPE eventType, const bool transformed) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_REGISTER_EVENT_LISTENER Write"));
		#endif
			Write(SDT_REGISTER_EVENT_LISTENER)->Write(eventType)->Write(transformed ? 1 : 0)->Send(false);
		}
		void INPUT_TRACKING(const DeviceData &data) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_INPUT_TRACKING Write"));
		#endif
			Write(SDT_INPUT_TRACKING)->Write((unsigned long)data.id, 4)->Write((unsigned long)data.type, 4)->Write(&data.quality, 1)->Write(data.matrix._m, 16)->Write((unsigned long)data.buttons, 4);
			Write((unsigned long)data.controls.size(), 4);
			if (!data.controls.empty())
				Write(&data.controls[0], data.controls.size());
			Write(data.hand ? 1 : 0)->Write((unsigned long)data.fingers.size(), 4);
			for (auto &finger : data.fingers) {
				Write(finger.matrix._m, 16);
				Write(finger.lengths, 3);
				Write(finger.angles, 2);
				Write(&finger.radius, 1);
			}
			Send(false);
		}
		void VEHICLE_SIMULATION_DATA(SCENE_ID sceneID, const VehicleSimulationData &data) {
			// $$ only serialize messages with controllerID == 0 to prevent high TCP traffic
			if (data.controllerID == 0) {
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_VEHICLE_SIMULATION_DATA Write"));
			#endif
				// TODO: deserialization of this message!

				Write(SDT_VEHICLE_SIMULATION_DATA);

				Write(dataTarget->ConvertSID(sceneID), 4);
				Write(data.vehicleID, sizeof(int));
				Write(data.controllerID, sizeof(int));

				float speed = 3.6f*data.GetSpeed();
				Write(&speed, 1);
				Write(&data.engineRPM, 1);
				Write(&data.engineTorque, 1);
				Write(data.gear, sizeof(int));

				Write(data.velocity._v, 3);
				Write(data.position._v, 3);
				Write(data.orientation._v, 3);
				Write(data.angularVelocity._v, 3);

				Write(&data.distance, 1);

				Write((char *)data.wheelContactInfo, 4 * sizeof(int));
				Write((char *)data.virtualWheelContactInfo, 4 * sizeof(int));

				Write(&data.wheel, 1);
				Write(&data.gas, 1);
				Write(&data.brake, 1);

				Write((char *)data.wheelSlipInfo, 4 * sizeof(int));

				Write((char *)&data.buttons, sizeof(int));
				Write((char *)data.virtualWheelPosition, 4 * 3 * sizeof(float));
				Write((char *)data.wheelPosition, 4 * 3 * sizeof(float));
				Send();
			}
		}
	//#if LUKAS_RUZICKA_DEBUG
		void ESTABLISH_CONNECTION(const std::vector<int> & ports, const std::vector<wxString> & addresses) {
			if (ports.size() != addresses.size()) {
				LOGERROR(wxT("VRUTSerializer::ESTABLISH_CONNECTION(...) vectors have different sizes!"));
				return;
			}
			if (ports.size() == 0) {
				return;
			}
			unsigned long size = ports.size();
			Write(STD_ESTABLISH_CONNECTION)->Write((char*)&size, sizeof(size));
			for (long long i = 0; i < size; ++i) {
				auto port = ports[i];//int
				auto address = addresses[i];//wxString
				Write((char*)&port, sizeof(port))->Write(address.utf8_str());
			}
		}
	//#endif
		void TRAFFIC_INFO_DATA(SCENE_ID sceneID, const TrafficInfoData &data) {
		#if USE_EXTRA_LOGGING
			LOG(wxT("SDT_TRAFFIC_INFO_DATA Write"));
		#endif
			//			LOG(wxString::Format(wxT("Serializing traffic info data")));

			// TODO: deserialization of this message!
			Write(SDT_TRAFFIC_INFO_DATA);

			Write(dataTarget->ConvertSID(sceneID), 4);

			// sending of the data starts here
			Write((char *)&data, sizeof(TrafficInfoData));
		}
	#if LUKAS_RUZICKA_DEBUG2
		void NETWORK_TOPOLOGY(const Network & network) {
			Write(SDT_NETWORK_TOPOLOGY);
			unsigned long size = (unsigned long)network.vertices.size();
			Write(size, sizeof(size));
			for (auto & node : network.vertices) {
				Write(node.role); //considers it as a char
				Write(node.name.utf8_str());
				Write((char*)&node.port, sizeof(node.port));
				Write(node.id, sizeof(node.id));
				unsigned long amountOfNeighbors = (unsigned long)node.neighbors.size();
				Write(amountOfNeighbors, sizeof(amountOfNeighbors));
				for (auto & neighbor : node.neighbors)
					Write(neighbor, sizeof(neighbor));
			}
			Send(); //flush to proper buffer
		}
		void CONNECTION_INFORMATION(const unsigned long predecessorId, const unsigned long successorId, const unsigned long connectionCounter, const bool serial = false) {
			Write(SDT_CONNECTION_INFORMATION);
			Write(predecessorId, sizeof(predecessorId));
			Write(successorId, sizeof(successorId));
			Write(connectionCounter, sizeof(connectionCounter));
			char s = serial ? '1' : '0';
			Write(s);
			Send();
		}
	#endif
	};

	template <typename DataSource> class VRUTDeSerializer {
	private:
		VRUTDeCompressor decompressor;
		DataSource *dataSource;
		wxCriticalSection cs;
		VRUTDeSerializer * ReadBinData(char * data, size_t size) {
			wxCriticalSectionLocker csl(cs);
			if (decompressor.GetCompressionLevel() > 0)
				decompressor.Read((void*)data, size);
			else
				dataSource->ReadBinData(data, size);
			return this;
		}
		VRUTDeSerializer * ReadULong(unsigned long * value, const size_t bytes) {
			*value = 0;
			for (size_t i = 0; i< bytes; i++) {
				char c = ReadChar();
				*value = *value + ((unsigned long)((unsigned char)c) << (i * 8));
			}
			return this;
		}
		VRUTDeSerializer * ReadVector(float * values, int num) {
			ReadBinData((char*)values, sizeof(float) * num);
			return this;
		}
		VRUTDeSerializer * ReadWxString(wxString & string) {
			std::string res;
			char c;
			while ((c = ReadChar()) != 0)
				res += c;
			string = wxString::FromUTF8(res.c_str());
			return this;
		}
		char ReadChar(void) {
			char c;
			ReadBinData(&c, 1);
			return c;
		}
		unsigned char ReadUnsignedChar(void) {
			unsigned char c;
			ReadBinData((char *)&c, 1);
			return c;
		}
		VRUTDeSerializer * Receive() {
			wxCriticalSectionLocker csl(this->cs);
			assert(sizeof(int) == 4);
			// packet = comrpessedSize, uncompressedSize, compressedData => read compressed size:
			int size = 0;
			this->dataSource->ReadBinData((char*)&size, sizeof(int));
			size_t compressedSize = (size_t)size;
			this->decompressor.Resize(compressedSize);
			// read uncompressedSize:
			size = 0;
			this->dataSource->ReadBinData((char*)&size, sizeof(int));
			this->decompressor.SetUncompressedSize(size);
			// read compressedData:
			this->dataSource->ReadBinData((char*)this->decompressor.GetData(), compressedSize);
			return this;
		}
	public:
		VRUTDeSerializer(DataSource *dataSource) : dataSource(dataSource) {
			this->decompressor.SetCompressionLevel(0);
		}
		~VRUTDeSerializer() {
		}
		char ReadItem() {
			if (this->decompressor.GetCompressionLevel() > 0) {
				while (!this->decompressor.CanReadCompressedStream()) {
					this->decompressor.PartialReset();
					//decompressor.Reset();
					this->Receive();
				}
			}
			char c = ReadChar();

			switch (c) {
			case SDT_SCENE_NODE_INSERT:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_SCENE_NODE_INSERT Read"));
			#endif
				unsigned long sceneID = ReadChar();
				unsigned long nodeType = ReadChar();
				unsigned long nodeID;
				ReadULong(&nodeID, 4);
				unsigned long parentID;
				ReadULong(&parentID, 4);
				unsigned long active = ReadChar();
				wxString nodeName;
				ReadWxString(nodeName);
				SceneNode *node = NULL;
				switch (nodeType) {
				case SceneNode::FILE_ROOT:
					node = new SceneNode(nodeName, SceneNode::SCENENODE_TYPE(nodeType));
					break;
				case SceneNode::ASSEMBLY:
					node = new SceneNode(nodeName, SceneNode::SCENENODE_TYPE(nodeType));
					break;
				case SceneNode::GEOMETRY:
					node = new GeometryNode(nodeName);
					break;
				case SceneNode::CAMERA:
					node = new Camera(nodeName);
					break;
				case SceneNode::LIGHT:
					node = new LightNode(nodeName);
					break;
				case SceneNode::LOD:
					node = new LODNode(nodeName);
					break;
				case SceneNode::SWITCH:
					node = new SwitchNode(nodeName);
					break;
				case SceneNode::BACKGROUND:
					node = new BackgroundNode(nodeName);
					break;
				case SceneNode::SOUND_SOURCE:
					node = new SoundSourceNode(nodeName);
					break;
				default:
					LOGERROR(wxString::Format(wxT("<VRUTDeSerializer>Parse unknown node type %lu"), nodeType));
				}
				if (!node)
					break;
				node->SetActive(active == 1);
				node->SetID(dataSource->ConvertID(nodeID));
				dataSource->PostToKernel(GET_EVT_SCENE_NODE_INSERT(dataSource->ConvertSID(sceneID), node, dataSource->ConvertID(parentID)));
				//dataSource->scene->Insert(node, dataSource->ConvertID(parentID));
				break;
			}
			case SDT_SCENE_NODE_TRANSFORM_SET:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_SCENE_NODE_TRANSFORM_SET Read"));
			#endif
				unsigned long sceneID = ReadChar();
				unsigned long nodeID;
				ReadULong(&nodeID, 4);
				Matrix localTransform;
				ReadVector(localTransform._m, 16);
				dataSource->PostToKernel(GET_EVT_SCENE_NODE_TRANSFORM_SET(dataSource->ConvertSID(sceneID), dataSource->ConvertID(nodeID), localTransform));
				break;
			}
			case SDT_SCENE_GEOMETRY_TRIANGLES_ADD:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_SCENE_GEOMETRY_TRIANGLES_ADD Read"));
			#endif
			#if 1
				unsigned long sceneID = ReadChar();
				unsigned long geometryID;
				ReadULong(&geometryID, 4);
			#if USE_EXTRA_LOGGING
				LOG(wxString::Format(wxT("SDT_SCENE_GEOMETRY_TRIANGLES_ADD Read gid=%i"), geometryID));
			#endif
				GeometryTriangles *geoTri = new GeometryTriangles(dataSource->ConvertGID(geometryID));
				unsigned long vertsNum;
				ReadULong(&vertsNum, 4);
			#if USE_EXTRA_LOGGING
				LOG(wxString::Format(wxT("SDT_SCENE_GEOMETRY_TRIANGLES_ADD Read vertsNum=%lu"), vertsNum));
			#endif
				unsigned int bytesPerInd = 1 + ((vertsNum>256) ? 1 : 0) + ((vertsNum>65536) ? 1 : 0) + ((vertsNum>16777216) ? 1 : 0);
				if (vertsNum>0) {
					geoTri->vertices.resize(vertsNum);
					ReadBinData((char *)&geoTri->vertices[0]._v, 3 * sizeof(float)*vertsNum);
				}
				unsigned long normsNum;
				ReadULong(&normsNum, 4);
			#if USE_EXTRA_LOGGING
				LOG(wxString::Format(wxT("SDT_SCENE_GEOMETRY_TRIANGLES_ADD Read normsNum=%lu"), normsNum));
			#endif
				if (normsNum>0) {
					geoTri->normals.resize(normsNum);
					ReadBinData((char *)&geoTri->normals[0]._v, 3 * sizeof(float)*normsNum);
				}
				unsigned long texCNum;
				ReadULong(&texCNum, 4);
			#if USE_EXTRA_LOGGING
				LOG(wxString::Format(wxT("SDT_SCENE_GEOMETRY_TRIANGLES_ADD Read texCNum=%lu"), texCNum));
			#endif
				if (texCNum>0) {
					geoTri->texCoords.resize(texCNum);
					ReadBinData((char *)&geoTri->texCoords[0]._v, 2 * sizeof(float)*texCNum);
				}
				unsigned long indsNum;
				ReadULong(&indsNum, 4);
			#if USE_EXTRA_LOGGING
				LOG(wxString::Format(wxT("SDT_SCENE_GEOMETRY_TRIANGLES_ADD Read indsNum=%lu"), indsNum));
			#endif
				int bytesPerTri = 1 + ((indsNum>256) ? 1 : 0) + ((indsNum>65536) ? 1 : 0) + ((indsNum>16777216) ? 1 : 0);
				{
					geoTri->indices.resize(indsNum);
					unsigned char *buffer = new unsigned char[indsNum*bytesPerInd];
					ReadBinData((char *)buffer, indsNum*bytesPerInd);
					unsigned char *pos = buffer;
					switch (bytesPerInd) {
					case 1:
						for (size_t j = 0; j < indsNum; ++j)
							geoTri->indices[j] = *(pos++);
						break;
					case 2:
						for (size_t j = 0; j < indsNum; ++j, pos += 2)
							geoTri->indices[j] = *pos + ((unsigned int)*(pos + 1) << 8);
						break;
					case 3:
						for (size_t j = 0; j < indsNum; ++j, pos += 3)
							geoTri->indices[j] = *pos + ((unsigned int)*(pos + 1) << 8) + ((unsigned int)*(pos + 2) << 16);
						break;
					case 4:
						for (size_t j = 0; j < indsNum; ++j, pos += 4)
							geoTri->indices[j] = *pos + ((unsigned int)*(pos + 1) << 8) + ((unsigned int)*(pos + 2) << 16) + ((unsigned int)*(pos + 3) << 24);
						break;
					default:
						for (size_t j = 0; j < indsNum; ++j) {
							unsigned int ind = 0;
							for (unsigned int i = 0; i<bytesPerInd; ++i)
								ind += ((unsigned int)(*(pos++)) << (i * 8));
							geoTri->indices[j] = ind;
						}
						break;
					}
					delete[] buffer;
				}
				unsigned long triDNum;
				ReadULong(&triDNum, 4);
			#if USE_EXTRA_LOGGING
				LOG(wxString::Format(wxT("SDT_SCENE_GEOMETRY_TRIANGLES_ADD Read triDNum=%lu"), triDNum));
			#endif
				unsigned char * buffer = new unsigned char[triDNum * (bytesPerTri + 1)];
				unsigned char *pos = buffer;
				ReadBinData((char*)buffer, triDNum * (bytesPerTri + 1));
				geoTri->triDescList.resize(triDNum);
				for (auto &triDesc : geoTri->triDescList) {
					GeometryTriangles::Index index;
					index = *pos++;
					if (bytesPerTri >= 2)
						index += ((unsigned int)*pos++ << 8);
					if (bytesPerTri >= 3)
						index += ((unsigned int)*pos++ << 16);
					if (bytesPerTri >= 4)
						index += ((unsigned int)*pos++ << 24);
					triDesc.first = index;
					triDesc.second = (GeometryTriangles::PRIMITIVE_TYPE)*pos++;
				}
				delete[] buffer;
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_SCENE_GEOMETRY_TRIANGLES_ADD Read end"));
			#endif
			#else
				unsigned long sceneID = ReadChar();
				unsigned long geometryID;
				ReadULong(&geometryID, 4);
				GeometryTriangles *geoTri = new GeometryTriangles(geometryID);
				unsigned long vertsNum;
				ReadULong(&vertsNum, 4);
				int bytesPerInd = 1 + ((vertsNum>256) ? 1 : 0) + ((vertsNum>65536) ? 1 : 0) + ((vertsNum>16777216) ? 1 : 0);
				geoTri->vertices.reserve(vertsNum);
				unsigned long normsNum;
				ReadULong(&normsNum, 4);
				geoTri->normals.reserve(normsNum);
				unsigned long texCNum;
				ReadULong(&texCNum, 4);
				geoTri->texCoords.reserve(texCNum);
				unsigned long indsNum;
				ReadULong(&indsNum, 4);
				int bytesPerTri = 1 + ((indsNum>256) ? 1 : 0) + ((indsNum>65536) ? 1 : 0) + ((indsNum>16777216) ? 1 : 0);
				geoTri->indices.reserve(indsNum);
				unsigned long triDNum;
				ReadULong(&triDNum, 4);
				geoTri->triDescList.reserve(triDNum);
				unsigned long zlibLenght;
				ReadULong(&zlibLenght, 4);
				char *zlibBuf = new char[zlibLenght];
				ReadBinData(zlibBuf, zlibLenght);
				wxMemoryInputStream mis(zlibBuf, zlibLenght);
				wxZlibInputStream zis(mis, 0);
				for (; vertsNum>0; vertsNum--) {
					Vector3 vert;
					zis.Read(vert._v, 3 * 4);
					geoTri->vertices.push_back(vert);
				}
				for (; normsNum>0; normsNum--) {
					Vector3 norm;
					zis.Read(norm._v, 3 * 4);
					geoTri->normals.push_back(norm);
				}
				for (; texCNum>0; texCNum--) {
					GeometryTriangles::TexCoord texC;
					zis.Read(texC._v, 2 * 4);
					geoTri->texCoords.push_back(texC);
				}
				unsigned char tmp[4] = {0,0,0,0};
				for (; indsNum>0; indsNum--) {
					zis.Read(tmp, bytesPerInd);
					geoTri->indices.push_back(tmp[0] + (tmp[1] << 8) + (tmp[2] << 16) + (tmp[3] << 24));
				}
				for (; triDNum>0; triDNum--) {
					unsigned long ind;
					zis.Read(tmp, bytesPerTri);
					ind = tmp[0] + (tmp[1] << 8) + (tmp[2] << 16) + (tmp[3] << 24);
					zis.Read(tmp, 1);
					std::pair<GeometryTriangles::Index, GeometryTriangles::PRIMITIVE_TYPE> indType((GeometryTriangles::Index)ind, (GeometryTriangles::PRIMITIVE_TYPE)tmp[0]);
					geoTri->triDescList.push_back(indType);
				}
				delete[] zlibBuf;
			#endif
				dataSource->PostToKernel(GET_EVT_SCENE_GEOMETRY_ADD(dataSource->ConvertSID(sceneID), geoTri));
				//dataSource->scene->AddGeometry(geoTri);
				break;
			}
			case SDT_SCENE_GEOMETRY_ADD:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_SCENE_GEOMETRY_ADD Read"));
			#endif
				unsigned long sceneID = ReadChar();
				unsigned long geometryID;
				ReadULong(&geometryID, 4);
				unsigned long type = ReadChar();
				switch (type) {
				case Geometry::GEOMETRY_TEXT:
				{
					GeometryText *geoText = new GeometryText(dataSource->ConvertGID(geometryID));
					wxString text;
					ReadWxString(text);
					geoText->SetText(text);
					float sizeSpacing[2];
					ReadBinData((char *)&sizeSpacing, 2 * sizeof(float));
					geoText->SetSize(sizeSpacing[0]);
					geoText->SetSpacing(sizeSpacing[1]);
					geoText->SetMajorJustify((GeometryText::Justify)ReadChar());
					geoText->SetMinorJustify((GeometryText::Justify)ReadChar());
					geoText->SetFontFamily(ReadChar());
					ReadWxString(text);
					geoText->SetFontName(text);
					geoText->SetFontStyle(ReadChar());
					dataSource->PostToKernel(GET_EVT_SCENE_GEOMETRY_ADD(dataSource->ConvertSID(sceneID), geoText));
					//dataSource->scene->AddGeometry(geoText);
					break;
				}
				default:
					LOGERROR(wxString::Format(wxT("<VRUTSerializer>SDT_SCENE_GEOMETRY_ADD: unsupported geometry type %i"), type));
					break;
				}
				break;
			}
			case SDT_SCENE_VARIANT_ADD:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_SCENE_VARIANT_ADD Read"));
			#endif
				unsigned long sceneID = ReadChar();
				unsigned long varID;
				ReadULong(&varID, 4);
				wxString name;
				ReadWxString(name);
				unsigned long type = ReadChar();
				Variant *var = NULL;
				switch (type) {
				case Variant::VARIANT_GEOMETRY:
					var = new VariantGeometry(dataSource->ConvertVID(varID), name);
					break;
				case Variant::VARIANT_MATERIAL:
					var = new VariantMaterial(dataSource->ConvertVID(varID), name);
					break;
				case Variant::VARIANT_SET:
					var = new VariantSet(dataSource->ConvertVID(varID), name);
					break;
				case Variant::VARIANT_CAMERA:
					var = new VariantCamera(dataSource->ConvertVID(varID), name);
					break;
				default:
					LOGERROR(wxString::Format(wxT("<VRUTDeSerializer>SDT_SCENE_VARIANT_ADD: unsupported variant type %i"), type));
					break;
				}
				unsigned long statesCount;
				ReadULong(&statesCount, 4);
				wxString stateName;
				for (unsigned long i = 0; i < statesCount; ++i) {
					ReadWxString(stateName);
					var->AddState(stateName);
				}
				unsigned long activeState;
				ReadULong(&activeState, 4);
				var->activeState = activeState;
				switch (type) {
				case Variant::VARIANT_GEOMETRY:
				{
					VariantGeometry *varG = (VariantGeometry *)var;
					unsigned long nodesCount;
					ReadULong(&nodesCount, 4);
					for (unsigned long i = 0; i < nodesCount; ++i) {
						unsigned long nodeID;
						ReadULong(&nodeID, 4);
						varG->AddNode(dataSource->ConvertID(nodeID));
					}
					for (unsigned long i = 0; i < statesCount; ++i)
						for (unsigned long j = 0; j < nodesCount; ++j)
							varG->SetStateNodeStatus(i, varG->nodesList[j], ReadChar() == 1);
					break;
				}
				case Variant::VARIANT_MATERIAL:
					//nothing extra is necessary
					break;
				case Variant::VARIANT_SET:
				{
					VariantSet *varS = (VariantSet *)var;
					unsigned long detailsCount;
					ReadULong(&detailsCount, 4);
					for (unsigned long i = 0; i < detailsCount; ++i) {
						char detailsType = ReadChar();
						unsigned long detail;
						ReadULong(&detail, 4);
						switch (detailsType) {
						case VariantSet::VARIANT_SET_DETAIL_VARIANT:
							varS->AddVariant(dataSource->ConvertVID(detail));
							break;
						case VariantSet::VARIANT_SET_DETAIL_SWITCH:
							varS->AddSwitch(dataSource->ConvertID(detail));
							break;
						case VariantSet::VARIANT_SET_DETAIL_SCRIPT:
							varS->AddScript(detail);
							break;
						default:
							LOGERROR(wxString::Format(wxT("<VRUTDeSerializer>SCENE_VARIANT_ADD: unsupported VariantSet::VariantSetDetailType %i"), varS->detailsTypes[i]));
							break;
						}
					}
					for (unsigned long i = 0; i < statesCount; ++i) {
						unsigned long keyCode, modifiers;
						ReadULong(&keyCode, 4);
						ReadULong(&modifiers, 4);
						varS->SetStateShortCut(i, ShortCut(modifiers, keyCode));
					}
					for (unsigned long i = 0; i < statesCount; ++i)
						for (unsigned long j = 0; j < detailsCount; ++j)
							ReadWxString(varS->stateDetailsTable[i][j]);
					break;
				}
				case Variant::VARIANT_CAMERA:
				{
					if (statesCount>0) {
						VariantCamera *varC = (VariantCamera *)var;
						varC->transformations.resize(statesCount);
						ReadBinData((char *)&varC->transformations[0]._m, 16 * sizeof(float)*statesCount);
						varC->FOVs.resize(statesCount);
						ReadBinData((char *)&varC->FOVs[0], sizeof(float)*statesCount);
					}
					break;
				}
				default:
					LOGERROR(wxString::Format(wxT("<VRUTDeSerializer>SDT_SCENE_VARIANT_ADD: unsupported variant type %i"), type));
					break;
				}

				dataSource->PostToKernel(GET_EVT_SCENE_VARIANT_ADD(dataSource->ConvertSID(sceneID), var));
				//dataSource->scene->SetGeometry(dataSource->ConvertID(nodeID), dataSource->ConvertGID(geometryID));
				break;
			}
			case SDT_SCENE_NODE_SOUND_SET:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_SCENE_NODE_SOUND_SET Read"));
			#endif
				unsigned long sceneID = ReadChar();
				unsigned long nodeID;
				ReadULong(&nodeID, 4);
				float gain;
				ReadVector(&gain, 1);
				bool looping = (ReadChar() != 0);
				SoundSourceNode::SoundSourceState state = (SoundSourceNode::SoundSourceState)ReadChar();
				float minGain, maxGain, referenceDistance, rollOffFactor, maxDistance, pitch;
				ReadVector(&minGain, 1);
				ReadVector(&maxGain, 1);
				ReadVector(&referenceDistance, 1);
				ReadVector(&rollOffFactor, 1);
				ReadVector(&maxDistance, 1);
				ReadVector(&pitch, 1);
				Vector3 direction;
				ReadVector(direction._v, 3);
				float coneInnerAngle, coneOuterAngle, coneOuterGain, secOffset;
				ReadVector(&coneInnerAngle, 1);
				ReadVector(&coneOuterAngle, 1);
				ReadVector(&coneOuterGain, 1);
				ReadVector(&secOffset, 1);
				wxString soundDataSource;
				ReadWxString(soundDataSource);
				dataSource->PostToKernel(GET_EVT_SCENE_NODE_SOUND_SET(dataSource->ConvertSID(sceneID), dataSource->ConvertID(nodeID), gain, looping, state, minGain, maxGain,
					referenceDistance, rollOffFactor, maxDistance, pitch, direction, coneInnerAngle, coneOuterAngle, coneOuterGain, secOffset, soundDataSource));
				break;
			}
			case SDT_SCENE_NODE_GEOMETRY_SET:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_SCENE_NODE_GEOMETRY_SET Read"));
			#endif
				unsigned long sceneID = ReadChar();
				unsigned long nodeID;
				ReadULong(&nodeID, 4);
				unsigned long geometryID;
				ReadULong(&geometryID, 4);
				dataSource->PostToKernel(GET_EVT_SCENE_NODE_GEOMETRY_SET(dataSource->ConvertSID(sceneID), dataSource->ConvertID(nodeID), dataSource->ConvertGID(geometryID)));
				//dataSource->scene->SetGeometry(dataSource->ConvertID(nodeID), dataSource->ConvertGID(geometryID));
				break;
			}
			case SDT_SCENE_MATERIAL_ADD:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_SCENE_MATERIAL_ADD Read"));
			#endif
				unsigned long sceneID = ReadChar();
				wxString matName;
				ReadWxString(matName);
				Material *material = new Material(matName);
				ReadVector(material->ambient._v, 4)->ReadVector(material->diffuse._v, 4)->ReadVector(material->specular._v, 4);
				ReadVector(material->emission._v, 4)->ReadVector(&material->shininess, 1)->ReadVector(&material->reflectivity, 1);

				unsigned long tmpULong;
				ReadULong(&tmpULong, 4)->ReadVector(&material->textureMix, 1);
				material->depthFunc = tmpULong;
				ReadULong(&tmpULong, 4);
				material->flags = tmpULong;
				ReadULong(&tmpULong, 4)->ReadWxString(material->imageName);
				if (!material->imageName.empty()) {
					material->imageName = dataSource->ConvertFileName(material->imageName, true);
				}
				material->texFlags = tmpULong;

				ReadULong(&tmpULong, 4);
				material->blendSrc = tmpULong;
				ReadULong(&tmpULong, 4);
				material->blendDst = tmpULong;

				char type = ReadChar();
				if (type != ShaderProgram::LANG_NONE) {
					//has shader
					material->shader = new ShaderProgram();
					material->shader->type = (ShaderProgram::SHADER_LANGUAGE)type;
					switch (type) {
					case ShaderProgram::LANG_GLSL:
						ReadWxString(material->shader->fsSource)->ReadWxString(material->shader->fsFileName);
						ReadWxString(material->shader->vsSource)->ReadWxString(material->shader->vsFileName);
						material->shader->fsFileName = dataSource->ConvertFileName(material->shader->fsFileName, false);
						material->shader->vsFileName = dataSource->ConvertFileName(material->shader->vsFileName, false);
						break;
					case ShaderProgram::LANG_CGFX:
						ReadWxString(material->shader->vsSource)->ReadWxString(material->shader->vsFileName);
						material->shader->vsFileName = dataSource->ConvertFileName(material->shader->vsFileName, false);
						break;
					case ShaderProgram::LANG_OPENRT:
						break;
					}
				}
				char shaderParamsCount = ReadChar();
				if ((shaderParamsCount>0) && !material->shader)
					material->shader = new ShaderProgram();
				for (; shaderParamsCount>0; shaderParamsCount--) {
					ShaderParam param;
					ReadWxString(param.name);
					param.type = (ShaderParam::PARAM_TYPE)ReadChar();
					switch (param.type) {
					case ShaderParam::BOOL:
						param.iVal = ReadChar();
						break;
					case ShaderParam::INT:
						unsigned long iVal;
						ReadULong(&iVal, 4);
						param.iVal = iVal;
						break;
					case ShaderParam::FLOAT1:
						ReadVector(param.fVals, 1);
						break;
					case ShaderParam::FLOAT2:
						ReadVector(param.fVals, 2);
						break;
					case ShaderParam::FLOAT3:
						ReadVector(param.fVals, 3);
						break;
					case ShaderParam::FLOAT4:
						ReadVector(param.fVals, 4);
						break;
					case ShaderParam::SAMPLER:
					case ShaderParam::SAMPLERCUBE:
					case ShaderParam::SAMPLER3D:
						ReadWxString(param.imageName);
						if (!param.imageName.empty()) {
							param.imageName = dataSource->ConvertFileName(param.imageName, true);
						}
						break;
					}
					material->shader->paramList.push_back(param);
				}
				dataSource->PostToKernel(GET_EVT_SCENE_MATERIAL_ADD(dataSource->ConvertSID(sceneID), material));
				break;
			}
			case SDT_SCENE_NODE_MATERIAL_SET:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_SCENE_NODE_MATERIAL_SET Read"));
			#endif
				unsigned long sceneID = ReadChar();
				unsigned long nodeID;
				ReadULong(&nodeID, 4);
				wxString materialName;
				ReadWxString(materialName);
				dataSource->PostToKernel(GET_EVT_SCENE_NODE_MATERIAL_SET(dataSource->ConvertSID(sceneID), dataSource->ConvertID(nodeID), materialName));
				//dataSource->scene->SetMaterial(dataSource->ConvertID(nodeID), dataSource->scene->GetMaterialID(materialName));
				break;
			}
			case SDT_SCENE_NODE_SWITCH_ACTIVECHILD_SET:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_SCENE_NODE_SWITCH_ACTIVECHILD_SET Read"));
			#endif
				unsigned long sceneID = ReadChar();
				unsigned long nodeID, activeChild;
				ReadULong(&nodeID, 4);
				ReadULong(&activeChild, 4);
				size_t activeChild1 = (size_t)activeChild;
				if (activeChild == (unsigned long)-1)
					activeChild1 = (size_t)-1;
				if (activeChild == (unsigned long)-2)
					activeChild1 = (size_t)-2;
				dataSource->PostToKernel(GET_EVT_SCENE_NODE_SWITCH_ACTIVECHILD_SET(dataSource->ConvertSID(sceneID), dataSource->ConvertID(nodeID), activeChild1));
				break;
			}
			case SDT_SCENE_NODE_LIGHT_SET:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_SCENE_NODE_LIGHT_SET Read"));
			#endif
				unsigned long sceneID = ReadChar();
				unsigned long nodeID;
				ReadULong(&nodeID, 4);
				Light light;
				light.type = (Light::LIGHT_TYPE)ReadChar();
				ReadVector(&light.angle, 1)->ReadVector(&light.exponent, 1)->ReadVector(light.diffuse._v, 4)->ReadVector(light.attenuation._v, 3);
				ReadVector(&light.diffuse.w, 1)->ReadWxString(light.ies);
				dataSource->PostToKernel(GET_EVT_SCENE_NODE_LIGHT_SET(dataSource->ConvertSID(sceneID), dataSource->ConvertID(nodeID), light));
				break;
			}
			case SDT_SCENE_NODE_LOD_DISTANCE_SET:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_SCENE_NODE_LOD_DISTANCE_SET Read"));
			#endif
				unsigned long sceneID = ReadChar();
				unsigned long parentID, nodeID;
				float distance;
				ReadULong(&parentID, 4)->ReadULong(&nodeID, 4)->ReadVector(&distance, 1);
				dataSource->PostToKernel(GET_EVT_SCENE_NODE_LOD_DISTANCE_SET(dataSource->ConvertSID(sceneID), dataSource->ConvertID(parentID), dataSource->ConvertID(nodeID), distance));
				break;
			}
			case SDT_IMAGE_ADD:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_IMAGE_ADD Read"));
			#endif
				wxString imageName, cubeSideName;
				ReadWxString(imageName);
				if (imageName == wxFileName(imageName).GetFullName())
					imageName = dataSource->ConvertFileName(imageName, false);
				bool cube = ReadChar() != 0;
				int cubeSide = (int)ReadChar();
				if (cubeSide != -1)
					ReadWxString(cubeSideName);
				else
					cubeSideName = imageName;
				unsigned long imageType = ReadChar();
				switch (imageType) {
				case 0://WXIMAGE
				{
					unsigned long height, width;
					ReadULong(&height, 2)->ReadULong(&width, 2);
					unsigned char *data = (unsigned char*)malloc(height*width * 3);
					ReadBinData((char*)data, height*width * 3);
					wxImage *wximage = new wxImage(width, height, data);
					unsigned long hasAlpha = ReadChar();
					if (hasAlpha == 1) {
						unsigned char *alpha = (unsigned char*)malloc(height*width);
						ReadBinData((char*)alpha, height*width);
						wximage->SetAlpha(alpha);
					}
					ImageCommon *imcommon = new ImageCommon(NULL, cube);
					imcommon->SetImage(wximage, cubeSide);
					delete wximage;
					if (imcommon->IsOk())
						dataSource->PostToKernel(GET_EVT_SCENE_IMAGE_ADD(cubeSideName, imcommon, cubeSide, imageName));
					break;
				}
				case 1://DDSIMAGE
				{
					ImageDDS tmpdds;
					unsigned char *header = (unsigned char*)malloc(sizeof(tmpdds.GetImage().header));
					ReadBinData((char*)header, sizeof(tmpdds.GetImage().header));
					unsigned long dataSize;
					ReadULong(&dataSize, 4);
					unsigned char *data = (unsigned char*)malloc(dataSize);
					ReadBinData((char*)data, dataSize);
					ImageDDS *imDDS = new ImageDDS((ImageDDS::DDS_header*)header, dataSize, data, cube);
					free(header);
					free(data);
					if (imDDS->IsOk())
						dataSource->PostToKernel(GET_EVT_SCENE_IMAGE_ADD(cubeSideName, imDDS, cubeSide, imageName));
					break;
				}
				case 2://raw file WXIMAGE
				{
					unsigned long fileSize;
					ReadULong(&fileSize, 4);
					unsigned char *data = (unsigned char*)malloc(fileSize);
					ReadBinData((char*)data, fileSize);
					wxMemoryInputStream memInputStream(data, fileSize);
					wxImage *wximage = new wxImage(wxImage(memInputStream).Mirror(false));
					ImageCommon *imcommon = new ImageCommon(NULL);
					imcommon->SetImage(wximage, cubeSide);
					delete wximage;
					if (imcommon->IsOk())
						dataSource->PostToKernel(GET_EVT_SCENE_IMAGE_ADD(cubeSideName, imcommon, cubeSide, imageName));
					free(data);
					break;
				}
				case 3://HDRIMAGE as file
				{
					unsigned long fileSize;
					ReadULong(&fileSize, 4);
					char *data = (char*)malloc(fileSize);
					ReadBinData(data, fileSize);
					ImageHDR *image = new ImageHDR(data, fileSize);
					if (image->IsOk())
						dataSource->PostToKernel(GET_EVT_SCENE_IMAGE_ADD(cubeSideName, image, cubeSide, imageName));
					free(data);
					break;
				}
				case 4://UNKNOWN
					break;
				}
				break;
			}
			case SDT_INTERPRETER_PROCESS_COMMANDS:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_INTERPRETER_PROCESS_COMMANDS Read"));
			#endif
				wxString commands;
				ReadWxString(commands);
				dataSource->PostToKernel(GET_EVT_INTERPRETER_PROCESS_COMMANDS(commands));
				break;
			}
			case SDT_REGISTER_EVENT_LISTENER:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_REGISTER_EVENT_LISTENER Read"));
			#endif
				Event::EVENT_TYPE eventType = (Event::EVENT_TYPE)ReadUnsignedChar();
				bool transformed = (ReadChar() == 1);
				dataSource->RegisterConnectionEventListener(eventType, transformed);
				break;
			}
			case SDT_INPUT_TRACKING:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_INPUT_TRACKING Read"));
			#endif
				DeviceData data;
				ReadBinData((char *)&data.id, 4);
				ReadBinData((char *)&data.type, 4);
				ReadVector(&data.quality, 1);
				ReadVector(data.matrix._m, 16);
				ReadBinData((char*)&data.buttons, 4);

				unsigned long numControls;
				ReadULong(&numControls, 4);
				data.controls.resize(numControls, 0.0f);
				for (unsigned long i = 0; i < numControls; ++i)
					ReadVector(&data.controls[i], 1);

				data.hand = (ReadChar() != 0);

				unsigned long numFingers;
				ReadULong(&numFingers, 4);
				if (numFingers) {
					data.fingers.resize(numFingers);
					for (auto &finger : data.fingers) {
						ReadVector(finger.matrix._m, 16);
						ReadVector(finger.lengths, 3);
						ReadVector(finger.angles, 2);
						ReadVector(&finger.radius, 1);
					}
				}
				dataSource->PostToKernel(GET_EVT_INPUT_TRACKING(data));
				break;
			}
			case SDT_AR_HUD_DATA:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_AR_HUD_DATA Read"));
			#endif
				ArHudData data;
				ReadBinData((char *)&data, sizeof(ArHudData));
				dataSource->PostToKernel(GET_EVT_AR_HUD_DATA(data));
				break;
			}
			case SDT_EXIT:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_EXIT Read"));
			#endif
				dataSource->PostToKernel(GET_EVT_EXIT());
				//exit(0);
				break;
			}
			case SDT_SCENE_ADD:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_SCENE_ADD Read"));
			#endif
				unsigned long sceneID = ReadChar();
				wxString sceneName;
				ReadWxString(sceneName);
				dataSource->PostToKernel(GET_EVT_SCENE_ADD(sceneName, sceneID));
				break;
			}
			case SDT_SCENE_MATERIAL_REMOVE:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_SCENE_MATERIAL_REMOVE Read"));
			#endif
				unsigned long sceneID = ReadChar();
				wxString materialName;
				ReadWxString(materialName);
				dataSource->PostToKernel(GET_EVT_SCENE_MATERIAL_REMOVE(sceneID, materialName));
				break;
			}
			case SDT_SCENE_GEOMETRY_REMOVE:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_SCENE_GEOMETRY_REMOVE Read"));
			#endif
				unsigned long sceneID = ReadChar();
				unsigned long geometryID;
				ReadULong(&geometryID, 4);
				dataSource->PostToKernel(GET_EVT_SCENE_GEOMETRY_REMOVE(sceneID, geometryID));
				break;
			}
			case SDT_SCENE_NODE_MOVE:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_SCENE_NODE_MOVE Read"));
			#endif
				unsigned long sceneID = ReadChar();
				unsigned long nodeID;
				ReadULong(&nodeID, 4);
				unsigned long parentID;
				ReadULong(&parentID, 4);
				dataSource->PostToKernel(GET_EVT_SCENE_NODE_MOVE(sceneID, nodeID, parentID));
				LOGDEBUG(wxString::Format(wxT("<Cluster>Node moved ID=%lu, Parent=%lu"), nodeID, parentID));
				break;
			}
			case SDT_SCENE_NODE_INDEX_CHANGE:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_SCENE_NODE_INDEX_CHANGE Read"));
			#endif
				unsigned long sceneID = ReadChar();
				unsigned long nodeID;
				ReadULong(&nodeID, 4);
				unsigned long newIndex;
				ReadULong(&newIndex, 4);
				dataSource->PostToKernel(GET_EVT_SCENE_NODE_INDEX_CHANGE(sceneID, nodeID, newIndex));
				LOGDEBUG(wxString::Format(wxT("<Cluster>Node replaced ID=%lu, newIndex=%lu"), nodeID, newIndex));
				break;
			}
			case SDT_SCENE_NODE_REMOVE:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_SCENE_NODE_REMOVE Read"));
			#endif
				unsigned long sceneID = ReadChar();
				unsigned long nodeID;
				ReadULong(&nodeID, 4);
				dataSource->PostToKernel(GET_EVT_SCENE_NODE_REMOVE(sceneID, nodeID));
				LOGDEBUG(wxString::Format(wxT("<Cluster>Remove node nodeID=%lu"), nodeID));
				break;
			}
			case SDT_SCENE_NODE_NAME_SET:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_SCENE_NODE_NAME_SET Read"));
			#endif
				unsigned long sceneID = ReadChar();
				unsigned long nodeID;
				ReadULong(&nodeID, 4);
				wxString nodeName;
				ReadWxString(nodeName);
				dataSource->PostToKernel(GET_EVT_SCENE_NODE_NAME_SET(sceneID, nodeID, nodeName));
				LOGDEBUG(wxString::Format(wxT("<Cluster>Set node name nodeID=%lu"), nodeID));
				break;
			}
			case SDT_SCENE_NODE_ACTIVE_SET:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_SCENE_NODE_ACTIVE_SET Read"));
			#endif
				unsigned long sceneID = ReadChar();
				unsigned long nodeID;
				ReadULong(&nodeID, 4);
				bool active = (ReadChar() != 0);
				dataSource->PostToKernel(GET_EVT_SCENE_NODE_ACTIVE_SET(sceneID, nodeID, active));
				break;
			}
			case SDT_SCENE_CAM_PROJECTION_SET:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_SCENE_CAM_PROJECTION_SET Read"));
			#endif
				unsigned long sceneID = ReadChar();
				unsigned long cameraID;
				float nearPlane, farPlane, FOV;
				ReadULong(&cameraID, 4)->ReadVector(&nearPlane, 1)->ReadVector(&farPlane, 1)->ReadVector(&FOV, 1);
				unsigned long lastWidth, lastHeight;
				ReadULong(&lastWidth, 4)->ReadULong(&lastHeight, 4);
				Camera::UP_FIX upFix = (Camera::UP_FIX)ReadChar();
				dataSource->PostToKernel(GET_EVT_SCENE_CAM_PROJECTION_SET(sceneID, cameraID, (unsigned int)lastWidth, (unsigned int)lastHeight, nearPlane, farPlane, FOV, upFix));
				Camera::PROJECTION_TYPE projectionType = (Camera::PROJECTION_TYPE)ReadChar();
				if (projectionType == Camera::PERSPECTIVE_GENERIC) {
					Vector3 offset;
					ReadVector(offset._v, 3);
					Camera::EYE_TYPE eye = (Camera::EYE_TYPE)ReadChar();
					float eyeSeparation;
					Vector3 pa, pb, pc, eyeAxis, lookAt;
					ReadVector(&eyeSeparation, 1)->ReadVector(pa._v, 3)->ReadVector(pb._v, 3)->ReadVector(pc._v, 3)->ReadVector(eyeAxis._v, 3)->ReadVector(lookAt._v, 3);
					dataSource->PostToKernel(GET_EVT_SCENE_CAM_SET_PERSPECTIVE_PARAMS(sceneID, cameraID, nearPlane, farPlane, offset, eye, eyeSeparation, pa, pb, pc, eyeAxis, lookAt));
					//LOG(wxString::Format(wxT("<ClusterParser::EVT_SCENE_CAM_PROJECTION_SET>camID=%lu, vWidth=%f, vHeight=%f, near=%f, far=%f, FOV=%f, lastWidth=%i, lastHeight=%i, projType=%i, eye=%i, eyeSeparation=%f, upFix=%i"),
					//	(unsigned long)cameraID, vWidth, vHeight, nearPlane, farPlane, FOV, lastWidth, lastHeight, projectionType, eye, eyeSeparation, upFix));
				}
				//else
				//	LOG(wxString::Format(wxT("<ClusterParser::EVT_SCENE_CAM_PROJECTION_SET>camID=%lu, near=%f, far=%f, FOV=%f, lastWidth=%i, lastHeight=%i, projType=%i,upFix=%i"),
				//		(unsigned long)cameraID, nearPlane, farPlane, FOV, lastWidth, lastHeight, projectionType, upFix));
				break;
			}
			case SDT_SCENE_ENVIRONMENT_PROBE_ADD:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_SCENE_ENVIRONMENT_PROBE_ADD Read"));
			#endif
				unsigned long sceneID;
				ReadULong(&sceneID, 4);
				unsigned long epID;
				ReadULong(&epID, 4);
				unsigned long attachedNodeID;
				ReadULong(&attachedNodeID, 4);
				float nearPlaneDistance;
				ReadVector(&nearPlaneDistance, 1);
				float farPlaneDistance;
				ReadVector(&farPlaneDistance, 1);
				unsigned long textureDimension;
				ReadULong(&textureDimension, 4);
				bool enabled = (ReadChar() == 1) ? true : false;
				bool singleShot = (ReadChar() == 1) ? true : false;
				EnvironmentProbe *ep = new EnvironmentProbe(epID, attachedNodeID, nearPlaneDistance, farPlaneDistance, textureDimension, enabled, singleShot);
				dataSource->PostToKernel(GET_EVT_SCENE_ENVIRONMENT_PROBE_ADD(sceneID, ep));
				break;
			}
			case SDT_SCENE_ENVIRONMENT_PROBE_ENABLE:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_SCENE_ENVIRONMENT_PROBE_ENABLE Read"));
			#endif
				unsigned long sceneID;
				ReadULong(&sceneID, 4);
				unsigned long epID;
				ReadULong(&epID, 4);
				bool enable = (ReadChar() == 1);
				dataSource->PostToKernel(GET_EVT_SCENE_ENVIRONMENT_PROBE_ENABLE(sceneID, epID, enable));
				break;
			}
			case SDT_SCENE_ENVIRONMENT_PROBE_SET_SINGLE_SHOT:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_SCENE_ENVIRONMENT_PROBE_SET_SINGLE_SHOT Read"));
			#endif
				unsigned long sceneID;
				ReadULong(&sceneID, 4);
				unsigned long epID;
				ReadULong(&epID, 4);
				bool singleShot = (ReadChar() == 1);
				dataSource->PostToKernel(GET_EVT_SCENE_ENVIRONMENT_PROBE_SET_SINGLE_SHOT(sceneID, epID, singleShot));
				break;
			}
			case SDT_SCENE_CLIPPING_PLANE_ADD:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_SCENE_CLIPPING_PLANE_ADD Read"));
			#endif
				ClippingPlane clippingPlane;
				unsigned long sceneID = ReadChar();
				unsigned long cpidl;
				ReadULong(&cpidl, 4);
				clippingPlane.cpid = cpidl;
				ReadVector(clippingPlane.plane._v, 4);
				clippingPlane.enabled = (ReadChar() == 1);
				dataSource->PostToKernel(GET_EVT_SCENE_CLIPPING_PLANE_ADD(sceneID, clippingPlane));
				break;
			}
			case SDT_RENDER_SCENE:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_RENDER_SCENE Read"));
			#endif
				unsigned long sceneID = ReadChar();
				unsigned long cameraID;
				ReadULong(&cameraID, 4);
				unsigned long windowID;
				ReadULong(&windowID, sizeof(RENDER_WINDOW_ID));
				unsigned long activeStereo = ReadChar();
				wxString nodeName;
				ReadWxString(nodeName);
				if (nodeName.Lower() != wxGetHostName().Lower())
					return c;

				//standard way how to render on clients
				dataSource->PostToKernel(GET_EVT_RENDER_SCENE(sceneID, cameraID, windowID, activeStereo != 0));
				break;
			}
			case SDT_RENDER_FULLSCREEN_SET:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_RENDER_FULLSCREEN_SET Read"));
			#endif
				unsigned long windowID;
				ReadULong(&windowID, sizeof(RENDER_WINDOW_ID));
				unsigned long fsMode = ReadChar();
				unsigned long positionX, positionY, sizeX, sizeY, colorRGB;
				ReadULong(&positionX, 4)->ReadULong(&positionY, 4)->ReadULong(&sizeX, 4)->ReadULong(&sizeY, 4)->ReadULong(&colorRGB, 4);
				wxString nodeName;
				ReadWxString(nodeName);
				if (nodeName.Lower() != wxGetHostName().Lower())
					return c;
				dataSource->PostToKernel(GET_EVT_RENDER_FULLSCREEN_SET(RENDER_WINDOW_ID(windowID), fsMode, positionX, positionY, sizeX, sizeY, colorRGB));
				//LOGDEBUG(wxString::Format(wxT("<ClusterParser>Set fullscreen windowID %lu, fsMode %lu, position (%lu, %lu), size (%lu, %lu), color %lu"), windowID, fsMode, positionX, positionY, sizeX, sizeY, colorRGB));
				break;
			}
			case SDT_RENDER_WIN_FOCUS:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_RENDER_WIN_FOCUS Read"));
			#endif
				unsigned long windowID;
				ReadULong(&windowID, sizeof(RENDER_WINDOW_ID));
				dataSource->PostToKernel(GET_EVT_RENDER_WIN_FOCUS(RENDER_WINDOW_ID(windowID)));
				break;
			}
			case SDT_RENDER_WIN_CLOSE:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_RENDER_WIN_CLOSE Read"));
			#endif
				unsigned long windowID;
				ReadULong(&windowID, sizeof(RENDER_WINDOW_ID));
				dataSource->PostToKernel(GET_EVT_RENDER_WIN_CLOSE(RENDER_WINDOW_ID(windowID)));
				break;
			}
			case SDT_RENDER_UPDATE:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_RENDER_UPDATE Read"));
			#endif
				unsigned long windowID;
				ReadULong(&windowID, sizeof(RENDER_WINDOW_ID));
				unsigned long renderState;
				ReadULong(&renderState, 4);
				dataSource->PostToKernel(GET_EVT_RENDER_UPDATE((RENDER_WINDOW_ID)windowID, (int)renderState));////TODO: Remove the sign when using rayTracer with Cluster2 for remote tile rendering

			#ifdef SYNC_DEBUG
				LOG(wxString::Format(wxT("<ClusterParser>Received EVT_RENDER_UPDATE (windowID=%lu, renderState=%i)"), windowID, -(int)renderState));
			#endif
				break;
			}
			case SDT_RENDER_SYNCHRONIZATION_REGISTER:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_RENDER_SYNCHRONIZATION_REGISTER Read"));
			#endif
				unsigned long windowID;
				ReadULong(&windowID, sizeof(RENDER_WINDOW_ID));
				unsigned long masterWindowID;
				ReadULong(&masterWindowID, sizeof(RENDER_WINDOW_ID));
				dataSource->PostToKernel(GET_EVT_RENDER_SYNCHRONIZATION_REGISTER((RENDER_WINDOW_ID)windowID, (RENDER_WINDOW_ID)masterWindowID)/*, true*/);
			#ifdef SYNC_DEBUG
				LOG(wxString::Format(wxT("<Cluster>client called synchronization register (windowID=%i, masterWindowID=%i)"), (int)windowID, (int)masterWindowID));
			#endif
				break;
			}
			case SDT_RENDER_SYNCHRONIZATION_UNREGISTER:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_RENDER_SYNCHRONIZATION_UNREGISTER Read"));
			#endif
				unsigned long windowID;
				ReadULong(&windowID, sizeof(RENDER_WINDOW_ID));
				dataSource->PostToKernel(GET_EVT_RENDER_SYNCHRONIZATION_UNREGISTER((RENDER_WINDOW_ID)windowID), true);
				break;
			}
			case SDT_RENDER_SYNCHRONIZATION_FINISHED_RENDERING:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_RENDER_SYNCHRONIZATION_FINISHED_RENDERING Read"));
			#endif
				unsigned long windowID;
				ReadULong(&windowID, sizeof(RENDER_WINDOW_ID));
				unsigned long renderState;
				ReadULong(&renderState, 4);
				dataSource->PostToKernel(GET_EVT_RENDER_SYNCHRONIZATION_FINISHED_RENDERING((RENDER_WINDOW_ID)windowID, renderState), true);
				break;
			}
			case SDT_RENDER_SYNCHRONIZATION_BARRIER_RELEASE:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_RENDER_SYNCHRONIZATION_BARRIER_RELEASE Read"));
			#endif
				unsigned long windowID;
				ReadULong(&windowID, sizeof(RENDER_WINDOW_ID));
				unsigned long renderState;
				ReadULong(&renderState, 4);
			#ifdef SYNC_DEBUG
				LOG(wxString::Format(wxT("<ClusterParser>EVT_RENDER_SYNCHRONIZATION_BARRIER_RELEASE renderState=%i"), (int)renderState));
			#endif
				dataSource->PostToKernel(GET_EVT_RENDER_SYNCHRONIZATION_BARRIER_RELEASE((RENDER_WINDOW_ID)windowID, (int)renderState), true);
				break;
			}
			case SDT_RENDER_TILE:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_RENDER_TILE Read"));
			#endif
				unsigned long cameraId;
				RenderTileData tileData;
				unsigned long tmpULong;

			#if LUKAS_RUZICKA_DEBUG
				tileData.time = VRUTGetTime();
				unsigned long long tmpULL;
				ReadBinData((char*)&tmpULL, sizeof(unsigned long long));
				tileData.totalTime = tmpULL;
			#endif

				unsigned long sceneId = ReadChar();
				ReadULong(&cameraId, 4);
				ReadULong(&tmpULong, 4);
				tileData.frameId = tmpULong;
				ReadULong(&tmpULong, 4);
				tileData.tileIndex = tmpULong;
				ReadULong(&tmpULong, 2);
				tileData.LOD = tmpULong;
				ReadULong(&tmpULong, 2);
				tileData.skip = tmpULong;
				ReadULong(&tmpULong, 4);
				tileData.cameraIndex = tmpULong;
				ReadULong(&tmpULong, 1);
				tileData.antialiasing = tmpULong != 0;
				ReadULong(&tmpULong, 4);
				tileData.minVal.x = tmpULong;
				ReadULong(&tmpULong, 4);
				tileData.minVal.y = tmpULong;
				ReadULong(&tmpULong, 4);
				tileData.maxVal.x = tmpULong;
				ReadULong(&tmpULong, 4);
				tileData.maxVal.y = tmpULong;
				ReadULong(&tmpULong, 2);
				tileData.imageWidth = tmpULong;
				ReadULong(&tmpULong, 2);
				tileData.imageHeight = tmpULong;
				ReadULong(&tmpULong, 4);
				tileData.workerId = tmpULong;
				ReadULong(&tmpULong, 4);
				tileData.samples = tmpULong;
				ReadULong(&tmpULong, 4);
				tileData.numPixels = tmpULong;

			#if LUKAS_RUZICKA_DEBUG
				LOG(wxString::Format(wxT("LUKAS_RUZICKA_DEBUG 3, %i, %i, %i, -1, -1"), tileData.frameId, tileData.tileIndex, tileData.LOD));
			#endif

				dataSource->PostToKernel(GET_EVT_RENDER_TILE(dataSource->ConvertSID(sceneId), dataSource->ConvertID(cameraId), tileData));
				break;
			}
			case SDT_RENDER_TILE_DONE:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_RENDER_TILE_DONE Read"));
			#endif
				static const int MAX_TILE_SIZE = 64 * 64;
				unsigned long cameraId;
				RenderTileData tileData;
				unsigned long tmpULong;

			#if LUKAS_RUZICKA_DEBUG
				tileData.time = VRUTGetTime();
				unsigned long long tmpULL;
				ReadBinData((char*)&tmpULL, sizeof(unsigned long long));
				tileData.totalTime = tmpULL;
			#endif

				unsigned long sceneId = ReadChar();
				ReadULong(&cameraId, 4);
				ReadULong(&tmpULong, 4);
				tileData.frameId = tmpULong;
				ReadULong(&tmpULong, 4);
				tileData.tileIndex = tmpULong;
				ReadULong(&tmpULong, 2);
				tileData.LOD = tmpULong;
				ReadULong(&tmpULong, 2);
				tileData.skip = tmpULong;
				ReadULong(&tmpULong, 4);
				tileData.cameraIndex = tmpULong;
				ReadULong(&tmpULong, 1);
				tileData.antialiasing = tmpULong != 0;
				ReadULong(&tmpULong, 4);
				tileData.minVal.x = tmpULong;
				ReadULong(&tmpULong, 4);
				tileData.minVal.y = tmpULong;
				ReadULong(&tmpULong, 4);
				tileData.maxVal.x = tmpULong;
				ReadULong(&tmpULong, 4);
				tileData.maxVal.y = tmpULong;
				ReadULong(&tmpULong, 2);
				tileData.imageWidth = tmpULong;
				ReadULong(&tmpULong, 2);
				tileData.imageHeight = tmpULong;
				ReadULong(&tmpULong, 4);
				tileData.workerId = tmpULong;
				ReadULong(&tmpULong, 4);
				tileData.samples = tmpULong;
				ReadULong(&tmpULong, 4);
				tileData.numPixels = tmpULong;
				if (tileData.numPixels > 0) {
					if (tileData.numPixels < MAX_TILE_SIZE) {
						// read pixels
						tileData.pixels = std::shared_ptr<Vector4>(new Vector4[tileData.numPixels], std::default_delete<Vector4[]>());
					#if USE_HALF_PRECISION
						Vector4Float16 v;
						for (int i = 0; i < tileData.numPixels; ++i) {
							ReadBinData((char*)&v, sizeof(Vector4Float16));
							tileData.pixels.get()[i].x = float16to32(v.x);
							tileData.pixels.get()[i].y = float16to32(v.y);
							tileData.pixels.get()[i].z = float16to32(v.z);
							tileData.pixels.get()[i].w = float16to32(v.w);
						}
					#else
						ReadBinData((char*)tileData.pixels.get(), sizeof(Vector4) * tileData.numPixels);
					#endif
					} else {
						LOG(wxString::Format(wxT("<Cluster> Wrong number of pixels received! %i"), tileData.numPixels));
						// clear the TCP buffer?
						break;
					}
				}

			#if LUKAS_RUZICKA_DEBUG
				LOG(wxString::Format(wxT("LUKAS_RUZICKA_DEBUG 8, %i, %i, %i, -1, -1"), tileData.frameId, tileData.tileIndex, tileData.LOD));
			#endif

				dataSource->PostToKernel(GET_EVT_RENDER_TILE_DONE(dataSource->ConvertSID(sceneId), dataSource->ConvertID(cameraId), tileData));
				dataSource->NotifyAboutRenderTileDone(tileData);
				break;
			}
			case SDT_RENDER_TILE_DONE_SYNC:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_RENDER_TILE_DONE_SYNC Read"));
			#endif
				static const int MAX_TILE_SIZE = 64 * 64;
				unsigned long cameraId;
				std::shared_ptr<RenderTileData> tileData = std::make_shared<RenderTileData>();
				unsigned long tmpULong;

			#if LUKAS_RUZICKA_DEBUG
				tileData->time = VRUTGetTime();
				unsigned long long tmpULL;
				ReadBinData((char*)&tmpULL, sizeof(unsigned long long));
				tileData->totalTime = tmpULL;
			#endif

				unsigned long sceneId = ReadChar();
				ReadULong(&cameraId, 4);
				ReadULong(&tmpULong, 4);
				tileData->frameId = tmpULong;
				ReadULong(&tmpULong, 4);
				tileData->tileIndex = tmpULong;
				ReadULong(&tmpULong, 2);
				tileData->LOD = tmpULong;
				ReadULong(&tmpULong, 2);
				tileData->skip = tmpULong;
				ReadULong(&tmpULong, 4);
				tileData->cameraIndex = tmpULong;
				ReadULong(&tmpULong, 1);
				tileData->antialiasing = tmpULong != 0;
				ReadULong(&tmpULong, 4);
				tileData->minVal.x = tmpULong;
				ReadULong(&tmpULong, 4);
				tileData->minVal.y = tmpULong;
				ReadULong(&tmpULong, 4);
				tileData->maxVal.x = tmpULong;
				ReadULong(&tmpULong, 4);
				tileData->maxVal.y = tmpULong;
				ReadULong(&tmpULong, 2);
				tileData->imageWidth = tmpULong;
				ReadULong(&tmpULong, 2);
				tileData->imageHeight = tmpULong;
				ReadULong(&tmpULong, 4);
				tileData->workerId = tmpULong;
				ReadULong(&tmpULong, 4);
				tileData->samples = tmpULong;
				ReadULong(&tmpULong, 4);
				tileData->numPixels = tmpULong;
				if (tileData->numPixels > 0) {
					if (tileData->numPixels < MAX_TILE_SIZE) {
						// read pixels
						tileData->pixels = std::shared_ptr<Vector4>(new Vector4[tileData->numPixels], std::default_delete<Vector4[]>());
					#if USE_HALF_PRECISION
						Vector4Float16 v;
						for (int i = 0; i < tileData->numPixels; ++i) {
							ReadBinData((char*)&v, sizeof(Vector4Float16));
							tileData->pixels.get()[i].x = float16to32(v.x);
							tileData->pixels.get()[i].y = float16to32(v.y);
							tileData->pixels.get()[i].z = float16to32(v.z);
							tileData->pixels.get()[i].w = float16to32(v.w);
						}
					#else
						ReadBinData((char*)tileData->pixels.get(), sizeof(Vector4) * tileData->numPixels);
					#endif
					} else {
						LOG(wxString::Format(wxT("<Cluster> Wrong number of pixels received! %i"), tileData->numPixels));
						// clear the TCP buffer?
						break;
					}
				}
				// TODO lvorisek Tohle trochu komplikuje zpracovani prijatych udalosti na urovni modulu

			#if LUKAS_RUZICKA_DEBUG
				LOG(wxString::Format(wxT("LUKAS_RUZICKA_DEBUG 9, %i, %i, %i, -1, -1"), tileData->frameId, tileData->tileIndex, tileData->LOD));
			#endif

				EventRenderTileDoneSync syncEventData(dataSource->ConvertSID(sceneId), dataSource->ConvertID(cameraId), tileData);
				dataSource->NotifyAboutRenderTileDone(*tileData);
				for (auto &mid : KERNEL->GetMessageSink()->moduleListeners[Event::EVT_RENDER_TILE_DONE_SYNC]) {
					Module * module = KERNEL->GetModule(mid);
					if (module) {
						switch (module->processSyncEvent(Event::EVT_RENDER_TILE_DONE_SYNC, (void*)&syncEventData)) {
						case Module::Allowed:
							// Nothing changed, try the next module
							break;
						case Module::Changed:
							// Not resolved yet, so it tries the next module
							break;
						case Module::Denied:
							// Transformation is not allowed at all
							return false;
						}
					}
				}
				break;
			}
			case SDT_COMPRESSION_LEVEL_SET:
			{
			#if USE_EXTRA_LOGGING
				LOG(wxT("SDT_COMPRESSION_LEVEL_SET Read"));
			#endif
				unsigned char newCompressionLevel = (unsigned char)ReadChar();
				LOG(wxString::Format(wxT("VRUTDeSerializer::ReadItem() ... SDT_COMPRESSION_LEVEL_SET from %i to %i"), this->decompressor.GetCompressionLevel(), newCompressionLevel));
				decompressor.SetCompressionLevel(newCompressionLevel);
				break;
			}
		//#if LUKAS_RUZICKA_DEBUG
			case STD_ESTABLISH_CONNECTION:
			{
				std::vector<int> ports;
				std::vector<wxString> addresses;
				unsigned long size;
				ReadULong((unsigned long*)&size, sizeof(size));
				if (size <= 0) {
					LOGERROR(wxT("VRUTDeSerializer::ReadItem() case STD_ESTABLISH_CONNECTION : size <= 0"));
					break;
				}
				ports.reserve(size);
				addresses.reserve(size);
				int port;
				wxString address;
				for (long long i = 0; i < size; ++i) {
					ReadULong((unsigned long*)&port, sizeof(port));
					ports.push_back(port);
					ReadWxString(address);
					addresses.push_back(address);
				}
				if (size > 0) {
					if (size > 1)
						LOG(wxString::Format(wxT("Got request to directly connect to port = %i, address = "), ports[1]) + addresses[1]);
					LOG(wxT("VRUTDeSerializer::ReadItem() case STD_ESTABLISH_CONNECTION : addresses and ports in vector :"));
					for (long long i = 0; i < size; ++i) {
						LOG(wxString::Format(wxT("port = %i"), ports[i]) + wxT(", address = ") + addresses[i]);
					}
				} else {
					LOGERROR(wxT("VRUTDeSerializer::ReadItem() case STD_ESTABLISH_CONNECTION : empty message!"));
					break;
				}
				dataSource->EstablishConnectionWith(ports, addresses);
				break;
			}
		//#endif

		#if LUKAS_RUZICKA_DEBUG2
			case SDT_NETWORK_TOPOLOGY:
			{
				unsigned long size;
				std::vector<Node> vertices;
				Node node;
				ReadULong(&size, sizeof(size));
				vertices.reserve(size);
				for (size_t i = 0; i < size; ++ i) {
					node.role = (Node::Role)ReadChar();
					ReadWxString(node.name);
					ReadBinData((char*)&node.port, sizeof(node.port));
					ReadULong(&node.id, sizeof(node.id));
					unsigned long amountOfNeighbors;
					ReadULong(&amountOfNeighbors, sizeof(amountOfNeighbors));
					node.neighbors.reserve(amountOfNeighbors);
					for (size_t neighbor = 0; neighbor < amountOfNeighbors; ++ neighbor) {
						unsigned long tmpNeighbor;
						ReadULong(&tmpNeighbor, sizeof(tmpNeighbor));
						node.neighbors.push_back(tmpNeighbor);
					}
					vertices.push_back(node);
					node.neighbors.clear();
				}
				//inform cluster2::connection ...
				dataSource->NetworkTopologyReceived(vertices);
				break;
			}
			case SDT_CONNECTION_INFORMATION:
			{
				unsigned long predecessorId;
				ReadULong(&predecessorId, sizeof(predecessorId));
				unsigned long successorId;
				ReadULong(&successorId, sizeof(successorId));
				unsigned long connectionCounter;
				ReadULong(&connectionCounter, sizeof(connectionCounter));
				char s;
				s = ReadChar();
				bool serial;
				if (s == '1') {
					serial = true;
				} else if (s == '0') {
					serial = false;
				} else {
					LOGERROR(wxT("VRUTDeSerializer::ReadItem() case SDT_CONNECTION_INFORMATION : critical error - invalid value in place of 'serial'"));
				}
				//TODO : inform cluster2::connection ...
				dataSource->ConnectionInformationReceived(predecessorId, successorId, connectionCounter, serial);
				break;
			}
		#endif

			default: // bad hit
			{
				LOGERROR(wxString::Format(wxT("<VRUTDeSerializer> Unexpected data block type: %i (%c)"), c, c));
				//return c;
				return SDT_CONNECTION_ERROR;
			}
			}
			return c;
		}
	};
}
#endif
