#include "bob_dom_bob.h"
//---------------------------------------------------------------------------------
// BOB file
bool bob_dom_bob::load(bob_dom_ibinaryfilestream& is)
{
	int hdr;	
	is >> hdr;
	if(hdr!=hdr_begin){
		error(e_badHeader);
		return false;
	}
	
	if(peek(is)==bob_dom_info::hdr_begin){
		if(!info.load(is)){
			for(ErrorIterator &it=info.errors.begin(); it!=info.errors.end(); ++it){
				error(it->code, "info: %s", it->text);
			}
			return false;
		}
	}
	
	if(materials.load(is)==false){
		for(ErrorIterator &it=materials.errors.begin(); it!=materials.errors.end(); ++it){
			error(it->code, "materials->%s", it->text);
			return false;
		}
	}
	/*switch(m_settings->X3BOB()){
		case Settings::SwitchValue::on:
			bobType=bobX3;
			break;
		case Settings::SwitchValue::off:
			bobType=bobX2;
			break;
		default:
			if(materials.size() && materials.front()->type >= bob_dom_material::mat6)
				bobType=bobX3;
			else
				bobType=bobX2;
	}*/
	if(bodies.load(is)==false){
		for(ErrorIterator &it=bodies.errors.begin(); it!=bodies.errors.end(); ++it){
			error(it->code, "bodies->%s", it->text);
		}
		return false;
	}
	
	is >> hdr;
	if(hdr!=hdr_end)
		error(e_badEndHeader);
		
	return(hdr==hdr_end && !is.fail());
}
//---------------------------------------------------------------------------------
bool bob_dom_bob::toFile(bob_dom_obinaryfilestream& os)
{
	os << hdr_begin;
	info.toFile(os);
	materials.toFile(os);
	bodies.toFile(os);
	os << hdr_end;
	return os.good();
}
//---------------------------------------------------------------------------------
bool bob_dom_bob::toFile(bob_dom_otextfilestream& os)
{
	info.toFile(os);
	os << endl;
	materials.toFile(os);
	if(materials.size())
		os << endl;
	bodies.toFile(os, m_settings, &materials);
	return os.good();
}
//---------------------------------------------------------------------------------
// MATERIAL  - object
bool bob_dom_material1::load(bob_dom_ibinaryfilestream& is)
{
	is >> index;
	is >> textureID; // int?
	is >> ambient;
	is >> diffuse;
	is >> specular;
	
	errorCode=is.fail() ? e_notEnoughData : e_noError;
	
	return !is.fail();
}
//---------------------------------------------------------------------------------
bool bob_dom_material1::toFile(bob_dom_obinaryfilestream& os)
{
	os << index << textureID << ambient << diffuse << specular;
	
	return os.good();
}
//---------------------------------------------------------------------------------
bool bob_dom_material1::toFile(bob_dom_otextfilestream& os)
{
	os << noSemicolons << "MATERIAL";
	switch(type){
		case mat3:
			os << '3';
			break;
		case mat5:
			os << '5';
			break;
	}
	os << ": " << autoSemicolons;
	os << index << textureID;
	os << ambient << diffuse << specular;
	
	return os.good();
}
//---------------------------------------------------------------------------------
// MATERIAL 3 - object
bool bob_dom_material3::load(bob_dom_ibinaryfilestream& is)
{
	base::load(is);
	if(type > mat1){
		is >> transparency; // int?
		is >> selfIllumination;
		is >> shininess;
		short s;
		is >> s;
		destinationBlend = (s & 0x2) > 0;
		twoSided = (s & 0x10) > 0;
		wireframe = (s & 0x8) > 0;
		is >> textureValue;
		is >> enviromentMap;
		is >> bumpMap;
	}
	errorCode=is.fail() ? e_notEnoughData : e_noError;
	
	return !is.fail();
}
//---------------------------------------------------------------------------------
bool bob_dom_material3::toFile(bob_dom_obinaryfilestream& os)
{
	base::toFile(os);
	os << transparency << selfIllumination << shininess;
	short s=0;
	if(destinationBlend) s|=0x2;
	if(twoSided) s|=0x10;
	if(wireframe) s|=0x8;
	os << s;
	os << textureValue << enviromentMap << bumpMap;
	
	return os.good();
}
//---------------------------------------------------------------------------------
bool bob_dom_material3::toFile(bob_dom_otextfilestream& os)
{
	base::toFile(os);
	os << autoSemicolons;
	os << transparency << selfIllumination << shininess;
	os << noSemicolons << destinationBlend << ';' << twoSided << ';' << autoSemicolons << wireframe;
	os << textureValue;
	os << enviromentMap << bumpMap;
	return os.good();
}
//---------------------------------------------------------------------------------
// MATERIAL5
bool bob_dom_material5::load(bob_dom_ibinaryfilestream& is)
{
	base::load(is);
	if(type > mat3)
		is >> lightMap;
	
	errorCode=is.fail() ? e_notEnoughData : e_noError;
	
	return !is.fail();
}
//---------------------------------------------------------------------------------
bool bob_dom_material5::toFile(bob_dom_obinaryfilestream& os)
{
	base::toFile(os);
	os << lightMap;
	return os.good();
}
//---------------------------------------------------------------------------------
bool bob_dom_material5::toFile(bob_dom_otextfilestream& os)
{
	base::toFile(os);
	if(type > mat3)
		os << autoSemicolons << lightMap;
	return os.good();
}
//---------------------------------------------------------------------------------
char * material6_value::m_stringTypes[]={
	"SPTYPE_LONG",
	"SPTYPE_BOOL",
	"SPTYPE_FLOAT",
	"",
	"",
	"SPTYPE_FLOAT4",
	"",
	"",
	"SPTYPE_STRING"
};

int material6_value::m_stringTypesCount=9;

bob_error_codes material6_value::load(bob_dom_ibinaryfilestream &is)
{
	is >> name;
	if(is.fail()) return e_error;
	short t;
	is >> t;
	type=(Type)t;
	
	switch(type){
		case typeBool: // no break
		case typeLong:
			is >> val.i;
			break;
		case typeFloat:
			is >> val.f;
			break;
		case typeFloat4:
			is >> val.f4;
			break;
		case typeString:
			is >> val.psz;
			break;
		default:	
			return e_unkMaterialValueType;
	}
	return is.fail() ? e_error : e_noError;
}
//---------------------------------------------------------------------------------
bool material6_value::toFile(bob_dom_obinaryfilestream& os)
{
	os << name << (short) type;
	
	switch(type){
		case typeBool: // no break
		case typeLong:
			os << val.i;
			break;
		case typeFloat:
			os << val.f;
			break;
		case typeFloat4:
			os << val.f4;
			break;
		case typeString:
			os << val.psz;
			break;
		default:	
			return false;
	}
	return os.good();
}
//---------------------------------------------------------------------------------
bool material6_value::toFile(bob_dom_otextfilestream& os)
{
	int old=os.flags();
	os << noSemicolons << name << ';';
	
	os << typeName() << ';';
	
	switch(type){
		case typeLong:
			os << val.i << ';';
			break;
		case typeBool:
			os << val.i << ';';
			break;
		case typeFloat:
			os << val.f << ';';
			break;
		case typeFloat4:
			for(int i=0; i < 4; i++){
				os << val.f4.f[i] << ';';
			}
			break;
		case typeString:
			os << val.psz << ';';
			break;
		default:
			return false;
	}
	os << ' ';
	os.flags(old);
	return os.good();
}
//---------------------------------------------------------------------------------
// MATERIAL6_VALUES
bob_error_codes bob_dom_material6_values::load(bob_dom_ibinaryfilestream& is)
{
	short count;
	material6_value *v;
	
	bob_error_codes res;
	
	is >> count;
	for(int i=0; i < count; i++){
		v=new material6_value();
		if((res=v->load(is))!=e_noError) {
			delete v;
			return res;
		}
		push_back(v);
	}
	return is.fail() ? e_error : e_noError;
}
//---------------------------------------------------------------------------------
bool bob_dom_material6_values::toFile(bob_dom_obinaryfilestream& os)
{
	os << (short)size();
	for(iterator &it=begin(); it!=end(); ++it){
		it->toFile(os);
	}
	return os.good();
}
//---------------------------------------------------------------------------------
bool bob_dom_material6_values::toFile(bob_dom_otextfilestream& os)
{
	os << (int)size();
	for(iterator &it=begin(); it!=end(); ++it){
		it->toFile(os);
	}
	return os.good();
}
//---------------------------------------------------------------------------------
// MATERIAL6 - big
bob_error_codes bob_dom_material6::Big::load(bob_dom_ibinaryfilestream& is)
{
	bob_error_codes errorCode;
	
	is >> technique >> effect;
	
	errorCode=values.load(is);
	
	return errorCode;
}
//---------------------------------------------------------------------------------
bool bob_dom_material6::Big::toFile(bob_dom_obinaryfilestream& os)
{
	os << technique << effect;
	values.toFile(os);
	return os.good();
}
//---------------------------------------------------------------------------------
bool bob_dom_material6::Big::toFile(bob_dom_otextfilestream& os)
{
	int old=os.flags();
	os << autoSemicolons << technique << effect;
	values.toFile(os);
	os.flags(old);
	return os.good();
}
//---------------------------------------------------------------------------------
// MATERIAL 6 - small
bob_error_codes bob_dom_material6::Small::load(bob_dom_ibinaryfilestream& is, int flags)
{
	is >> textureFile;
	is >> ambient >> diffuse >> specular;
	is >> transparency >> selfIllumination >> shininess;
	short s=flags;
	//is >> s;
	destinationBlend = (s & 0x2) > 0;
	twoSided = (s & 0x10) > 0;
	wireframe = (s & 0x8) > 0;
	is >> textureValue >> enviromentMap >> bumpMap >> lightMap;
	is >> map4 >> map5;
	
	return !is.fail() ? e_noError : e_notEnoughData;
}
//---------------------------------------------------------------------------------
bool bob_dom_material6::Small::toFile(bob_dom_obinaryfilestream& os)
{
	static char *empty="";
	os << (textureFile ? textureFile : empty);
	os << ambient << diffuse << specular;
	os << transparency << selfIllumination << shininess;
	
	os << textureValue << enviromentMap << bumpMap << lightMap;
	os << map4 << map5;
	
	return os.good();
}
//---------------------------------------------------------------------------------
bool bob_dom_material6::Small::toFile(bob_dom_otextfilestream& os)
{
	os << (*textureFile==0 ? "NULL" : textureFile);
	os << ambient << diffuse << specular;
	os << transparency << selfIllumination << shininess;
	os << noSemicolons << destinationBlend << ';' << twoSided << ';' << autoSemicolons << wireframe;
	os << textureValue;
	os << enviromentMap << bumpMap << lightMap << map4 << map5;
	return os.good();
}
//---------------------------------------------------------------------------------
// MATERIAL 6
bool bob_dom_material6::load(bob_dom_ibinaryfilestream& is)
{
	is >> index;
	is >> flags;
	
	if(flags==Big::flag) {
		big=new Big();
		errorCode=big->load(is);
	}
	else{
		/*FILE *f=fopen("d:\\mat56.log", "a+");
		fprintf(f, "%s - flags: %d, offset 0x%x\n", is.name(), flags, is.tell());
		fclose(f);
		*/
	
		small=new Small();
		errorCode=small->load(is, flags);
	}
		
	return errorCode==e_noError;
}
//---------------------------------------------------------------------------------
bool bob_dom_material6::toFile(bob_dom_obinaryfilestream& os)
{
	bool bRes;
	
	os << index << flags;
	if(big)
		bRes=big->toFile(os);
	else
		bRes=small->toFile(os);
		
	return bRes;
}
//---------------------------------------------------------------------------------
bool bob_dom_material6::toFile(bob_dom_otextfilestream& os)
{
	int old=os.flags();
	os << noSemicolons << "MATERIAL6: " 
	<< autoSemicolons << index << noSemicolons << "0x" << hex << autoSemicolons << flags << dec;
	
	if(big) 
		big->toFile(os);
	else if(small)
		small->toFile(os);
	
	os.flags(old);
	return os.good();
}
//---------------------------------------------------------------------------------
// MATERIAL - section
bool bob_dom_materials::load(bob_dom_ibinaryfilestream& is)
{
	int hdr;
	bob_dom_material::materialType type;
	
	is >> hdr;
	switch(hdr){
		case hdr_mat5_begin:
			type=bob_dom_material::mat5;
			break;
		case hdr_mat6_begin:
			type=bob_dom_material::mat6;
			break;
		default:
			error(e_badHeader);
			return false;
	}
	
	int matCount;
	is >> matCount;

	bob_dom_material *m;
	for(int i=0; i < matCount; i++){
		switch(type) {
			case bob_dom_material::mat5:
				m=new bob_dom_material5();
				break;
			case bob_dom_material::mat6:
				m=new bob_dom_material6();
				break;
		}
		if(m->load(is)==false){
			error(m->errorCode, "material[%d]: %s", i, bob_traslate_error(m->errorCode));
			delete m;
			return false;
		}
		else
			push_back(m);
	}
	is >> hdr;
	if(hdr!=hdr_end)
		error(e_badEndHeader);
	
	return (hdr==hdr_end && !is.fail());
}
//---------------------------------------------------------------------------------
bool bob_dom_materials::toFile(bob_dom_obinaryfilestream& os)
{
	int hdr;
	if(size() && front()->type==bob_dom_material::mat6)
		hdr=hdr_mat6_begin;
	else
		hdr=hdr_mat5_begin;
		
	os << hdr << (int)size();
	for(iterator &it=begin(); it!=end(); ++it){
		it->toFile(os);
	}
	os << hdr_end;
	return os.good();
}
//---------------------------------------------------------------------------------
bool bob_dom_materials::toFile(bob_dom_otextfilestream& os)
{
	for(iterator &it=begin(); it!=end(); ++it){
		it->toFile(os);
		os << endl;
	}
	return os.good();
}
//---------------------------------------------------------------------------------
// BODIES - section
bool bob_dom_bodies::load(bob_dom_ibinaryfilestream& is)
{
	int hdr;
	is >> hdr;
	if(hdr!=hdr_begin){
		error(e_badHeader);
		return false;
	}
	short bodyCount;
	is >> bodyCount;
	
	child_type *ch;
	for(int i=0; i < bodyCount; i++){
		ch=createChild();
		if(ch->load(is)==false){
			for(ErrorIterator &it=ch->errors.begin(); it!=ch->errors.end(); ++it){
				error(it->code, "body[%d]->%s", i, it->text);
			}
			return false;
		}
	}
	
	is >> hdr;
	if(is.fail())
		error(e_notEnoughData);
		
	if(hdr!=hdr_end)
		error(e_badEndHeader);
	
	return hdr==hdr_end;
}
//---------------------------------------------------------------------------------
bool bob_dom_bodies::toFile(bob_dom_obinaryfilestream& os)
{
	os << hdr_begin << (short)size();
	for(iterator &it=begin(); it!=end(); ++it){
		it->toFile(os);
	}
	os << hdr_end;
	return os.good();
}
//---------------------------------------------------------------------------------
bool bob_dom_bodies::toFile(bob_dom_otextfilestream& os, const Settings *settings, const bob_dom_materials *materials)
{
	bool bRes=true;
	int i=1;
	os << noSemicolons << "// beginning of bodies (" << (int)size() << ')' << endl;
	for(iterator &it=begin(); it!=end(); ++it, ++i){
		bRes&=it->toFile(os, settings, materials, i);
		os << endl;
	}
	os << "// end of bodies" << endl;
	return bRes;
}
//---------------------------------------------------------------------------------
// POINTS - section
bool bob_dom_points::load(bob_dom_ibinaryfilestream& is)
{
	int hdr;
	is >> hdr;
	if(hdr!=hdr_begin){
		error(e_badHeader);
		return false;
	}
	
	int pointCount;
	is >> pointCount;
	
	map.create(pointCount);
	
	bob_dom_point *ch;
	for(int i=0; i < pointCount; i++){
		ch=new bob_dom_point();
		if(ch->load(is)==false){
			error(ch->errorCode, "point[%d]: %s", i, bob_traslate_error(ch->errorCode));
			delete ch;
			return false;
		}
		map.addPoint(ch);
		
	}
	
	//printf("AVL Points: %d, compares: %d, average comp to find pnt: %d\n", pointCount, map.map2.m_compCount, map.map2.m_compCount / pointCount);
	
	//printf("TST: Points: %d, compares: %d, average comp to find pnt: %d\n", pointCount,map.m_compCount, map.m_compCount / pointCount);
	
	is >> hdr;
	if(hdr!=hdr_end)
		error(e_badEndHeader);
		
	return hdr==hdr_end && !is.fail();
}
//---------------------------------------------------------------------------------
bool bob_dom_points::toFile(bob_dom_obinaryfilestream& os)
{
	os << hdr_begin;
	
	if(new_points.size()){
		os << (int)new_points.size();
		for(PointIterator &it=new_points.begin(); it!=new_points.end(); ++it){
			it->toFile(os);
		}
	}
	else{
		os << (int)map.pointsSize();
		for(bob_point_map::iterator &it=map.begin(); it!=map.end(); ++it){
			it->toFile(os);
		}
	}
	os << hdr_end;
	return os.good();
}
//---------------------------------------------------------------------------------
bool bob_dom_points::toFile(bob_dom_otextfilestream& os)
{
	int oldf=os.flags();
	int i=0;
	os << noSemicolons << "// beginning of points (" << (int)map.uniquePointsSize() << ')' << endl << autoSemicolons;
	
	bob_dom_point *p;
	while(p=map.nextUniquePoint()){
		p->toFile(os, i++);
	}
	os << noSemicolons << "-1; -1; -1; // points end" << endl << endl;
	
	os.flags(oldf);
	return os.good();
}
//---------------------------------------------------------------------------------
// POINT - object
double bob_dom_point::multiplier=1.52587890625; // == 100000 / 65535

bool bob_dom_point::load(bob_dom_ibinaryfilestream& is)
{
	int size, v;
	
	is >> type;
	switch(type){
		case 0x1F:
			size=11;
			break;
		case 0x1B:
			size=9;
			break;
		case 0x19:
			size=7;
			break;
		default:
			errorCode=e_unkPointHeader;
			return false;
	}
	is >> x >> y >> z;
	is >> textureCoords.left >> textureCoords.right;
	
	for(int i=5; i < size; i++){
		is >> v;
		values.push_back(v);
	}
	
	if(is.fail())
		errorCode=e_notEnoughData;
	
	return !is.fail();
}
//---------------------------------------------------------------------------------
bool bob_dom_point::toFile(bob_dom_obinaryfilestream& os)
{
	os << type << x << y << z << textureCoords.left << textureCoords.right;
	for(iterator &it=values.begin(); it!=values.end(); ++it){
		os << *it;
	}
	return os.good();
}
//---------------------------------------------------------------------------------
bool bob_dom_point::toFile(bob_dom_otextfilestream& os, int idx)
{
	// autoSemicolons is set by parent (points)
	int x,y,z;
	
	__asm{
		mov eax, this
		
		fld multiplier
		fimul [eax].x
		fistp x
		
		fld multiplier
		fimul [eax].y
		fistp y
		
		fld multiplier
		fimul [eax].z
		fistp z
	}
	os << x << y << z;
	
	os << noSemicolons << "// " << idx << endl << autoSemicolons;
	return os.good();
}
//---------------------------------------------------------------------------------
// X3 UV record
bool bob_x3uv::load(bob_dom_ibinaryfilestream& is)
{
	is >> idx;
	for(int i=0; i < 6; i++){
		is >> values[i];
	}
	return !is.fail();
}
//---------------------------------------------------------------------------------
bool bob_x3uv::toFile(bob_dom_obinaryfilestream& os)
{
	os << idx;
	for(int i=0; i < 6; i++){
		os << values[i];
	}
	return os.good();
}
//---------------------------------------------------------------------------------
bool bob_x3uv::toFile(bob_dom_otextfilestream& os, int matIdx)
{
	int old=os.flags();
	os << autoSemicolons;
	os << matIdx << idx;
	for(int i=0; i < 6; i++){
		os << values[i];
	}
	os.flags(old);
	return os.good();
}
//---------------------------------------------------------------------------------
int compare_uv(const void *a, const void *b)
{
	const bob_x3uv *uv1=*((bob_x3uv**)a), *uv2=*((bob_x3uv**)b);
	return uv1->idx - uv2->idx;
}
//---------------------------------------------------------------------------------
// X3 uv list
bool bob_x3uv_list::load(bob_dom_ibinaryfilestream& is)
{
	int count;
	bob_x3uv *uv;
	
	is >> count;
	reserve(count);
	for(int i=0; i < count; i++){
		uv=new bob_x3uv();
		if(!uv->load(is)){
			delete uv;
			return false;
		}
		push_back(uv);
	}
	sort(compare_uv);
	return !is.fail();
}
//---------------------------------------------------------------------------------
bool bob_x3uv_list::toFile(bob_dom_obinaryfilestream& os)
{
	os << (int) size();
	for(iterator &it=begin(); it!=end(); ++it){
		it->toFile(os);
	}
	return os.good();
}
//---------------------------------------------------------------------------------
bool bob_x3uv_list::toFile(bob_dom_otextfilestream& os, int matIdx)
{
	for(iterator &it=begin(); it!=end(); ++it){
		it->toFile(os, matIdx);
		os << endl;
	}
	return os.good();
}
//---------------------------------------------------------------------------------

// FACE LIST
bool bob_face_list::load(bob_dom_ibinaryfilestream& is, bool x3data)
{
	int count;
	
	is >> materialIndex >> count;
	
	for(int i=0; i < count; i++){
		bob_dom_face *face=new bob_dom_face();
		if(face->load(is)==false){
			error(face->errorCode, "face[%d]: %s", i, bob_traslate_error(face->errorCode));
			delete face;
			return false;
		}
		push_back(face);
	}
	
	if(x3data && x3uvlist.load(is)==false) return false;
	
	return !is.fail();
}
//---------------------------------------------------------------------------------
bool bob_face_list::toFile(bob_dom_obinaryfilestream& os, bool x3data)
{
	os << materialIndex << (int)size();
	for(iterator &it=begin(); it!=end(); ++it){
		it->toFile(os);
	}
	
	if(x3data)
		x3uvlist.toFile(os);
	
	return os.good();
}
//---------------------------------------------------------------------------------
// PARTS - section PART
bool bob_dom_parts::load(bob_dom_ibinaryfilestream& is)
{
	int hdr, count;
	
	is >> hdr;
	if(hdr!=hdr_begin){
		error(e_badHeader);
		return false;
	}
	
	is >> count;
	
	bob_dom_part *part;
	for(int i=0; i < count; i++){
		part=new bob_dom_part();
		if(!part->load(is)){
			for(ErrorIterator &it=part->errors.begin(); it!=part->errors.end(); ++it){
				error(it->severity, it->code, "part[%d]->%s", i, it->text);
			}
			delete part;
			return false;
		}
		push_back(part);
	}

	is >> hdr;
	if(hdr!=hdr_end)
		error(e_badEndHeader);
	
	return hdr==hdr_end && !is.fail();
}
//---------------------------------------------------------------------------------
bool bob_dom_parts::toFile(bob_dom_obinaryfilestream& os)
{
	os << hdr_begin << (int) size();
	for(iterator &it=begin(); it!=end(); ++it){
		it->toFile(os);
	}
	os << hdr_end;
	
	return os.good();
}
//---------------------------------------------------------------------------------
bool bob_dom_parts::toFile(bob_dom_otextfilestream& os, const Settings *settings, const bob_dom_materials *materials, const bob_point_map *pointMap)
{
	int i=1;
	for(iterator &it=begin(); it!=end(); ++it, ++i){
		it->toFile(os, settings, materials, pointMap, i);
	}
	return os.good();
}
//---------------------------------------------------------------------------------
bool bob_dom_part_x3vals::load(bob_dom_ibinaryfilestream& is)
{
	for(int i=0; i < 10; i++){
		is >> m_values[i];
	}
	return !is.fail();
}
//---------------------------------------------------------------------------------
bool bob_dom_part_x3vals::toFile(bob_dom_obinaryfilestream& os)
{
	for(int i=0; i < 10; i++){
		os << m_values[i];
	}
	return os.good();
}
//---------------------------------------------------------------------------------
bool bob_dom_part_x3vals::toFile(bob_dom_otextfilestream& os, bool bCommentItself)
{
	int old=os.flags();
	
	os << noSemicolons;
	if(bCommentItself)
		os << "// ";
	os << "PART_VALUES_RAW: " << autoSemicolons;
	for(int i=0; i < 10; i++){
		os << m_values[i];
	}
	
	os << endl;
	
	/*os << noSemicolons << "// raw:" << endl;
	os << "// " << autoSemicolons;
	for(int i=0; i < 10; i++){
		os << m_values[i];
	}
	os << endl << */
	os << noSemicolons << "// point:" << endl;
	os << "// " << autoSemicolons;
	for(int i=0; i < 10; i++){
		os << (int)(m_values[i] / bob_dom_point::multiplier);
	}
	
	os << endl << noSemicolons << "// float:" << endl;
	static const double multiplier=1.52587890625E-05; // 1/65535
	os << "// " << autoSemicolons;
	for(int i=0; i < 10; i++){
		os << (float)(m_values[i] * multiplier);
	}
	os << endl;
	os.flags(old);
	return os.good();
}
//---------------------------------------------------------------------------------
// PARTS - object

const double bob_dom_part::multiplier=1.52587890625E-05; // == 1 / 65636

bool bob_dom_part::load(bob_dom_ibinaryfilestream& is)
{
	short count;
	
 	is >> flags >> count;
	
	for(int i=0; i < count; i++){
		bob_face_list *faces=new bob_face_list();
		if(faces->load(is, (flags & x3flag) > 0)==false){
			for(ErrorIterator &it=faces->errors.begin(); it!=faces->errors.end(); ++it){
				error(it->severity, it->code, "face list[%d]->%s", i, it->text);
			}
			delete faces;
			return false;
		}
		push_back(faces);
	}
	
	if(flags & x3flag)
		values.load(is);

	return !is.fail();
}
//---------------------------------------------------------------------------------
bool bob_dom_part::toFile(bob_dom_obinaryfilestream& os)
{
	os << flags << (short)size();
	
	for(iterator &it=begin(); it!=end(); ++it){
		it->toFile(os, (flags & x3flag) > 0);
	}
	
	if(flags & x3flag)
		values.toFile(os);

	return os.good();
}
//---------------------------------------------------------------------------------
bool bob_dom_part::toFile(bob_dom_otextfilestream& os, const Settings *settings, const bob_dom_materials *materials, const bob_point_map *pointMap, int idx)
{
	bob_dom_face *part;
	const bob_dom_point *pnt;
	int line=0;
	int materialIndex;
	
	int oldf=os.flags();
	
	size_t count=0;
	for(iterator &it=begin(); it!=end(); ++it){
		count+=it->size();
	}
	
	os << noSemicolons << "// ----- part " << idx << " (" << (int)count << " faces) -----" << endl << autoSemicolons;
	for(iterator &it=begin(); it!=end(); ++it){
		materialIndex=it->materialIndex;
		
		for(bob_face_list::iterator &it2=it->begin(); it2!=it->end(); ++it2, ++line){
			part=*it2;
			
			os << autoSemicolons << materialIndex;
			for(int i=0; i < 3; i++){
				os << pointMap->uniqueIndex(part->values[i]);
			}
			
			pnt=(*pointMap)[part->values[0]];
			if(pnt==NULL){
				error(e_pointNotFound);
				return false;
			}
			int SGBits=pnt->values.back();
			int magic;
			
			/*
				meaning of "magic" number:
				-25: smoothing bits and UV coords
				-17: smoothing bits and no UV coords
				-9: no smoothing and UV coords
				-1: no smoothing and no UV coords
				
				--obsolete----------------------
				old text from Checker's sources:
				if there are no materials used, magic is -17
				if there are materials and last value of the first point is non zero,
				magic is -25, otherwise it's -9
			*/
			
			const bob_dom_point *points_ar[3];
			for(int i=0; i < 3; i++){
				pnt=(*pointMap)[part->values[i]];
				if(pnt==NULL){
					error(e_pointNotFound);
					return false;
				}
				points_ar[i]=pnt;
			}
			
			bool bHasUV=false;
			for(int i=0; i < 3; i++){
				if(bHasUV=(points_ar[i]->textureCoords.left!=0 || points_ar[i]->textureCoords.right!=0))
					break;
			}
			
			if(SGBits) {
				if(bHasUV)
					magic=-25;
				else
					magic=-17;
			}
			else{
				if(bHasUV)
					magic=-9;
				else
					magic=-1;
			}
			
			os << magic;
			if(SGBits!=0) os << SGBits;
			
			// we have uv coords so lets output them
			if(bHasUV){
				double u, v;
				for(int i=0; i < 3; i++){
					u=points_ar[i]->textureCoords.left * multiplier;
					v=points_ar[i]->textureCoords.right * multiplier;
				
					os << (float) u << (float) v;
				}
				// those are the unknown values stored in point after texture coordinates
				// I place them after bod part definition and behind comment, so they are invisible to 
				// bod viewer and x2
				
				if(settings->extraPntInfo()){
					bool bEmpty=true;
					for(int i=0; i < 3; i++){
						bEmpty&=(points_ar[i]->values.size() <= 1);
					}
					if(!bEmpty){
						os << noSemicolons << "/! ";
						for(int i=0; i < 3; i++){
							os << "{ " << autoSemicolons;
							bob_dom_point::const_iterator &last=--points_ar[i]->values.end();
							double d;
							for(bob_dom_point::const_iterator &it=points_ar[i]->values.begin(); it!=last; ++it){
								d=*it * multiplier;
								if(d==0)
									os << 0;
								else
									os << (float)d;
							}
							os << noSemicolons << "} ";
						}
						os << "!/ " << autoSemicolons;
					}
				}
			}
			os << noSemicolons << "// " << line << endl;
		}
	}
	
	// x3 data
	if(flags & x3flag){
		os << "// x3 part values" << endl;
		if(settings->extraX3BobInfo())
			os << "/!" << endl;
		values.toFile(os, settings->extraX3BobInfo()==false);
		if(settings->extraX3BobInfo()) {
			os << endl << "// secondary UVs (or whatever this is)" << endl;
			for(iterator &it=begin(); it!=end(); ++it){
				it->x3uvlist.toFile(os, it->materialIndex);
			}
			os << "!/" << endl;
		}
	}

	int bit=1;
	char str[21];
	for(int i=19; i >= 0; i--){
		str[i]=flags & bit ? '1' : '0';
		bit<<=1;
	}
	str[sizeof(str)-1]=0;
	
	os << autoSemicolons  << "-99" << str << noSemicolons << "// part " << idx << " end" << endl;
	
	os.flags(oldf);
	
	return os.good();
}
//---------------------------------------------------------------------------------
// PART - object
bool bob_dom_face::load(bob_dom_ibinaryfilestream& is)
{
	for(int i=0; i < 4; i++){
		is >> values[i];
	}
	if(is.fail()) 
		errorCode=e_notEnoughData;
		
	return !is.fail();
}
//---------------------------------------------------------------------------------
bool bob_dom_face::toFile(bob_dom_obinaryfilestream& os)
{
	for(int i=0; i < 4; i++){
		os << values[i];
	}
	return os.good();
}
//---------------------------------------------------------------------------------
bool bob_dom_body::load(bob_dom_ibinaryfilestream& is)
{
	is >> bodySize >> bodyFlags;
	if(peek(is)==bob_dom_bones::hdr_begin){
		if(!bones.load(is)){
			for(ErrorIterator &it=bones.errors.begin(); it!=bones.errors.end(); ++it){
				error(it->code, "bones: %s", it->text);
			}
			return false;
		}
	}
	if(peek(is)==bob_dom_points::hdr_begin){
		if(points.load(is)==false){
			for(ErrorIterator &it=points.errors.begin(); it!=points.errors.end(); ++it){
				error(it->code, "points->%s", it->text);
			}
			return false;
		}
	}
	if(peek(is)==bob_dom_weights::hdr_begin){
		if(!weights.load(is)){
			for(ErrorIterator &it=weights.errors.begin(); it!=weights.errors.end(); ++it){
				error(it->code, "weights->%s", it->text);
			}
			return false;
		}
	}
	if(peek(is)==bob_dom_parts::hdr_begin){
		if(parts.load(is)==false){
			for(ErrorIterator &it=parts.errors.begin(); it!=parts.errors.end(); ++it){
				error(it->code, "parts->%s", it->text);
			}
			return false;
		}
	}
	return !is.fail();
}
//---------------------------------------------------------------------------------
bool bob_dom_body::toFile(bob_dom_obinaryfilestream& os)
{
	os << bodySize << bodyFlags;
	
	bones.toFile(os);
	points.toFile(os);
	weights.toFile(os);
	parts.toFile(os);
	
	return os.good();
}
//---------------------------------------------------------------------------------
bool bob_dom_body::toFile(bob_dom_otextfilestream& os, const Settings *settings, const bob_dom_materials *materials, int idx)
{
	os << "// beginning of body " << idx << endl;
	os << autoSemicolons << bodySize << endl << endl;
	
	bones.toFile(os);
	
	points.toFile(os);
	
	weights.toFile(os, &points.map);
	
	parts.toFile(os, settings, materials, &points.map);
	
	char str[17]; int bit=1;
	for(int i=15; i >= 0; i--){
		str[i]=bodyFlags & bit ? '1' : '0';
		bit<<=1;
	}
	str[sizeof(str)-1]=0;
	
	os << "-99" << str << noSemicolons << "// body " << idx << " end" << endl;
	
	return os.good();
}
//---------------------------------------------------------------------------------
// BONES
bool bob_dom_bones::load(bob_dom_ibinaryfilestream& is)
{
	int hdr, count;
	is >> hdr;
	if(hdr!=hdr_begin){
		error(e_badHeader);
		return false;
	}
	
	is >> count;
	char *name;
	for(int i=0; i < count; i++){
		is >> name;
		if(name==0){
			error(e_notEnoughData);
			delete[] name;
			return false;
		}
		push_back(name);
	}
	is >> hdr;
	if(hdr!=hdr_end){
		error(e_badEndHeader);
		return false;
	}
	return true;
}
//---------------------------------------------------------------------------------
bool bob_dom_bones::toFile(bob_dom_obinaryfilestream& os)
{
	if(size()==0) return true;
	
	os << hdr_begin << (int) size();
	for(iterator &it=begin(); it!=end(); ++it){
		os << *it;
	}
	os << hdr_end;
	return os.good();
}
//---------------------------------------------------------------------------------
bool bob_dom_bones::toFile(bob_dom_otextfilestream& os)
{
	if(size()==0) return true;
	os << noSemicolons << "BONES: " << autoSemicolons << (int)size() << endl;
	for(iterator &it=begin(); it!=end(); ++it){
		os << *it << endl;
	}
	os << endl;
	return os.good();
}
//---------------------------------------------------------------------------------
// WEIGHTS - section
bool bob_dom_weights::load(bob_dom_ibinaryfilestream& is)
{
	int hdr;
	is >> hdr;
	if(hdr!=hdr_begin){
		error(e_badHeader);
		return false;
	}
	
	int count;
	is >> count;
	resize(count);
	
	bob_dom_weight *ch;
	for(int i=0; i < count; i++){
		ch=new bob_dom_weight();
		if(!ch->load(is)){
			error(ch->errorCode, "weight[%d]: %s", i, bob_traslate_error(ch->errorCode));
			delete ch;
			return false;
		}
		(*this)[i]=ch;
	}
	is >> hdr;
	if(hdr!=hdr_end){
		error(e_badEndHeader);
		return false;
	}
	return true;
}
//---------------------------------------------------------------------------------
bool bob_dom_weights::toFile(bob_dom_obinaryfilestream& os)
{
	if(new_weights.size()==0 && size()==0) return true;
	
	os << hdr_begin;
	if(new_weights.size()){
		os << (int)new_weights.size();
		for(WeightList::iterator &it=new_weights.begin(); it!=new_weights.end(); ++it){
			it->toFile(os);
		}
	}
	else{
		os << (int)size();
		for(iterator &it=begin(); it!=end(); ++it){
			it->toFile(os);
		}
	}
	
	os << hdr_end;
	return os.good();
}
//---------------------------------------------------------------------------------
bool bob_dom_weights::toFile(bob_dom_otextfilestream& os, const bob_point_map *pointMap)
{
	if(size()==0) return true;
	os << noSemicolons << "WEIGHTS " << autoSemicolons << (int) pointMap->uniquePointsSize() << endl;
	int i=0;
	for(bob_point_map::const_index_iterator &it=pointMap->indexBegin(); it!=pointMap->indexEnd(); ++it){
		(*this)[*it]->toFile(os, i++);
	}
	os << autoSemicolons << "-1" << endl << endl;
	return os.good();
}
//---------------------------------------------------------------------------------
// WEIGHT - object
bool bob_dom_weight::load(bob_dom_ibinaryfilestream& is)
{
	short count;
	value v;
	
	is >> count;
	
	for(int i=0; i < count; i++){
		is >> v.boneIdx >> v.boneCoefficient;
		values.push_back(v);
	}
	
	return !is.fail();
}
//---------------------------------------------------------------------------------
bool bob_dom_weight::toFile(bob_dom_obinaryfilestream& os)
{	
	os << (short) values.size();
	
	value v;
	for(iterator &it=values.begin(); it!=values.end(); ++it){
		v=*it;
		os << v.boneIdx << v.boneCoefficient;
	}
	return os.good();
}
//---------------------------------------------------------------------------------
bool bob_dom_weight::toFile(bob_dom_otextfilestream& os, int idx)
{
	os << autoSemicolons;
	for(iterator &it=values.begin(); it!=values.end(); ++it){
		(*it).toFile(os);
	}
	os << noSemicolons << "-1; // " << idx << endl;
	return os.good();
}
//---------------------------------------------------------------------------------