void ARX_EQUIPMENT_RecreatePlayerMesh() {
	
	if(EXITING)
		return;
	
	arx_assert(entities.player());
	
	Entity * io = entities.player();
	
	if(io->obj != hero)
		delete io->obj;

	io->obj = loadObject("graph/obj3d/interactive/npc/human_base/human_base.teo", false);
	
	applyTweak(EQUIP_SLOT_HELMET, TWEAK_HEAD, "head");
	applyTweak(EQUIP_SLOT_ARMOR, TWEAK_TORSO, "chest");
	applyTweak(EQUIP_SLOT_LEGGINGS, TWEAK_LEGS, "leggings");
	
	Entity * target = entities.player();
	
	for(size_t i = 0; i < MAX_EQUIPED; i++) {
		if(ValidIONum(player.equiped[i])) {
			Entity *toequip = entities[player.equiped[i]];

			if(toequip) {
				if(toequip->type_flags & (OBJECT_TYPE_DAGGER | OBJECT_TYPE_1H | OBJECT_TYPE_2H | OBJECT_TYPE_BOW)) {
					if(player.Interface & INTER_COMBATMODE) {
						ARX_EQUIPMENT_AttachPlayerWeaponToHand();
					} else {
						EERIE_LINKEDOBJ_LinkObjectToObject(target->obj, toequip->obj, "weapon_attach", "primary_attach", toequip);
					}
				} else if(toequip->type_flags & OBJECT_TYPE_SHIELD) {
					if(ValidIONum(player.equiped[EQUIP_SLOT_SHIELD])) {
						EERIE_LINKEDOBJ_LinkObjectToObject(target->obj, toequip->obj, "shield_attach", "shield_attach", toequip);
					}
				}
			}
		}
	}

	ARX_PLAYER_Restore_Skin();
	HERO_SHOW_1ST = -1;

	if(EXTERNALVIEW) {
		ARX_INTERACTIVE_Show_Hide_1st(entities.player(), 0);
	} else {
		ARX_INTERACTIVE_Show_Hide_1st(entities.player(), 1);
	}

	ARX_INTERACTIVE_HideGore(entities.player(), 1);
	EERIE_Object_Precompute_Fast_Access(hero);
	EERIE_Object_Precompute_Fast_Access(entities.player()->obj);

	ARX_INTERACTIVE_RemoveGoreOnIO(entities.player()); 
}
示例#2
0
static void loadObjectData(EERIE_3DOBJ * eerie, const char * adr, size_t * poss, long version) {
	
	LogWarning << "loadObjectData";
	
	size_t pos = *poss;
	
	const THEO_OFFSETS * to = reinterpret_cast<const THEO_OFFSETS *>(adr + pos);
	pos += sizeof(THEO_OFFSETS);
	
	const THEO_NB * tn = reinterpret_cast<const THEO_NB *>(adr + pos);
	
	LogDebug("Nb Vertex " << tn->nb_vertex << " Nb Action Points " << tn->nb_action_point
	         << " Nb Lines " << tn->nb_lines);
	LogDebug("Nb Faces " << tn->nb_faces << " Nb Groups " << tn->nb_groups);
	
	eerie->vertexlist.resize(tn->nb_vertex);
	eerie->vertexlist3.resize(tn->nb_vertex);
	
	eerie->facelist.resize(tn->nb_faces);
	eerie->grouplist.resize(tn->nb_groups);
	eerie->actionlist.resize(tn->nb_action_point);
	
	eerie->ndata = NULL;
	eerie->pdata = NULL;
	eerie->cdata = NULL;
	eerie->sdata = NULL;
	
	// read vertices
	
	pos = to->vertex_seek;
	
	if(tn->nb_vertex > 65535) {
		LogError << ("Warning Vertex Number Too High...");
	}
	
	for(long i = 0; i < tn->nb_vertex; i++) {
		const THEO_VERTEX * ptv = reinterpret_cast<const THEO_VERTEX *>(adr + pos);
		pos += sizeof(THEO_VERTEX);
		eerie->vertexlist[i].v = ptv->pos.toVec3();
		eerie->cub.xmin = std::min(eerie->cub.xmin, ptv->pos.x);
		eerie->cub.xmax = std::max(eerie->cub.xmax, ptv->pos.x);
		eerie->cub.ymin = std::min(eerie->cub.ymin, ptv->pos.y);
		eerie->cub.ymax = std::max(eerie->cub.ymax, ptv->pos.y);
		eerie->cub.zmin = std::min(eerie->cub.zmin, ptv->pos.z);
		eerie->cub.zmax = std::max(eerie->cub.zmax, ptv->pos.z);
	}

	// Lecture des FACES THEO
	pos = to->faces_seek;

	for(long i = 0; i < tn->nb_faces; i++) {
		
		THEO_FACES_3006 tf3006;
		const THEO_FACES_3006 * ptf3006;
		if(version >= 3006) {
			ptf3006 = reinterpret_cast<const THEO_FACES_3006 *>(adr + pos);
			pos += sizeof(THEO_FACES_3006);
		} else {
			memset(&tf3006, 0, sizeof(THEO_FACES_3006));
			const THEO_FACES * ptf = reinterpret_cast<const THEO_FACES *>(adr + pos);
			pos += sizeof(THEO_FACES);
			tf3006.color = ptf->color;
			tf3006.index1 = ptf->index1;
			tf3006.index2 = ptf->index2;
			tf3006.index3 = ptf->index3;
			tf3006.ismap = ptf->ismap;
			tf3006.liste_uv = ptf->liste_uv;
			tf3006.element_uv = ptf->element_uv;
			tf3006.num_map = ptf->num_map;
			tf3006.tile_x = ptf->tile_x;
			tf3006.tile_y = ptf->tile_y;
			tf3006.user_tile_x = ptf->user_tile_x;
			tf3006.user_tile_y = ptf->user_tile_y;
			tf3006.flag = ptf->flag;
			tf3006.collision_type = ptf->collision_type;
			tf3006.rgb = ptf->rgb;
			tf3006.rgb1 = ptf->rgb1;
			tf3006.rgb2 = ptf->rgb2;
			tf3006.rgb3 = ptf->rgb3;
			tf3006.double_side = ptf->double_side;
			tf3006.transparency = ptf->transparency;
			tf3006.trans = ptf->trans;
			ptf3006 = &tf3006;
		}
		
		eerie->facelist[i].vid[0] = (unsigned short)ptf3006->index1;
		eerie->facelist[i].vid[1] = (unsigned short)ptf3006->index2;
		eerie->facelist[i].vid[2] = (unsigned short)ptf3006->index3;
		
		s32 num_map = ((size_t)ptf3006->num_map >= eerie->texturecontainer.size()) ? -1 : ptf3006->num_map;
		
		if(ptf3006->ismap) {
			eerie->facelist[i].texid = (short)num_map;
			eerie->facelist[i].facetype = POLY_NO_SHADOW;
			
			if(num_map >= 0 && eerie->texturecontainer[num_map] && (eerie->texturecontainer[num_map]->userflags & POLY_NOCOL)) {
				eerie->facelist[i].facetype |= POLY_NOCOL;
			}
		} else {
			eerie->facelist[i].texid = -1;
		}
		
		switch(ptf3006->flag) {
			case 0:
				eerie->facelist[i].facetype |= POLY_GLOW;
				break;
			case 1:
				eerie->facelist[i].facetype |= POLY_NO_SHADOW;
				break;
			case 4:
				eerie->facelist[i].facetype |= POLY_METAL;
				break;
			case 10:
				eerie->facelist[i].facetype |= POLY_NOPATH;
				break;
			case 11:
				eerie->facelist[i].facetype |= POLY_CLIMB;
				break;
			case 12:
				eerie->facelist[i].facetype |= POLY_NOCOL;
				break;
			case 13:
				eerie->facelist[i].facetype |= POLY_NODRAW;
				break;
			case 14:
				eerie->facelist[i].facetype |= POLY_PRECISE_PATH;
				break;
			case 16:
				eerie->facelist[i].facetype |= POLY_NO_CLIMB;
				break;
		}
		
		eerie->facelist[i].ou[0] = (short)ptf3006->liste_uv.u1;
		eerie->facelist[i].ov[0] = (short)ptf3006->liste_uv.v1;
		eerie->facelist[i].ou[1] = (short)ptf3006->liste_uv.u2;
		eerie->facelist[i].ov[1] = (short)ptf3006->liste_uv.v2;
		eerie->facelist[i].ou[2] = (short)ptf3006->liste_uv.u3;
		eerie->facelist[i].ov[2] = (short)ptf3006->liste_uv.v3;
		
		if(ptf3006->double_side) {
			eerie->facelist[i].facetype |= POLY_DOUBLESIDED;
		}
		
		if(ptf3006->transparency > 0) {
			if(ptf3006->transparency == 2) {
				// NORMAL TRANS 0.00001 to 0.999999
				if(ptf3006->trans < 1.f) {
					eerie->facelist[i].facetype |= POLY_TRANS;
					eerie->facelist[i].transval = ptf3006->trans;
				}
			}
			else if (ptf3006->transparency == 1) {
				if(ptf3006->trans < 0.f) {
					// SUBTRACTIVE -0.000001 to -0.999999
					eerie->facelist[i].facetype |= POLY_TRANS;
					eerie->facelist[i].transval = ptf3006->trans;
				} else {
					// ADDITIVE 1.000001 to 1.9999999
					eerie->facelist[i].facetype |= POLY_TRANS;
					eerie->facelist[i].transval = ptf3006->trans + 1.f;
				}
			} else {
				// MULTIPLICATIVE 2.000001 to 2.9999999
				eerie->facelist[i].facetype |= POLY_TRANS;
				eerie->facelist[i].transval = ptf3006->trans + 2.f;
			}
		}
		
		if(eerie->facelist[i].texid != -1 && !eerie->texturecontainer.empty() && eerie->texturecontainer[eerie->facelist[i].texid] != NULL) {
			
			if(eerie->texturecontainer[eerie->facelist[i].texid]->userflags & POLY_TRANS) {
				if(!(eerie->facelist[i].facetype & POLY_TRANS)) {
					eerie->facelist[i].facetype |= POLY_TRANS;
					eerie->facelist[i].transval = ptf3006->trans;
				}
			}
			
			if(eerie->texturecontainer[eerie->facelist[i].texid]->userflags & POLY_WATER) {
				eerie->facelist[i].facetype |= POLY_WATER;
			}
			
			if(eerie->texturecontainer[eerie->facelist[i].texid]->userflags & POLY_LAVA) {
				eerie->facelist[i].facetype |= POLY_LAVA;
			}
			
			if(eerie->texturecontainer[eerie->facelist[i].texid]->userflags & POLY_FALL) {
				eerie->facelist[i].facetype |= POLY_FALL;
			}

			if(eerie->texturecontainer[eerie->facelist[i].texid]->userflags & POLY_CLIMB) {
				eerie->facelist[i].facetype |= POLY_CLIMB;
			}
		}
		
	}
	
	// Groups Data
	pos = to->groups_seek;
	
	for(long i = 0; i < tn->nb_groups; i++) {
		
		THEO_GROUPS_3011 tg3011;
		const THEO_GROUPS_3011 * ptg3011;
		if(version >= 3011) {
			ptg3011 = reinterpret_cast<const THEO_GROUPS_3011 *>(adr + pos);
			pos += sizeof(THEO_GROUPS_3011);
		} else {
			const THEO_GROUPS * ltg = reinterpret_cast<const THEO_GROUPS *>(adr + pos);
			pos += sizeof(THEO_GROUPS);
			memset(&tg3011, 0, sizeof(THEO_GROUPS_3011));
			tg3011.origin = ltg->origin;
			tg3011.nb_index = ltg->nb_index;
			ptg3011 = &tg3011;
		}
		
		eerie->grouplist[i].origin = ptg3011->origin;
		eerie->grouplist[i].indexes.resize(ptg3011->nb_index);
		
		std::copy((const long*)(adr + pos), (const long*)(adr + pos) + ptg3011->nb_index, eerie->grouplist[i].indexes.begin());
		pos += ptg3011->nb_index * sizeof(long);
		
		eerie->grouplist[i].name = boost::to_lower_copy(util::loadString(adr + pos, 256));
		pos += 256;
		eerie->grouplist[i].siz = 0.f;
		
		for(long o = 0; o < ptg3011->nb_index; o++) {
			eerie->grouplist[i].siz = std::max(eerie->grouplist[i].siz,
			                              fdist(eerie->vertexlist[eerie->grouplist[i].origin].v,
			                                           eerie->vertexlist[eerie->grouplist[i].indexes[o]].v));
		}
		
		eerie->grouplist[i].siz = ffsqrt(eerie->grouplist[i].siz) * (1.f/16);
		
	}

	// SELECTIONS
	s32 THEO_nb_selected = *reinterpret_cast<const s32 *>(adr + pos);
	pos += sizeof(s32);
	
	eerie->selections.resize(THEO_nb_selected);
	for(long i = 0; i < THEO_nb_selected; i++) {
		
		const THEO_SELECTED * pts = reinterpret_cast<const THEO_SELECTED *>(adr + pos);
		pos += sizeof(THEO_SELECTED);
		
		eerie->selections[i].name = boost::to_lower_copy(util::loadString(pts->name));
		eerie->selections[i].selected.resize(pts->nb_index);
		
		if(pts->nb_index > 0) {
			std::copy((const long*)(adr + pos), (const long*)(adr + pos) + pts->nb_index, eerie->selections[i].selected.begin());
			pos += sizeof(long) * pts->nb_index;
		}
	}
	
	// Theo Action Points Read
	pos = to->action_point_seek;

	for(long i = 0; i < tn->nb_action_point; i++) {
		
		const THEO_ACTION_POINT * ptap = reinterpret_cast<const THEO_ACTION_POINT *>(adr + pos);
		pos += sizeof(THEO_ACTION_POINT);
		
		eerie->actionlist[i].act = ptap->action;
		eerie->actionlist[i].sfx = ptap->num_sfx;
		eerie->actionlist[i].idx = ptap->vert_index;
		eerie->actionlist[i].name = boost::to_lower_copy(util::loadString(ptap->name));
	}
	
	eerie->angle = Anglef::ZERO;
	eerie->pos = Vec3f_ZERO;
	
	// Now Interpret Extra Data chunk
	pos = to->extras_seek + 4;
	
	if(version >= 3005) {
		
		const THEO_EXTRA_DATA_3005 * pted3005 = reinterpret_cast<const THEO_EXTRA_DATA_3005 *>(adr + pos);
		pos += sizeof(THEO_EXTRA_DATA_3005);
		
		eerie->pos = pted3005->pos.toVec3();
		
		eerie->angle.setYaw((float)(pted3005->angle.alpha & 0xfff) * THEO_ROTCONVERT);
		eerie->angle.setPitch((float)(pted3005->angle.beta & 0xfff) * THEO_ROTCONVERT);
		eerie->angle.setRoll((float)(pted3005->angle.gamma & 0xfff) * THEO_ROTCONVERT);
		
		eerie->point0 = eerie->vertexlist[pted3005->origin_index].v;
		eerie->origin = pted3005->origin_index;
		
		eerie->quat = pted3005->quat;
	
	} else {
		
		const THEO_EXTRA_DATA * pted = reinterpret_cast<const THEO_EXTRA_DATA *>(adr + pos);
		pos += sizeof(THEO_EXTRA_DATA);
		
		eerie->pos = pted->pos.toVec3();
		
		eerie->angle.setYaw((float)(pted->angle.alpha & 0xfff) * THEO_ROTCONVERT);
		eerie->angle.setPitch((float)(pted->angle.beta & 0xfff) * THEO_ROTCONVERT);
		eerie->angle.setRoll((float)(pted->angle.gamma & 0xfff) * THEO_ROTCONVERT);
		
		eerie->point0 = eerie->vertexlist[pted->origin_index].v;
		eerie->origin = pted->origin_index;
	}
	
	*poss = pos;
	
	eerie->vertexlist3 = eerie->vertexlist;
	ReCreateUVs(eerie);
	EERIE_Object_Precompute_Fast_Access(eerie);
}
示例#3
0
void EERIE_MESH_TWEAK_Do(INTERACTIVE_OBJ * io, long tw, char * _path)
{
	if (!ALLOW_MESH_TWEAKING) return;

	char file2[256];
	char filet[256];
	char path[256];
	File_Standardize(_path, path);

	strcpy(filet, "GAME\\");
	strcat(filet, path);

	SetExt(filet, ".FTL");
	File_Standardize(filet, file2);

	if ((!PAK_FileExist(file2)) && (!PAK_FileExist(path))) return;

	if (tw == TWEAK_ERROR) return;

	if (io == NULL) return;

	if (io->obj == NULL) return;

	EERIE_MESH_ReleaseTransPolys(io->obj);

	if ((path == NULL) && (tw == TWEAK_REMOVE))
	{
		if (io->tweaky)
		{
			ReleaseEERIE3DObj(io->obj);
			io->obj = io->tweaky;
			EERIE_Object_Precompute_Fast_Access(io->obj);
			io->tweaky = NULL;
		}

		return;
	}

	EERIE_3DOBJ * tobj = NULL;
	EERIE_3DOBJ * result = NULL;
	EERIE_3DOBJ * result2 = NULL;

	if ((PAK_FileExist(file2)) || (PAK_FileExist(path)))
	{
		
		const char DIR_TEXTURES[] = "Graph\\Obj3D\\Textures\\";
		
		if (io->ioflags & IO_NPC)
			tobj = TheoToEerie_Fast(DIR_TEXTURES, path, TTE_NPC);
		else
			tobj = TheoToEerie_Fast(DIR_TEXTURES, path, 0);

		if (!tobj) return;

		switch (tw)
		{
			case TWEAK_ALL:

				if (io->tweaky == NULL) io->tweaky = io->obj;
				else ReleaseEERIE3DObj(io->obj);

				long i;
				TextureContainer * tc;
				tc = NULL;

				for (i = 0; i < tobj->nbfaces; i++)
				{
					if ((tobj->facelist[i].texid >= 0)
					        &&	(tobj->texturecontainer[tobj->facelist[i].texid]))
					{
						tc = tobj->texturecontainer[tobj->facelist[i].texid];

						if (!tc->m_pddsSurface)
							tc->Restore(GDevice);
					}
				}

				io->obj = tobj;
				return;
				break;
			case TWEAK_UPPER:
				result2 = CreateIntermediaryMesh(io->obj, tobj, TWEAK_HEAD);
				result = CreateIntermediaryMesh(result2, tobj, TWEAK_TORSO);
				ReleaseEERIE3DObj(result2);
				break;
			case TWEAK_LOWER:
				result2 = CreateIntermediaryMesh(io->obj, tobj, TWEAK_TORSO);
				result = CreateIntermediaryMesh(result2, tobj, TWEAK_LEGS);
				ReleaseEERIE3DObj(result2);
				break;
			case TWEAK_UP_LO:
				result = CreateIntermediaryMesh(tobj, io->obj, TWEAK_TORSO);
				break;
			default:
				result = CreateIntermediaryMesh(io->obj, tobj, tw);
				break;
		}

		if (result == NULL)
		{
			ReleaseEERIE3DObj(tobj);
			return;
		}

		result->pdata = NULL;
		result->cdata = NULL;

		if (io->tweaky == NULL) io->tweaky = io->obj;
		else if (io->tweaky != io->obj)
			ReleaseEERIE3DObj(io->obj);

		io->obj = result;
		EERIE_Object_Precompute_Fast_Access(io->obj);
	}

	EERIE_CreateCedricData(io->obj);

	if (io)
	{
		io->lastanimtime = 0;
		io->nb_lastanimvertex = 0;
	}

	ReleaseEERIE3DObj(tobj);
}
示例#4
0
void EERIE_MESH_TWEAK_Do(Entity * io, TweakType tw, const res::path & path) {
	
	res::path ftl_file = ("game" / path).set_ext("ftl");

	if ((!g_resources->getFile(ftl_file)) && (!g_resources->getFile(path))) return;

	if (!tw) return;

	if (io == NULL) return;

	if (io->obj == NULL) return;

	if(path.empty() && tw == TWEAK_REMOVE) {
		
		if(io->tweaky) {
			delete io->obj;
			io->obj = io->tweaky;
			EERIE_Object_Precompute_Fast_Access(io->obj);
			io->tweaky = NULL;
		}
		
		return;
	}

	EERIE_3DOBJ * tobj = NULL;
	EERIE_3DOBJ * result = NULL;

	{
		tobj = loadObject(path);

		if (!tobj) return;

		switch (tw)
		{
			case (u32)TWEAK_HEAD | (u32)TWEAK_TORSO | (u32)TWEAK_LEGS:

				if (!io->tweaky)
					io->tweaky = io->obj;
				else delete
					io->obj;

				io->obj = tobj;
				return;
				break;
			case (u32)TWEAK_HEAD | (u32)TWEAK_TORSO: {
				EERIE_3DOBJ * result2 = CreateIntermediaryMesh(io->obj, tobj, TWEAK_HEAD);
				result = CreateIntermediaryMesh(result2, tobj, TWEAK_TORSO);
				delete result2;
				break;
			}
			case (u32)TWEAK_TORSO | (u32)TWEAK_LEGS: {
				EERIE_3DOBJ * result2 = CreateIntermediaryMesh(io->obj, tobj, TWEAK_TORSO);
				result = CreateIntermediaryMesh(result2, tobj, TWEAK_LEGS);
				delete result2;
				break;
			}
			case (u32)TWEAK_HEAD | (u32)TWEAK_LEGS:
				result = CreateIntermediaryMesh(tobj, io->obj, TWEAK_TORSO);
				break;
			default:
				result = CreateIntermediaryMesh(io->obj, tobj, tw);
				break;
		}

		if(!result) {
			delete tobj;
			return;
		}

		if (io->tweaky == NULL) io->tweaky = io->obj;
		else if (io->tweaky != io->obj)
			delete io->obj;

		io->obj = result;
		EERIE_Object_Precompute_Fast_Access(io->obj);
	}

	EERIE_CreateCedricData(io->obj);
	
	io->animBlend.lastanimtime = 0;
	io->animBlend.m_active = false;
	
	delete tobj;
}
示例#5
0
//***********************************************************************************************
// Uses Fast Object Load if FTL file exists
//-----------------------------------------------------------------------------------------------
// VERIFIED (Cyril 2001/10/15)
//***********************************************************************************************
EERIE_3DOBJ * ARX_FTL_Load(const char * file)
{
	
	
	// Creates FTL file name
	char filename[256];
	sprintf(filename, "Game\\%s", file);
	SetExt(filename, ".FTL");

	// Checks for FTL file existence
	if(!PAK_FileExist(filename)) {
		LogError<<"ARX_FTL_Load: not found in PAK" << filename;
		return NULL;
	}

	// Our file exist we can use it
	unsigned char * dat;
	long pos = 0;
	size_t allocsize;

	ARX_FTL_PRIMARY_HEADER 	*		afph;
	ARX_FTL_SECONDARY_HEADER 	*		afsh;
	ARX_FTL_PROGRESSIVE_DATA_HEADER *	afpdh;
	ARX_FTL_CLOTHES_DATA_HEADER 	*	afcdh;
	ARX_FTL_COLLISION_SPHERES_DATA_HEADER * afcsdh;
	ARX_FTL_3D_DATA_HEADER 	*		af3Ddh;

	char * compressedData = NULL;
	size_t compressedSize = 0;
	long NOrelease = 1;
	long NoCheck = 0;

	compressedData = MCache_Pop(filename, &compressedSize);

	if (!compressedData)
	{
		compressedData = (char *)PAK_FileLoadMalloc(filename, &compressedSize);
		NOrelease = MCache_Push(filename, compressedData, compressedSize) ? 1 : 0;
	}
	else NoCheck = 1;

	if(!compressedData) {
		printf("ARX_FTL_Load: error loading from PAK\n");
		return NULL;
	}

	long DontCheck = 0;

	DontCheck = 1;

	dat = (unsigned char *)STD_Explode(compressedData, compressedSize, &allocsize);//pos,&cpr_pos);
	// TODO size ignored

	if(!dat) {
		printf("ARX_FTL_Load: error decompressing\n");
		return NULL;
	}

	if (!NOrelease) free(compressedData);

	// Pointer to Primary Header
	afph = (ARX_FTL_PRIMARY_HEADER *)dat;
	pos += sizeof(ARX_FTL_PRIMARY_HEADER);

	// Verify FTL file Signature
	if ((afph->ident[0] != 'F') && (afph->ident[1] != 'T') && (afph->ident[2] != 'L'))
	{
		printf("ARX_FTL_Load: wrong magic number\n");
		free(dat);
		return NULL;
	}

	// Verify FTL file version
	if (afph->version != CURRENT_FTL_VERSION)
	{
		printf("ARX_FTL_Load: wrong version: %f, expected %f\n", afph->version, CURRENT_FTL_VERSION);
		free(dat);
		return NULL;
	}

	// Verify Checksum
	if ((!NOCHECKSUM || NoCheck) && !DontCheck)
	{
		char check[512];

		HERMES_CreateFileCheck(file, check, 512, CURRENT_FTL_VERSION);

		char * pouet = (char *)(dat + pos);

		for (long i = 0; i < 512; i++)
			if (check[i] != pouet[i])
			{
				printf("ARX_FTL_Load: checksum error\n");
				free(dat);
				return NULL;
			}
	}

	// Increases offset by checksum size
	pos += 512;

	// Pointer to Secondary Header
	afsh = (ARX_FTL_SECONDARY_HEADER *)(dat + pos);
	pos += sizeof(ARX_FTL_SECONDARY_HEADER);

	EERIE_3DOBJ * obj = NULL;
	
	// Check For & Load 3D Data
	if (afsh->offset_3Ddata != -1)
	{

		//todo free
		obj = (EERIE_3DOBJ *)malloc(sizeof(EERIE_3DOBJ));
		memset(obj, 0, sizeof(EERIE_3DOBJ));

		af3Ddh = (ARX_FTL_3D_DATA_HEADER *)(dat + afsh->offset_3Ddata);
		pos = afsh->offset_3Ddata;
		pos += sizeof(ARX_FTL_3D_DATA_HEADER);

		obj->nbvertex = af3Ddh->nb_vertex;
		obj->nbfaces = af3Ddh->nb_faces;
		obj->nbmaps = af3Ddh->nb_maps;
		obj->nbgroups = af3Ddh->nb_groups;
		obj->nbaction = af3Ddh->nb_action;
		obj->nbselections = af3Ddh->nb_selections;
		obj->origin = af3Ddh->origin;
		strcpy(obj->file, af3Ddh->name);

		// Alloc'n'Copy vertices
		if (obj->nbvertex > 0)
		{
			//todo free
			obj->vertexlist = (EERIE_VERTEX *)malloc(sizeof(EERIE_VERTEX) * obj->nbvertex);

			obj->vertexlist3 = (EERIE_VERTEX *)malloc(sizeof(EERIE_VERTEX) * obj->nbvertex);

			for (long ii = 0; ii < obj->nbvertex; ii++)
			{
				memcpy(&obj->vertexlist[ii], dat + pos, sizeof(EERIE_OLD_VERTEX));
				memcpy(&obj->vertexlist3[ii], dat + pos, sizeof(EERIE_OLD_VERTEX));
				pos += sizeof(EERIE_OLD_VERTEX); 
			}

			obj->point0.x = obj->vertexlist[obj->origin].v.x;
			obj->point0.y = obj->vertexlist[obj->origin].v.y;
			obj->point0.z = obj->vertexlist[obj->origin].v.z;

			for (long i = 0; i < obj->nbvertex; i++)
			{
				obj->vertexlist[i].vert.color = 0xFF000000;
				obj->vertexlist3[i].vert.color = 0xFF000000;
			}
		}

		// Alloc'n'Copy faces
		if (obj->nbfaces > 0)
		{
			//todo free
			obj->facelist = (EERIE_FACE *)malloc(sizeof(EERIE_FACE) * obj->nbfaces);

			for (long ii = 0; ii < af3Ddh->nb_faces; ii++)
			{
				EERIE_FACE_FTL * eff = (EERIE_FACE_FTL *)(dat + pos);
				obj->facelist[ii].facetype = eff->facetype;
				obj->facelist[ii].texid = eff->texid;
				obj->facelist[ii].transval = eff->transval;
				obj->facelist[ii].temp = eff->temp;
				memcpy(&obj->facelist[ii].norm, &eff->norm, sizeof(EERIE_3D));

				for (long kk = 0; kk < IOPOLYVERT; kk++)
				{
					memcpy(&obj->facelist[ii].nrmls[kk], &eff->nrmls[kk], sizeof(EERIE_3D));
					obj->facelist[ii].vid[kk] = eff->vid[kk];
					obj->facelist[ii].u[kk] = eff->u[kk];
					obj->facelist[ii].v[kk] = eff->v[kk];
					obj->facelist[ii].ou[kk] = eff->ou[kk];
					obj->facelist[ii].ov[kk] = eff->ov[kk];
				}

				pos += sizeof(EERIE_FACE_FTL); 
			}
		}

		// Alloc'n'Copy textures
		if (af3Ddh->nb_maps > 0)
		{
			char ficc[256];
			char ficc2[256];
			char ficc3[256];

			//todo free
			obj->texturecontainer = (TextureContainer **)malloc(sizeof(TextureContainer *) * af3Ddh->nb_maps);

			for (long i = 0; i < af3Ddh->nb_maps; i++)
			{
				memcpy(ficc2, dat + pos, 256);
				strcpy(ficc3, ficc2);
				File_Standardize(ficc3, ficc);

				obj->texturecontainer[i] = D3DTextr_CreateTextureFromFile(ficc, 0, 0, EERIETEXTUREFLAG_LOADSCENE_RELEASE);

				if (GDevice && obj->texturecontainer[i] && !obj->texturecontainer[i]->m_pddsSurface)
					obj->texturecontainer[i]->Restore(GDevice);

				MakeUserFlag(obj->texturecontainer[i]);
				pos += 256;
			}
		}

		// Alloc'n'Copy groups
		if (obj->nbgroups > 0)
		{
			//todo free
			obj->grouplist = (EERIE_GROUPLIST *)malloc(sizeof(EERIE_GROUPLIST) * obj->nbgroups);
			memcpy(obj->grouplist, dat + pos, sizeof(EERIE_GROUPLIST) * obj->nbgroups);
			pos += sizeof(EERIE_GROUPLIST) * obj->nbgroups;

			for (long i = 0; i < obj->nbgroups; i++)
				if (obj->grouplist[i].nb_index > 0)
				{
					//TO DO: FREE+++++++++++++++++++++++
					obj->grouplist[i].indexes = (long *)malloc(sizeof(long) * obj->grouplist[i].nb_index);
					memcpy(obj->grouplist[i].indexes, dat + pos, sizeof(long)*obj->grouplist[i].nb_index);
					pos += sizeof(long) * obj->grouplist[i].nb_index;
				}
		}

		// Alloc'n'Copy action points
		if (obj->nbaction > 0)
		{
			//todo free
			obj->actionlist = (EERIE_ACTIONLIST *)malloc(sizeof(EERIE_ACTIONLIST) * obj->nbaction);
			memcpy(obj->actionlist, dat + pos, sizeof(EERIE_ACTIONLIST)*obj->nbaction);
			pos += sizeof(EERIE_ACTIONLIST) * obj->nbaction;
		}

		// Alloc'n'Copy selections
		if (obj->nbselections > 0)
		{
			//todo free++
			obj->selections = (EERIE_SELECTIONS *)malloc(sizeof(EERIE_SELECTIONS) * obj->nbselections);
			memcpy(obj->selections, dat + pos, sizeof(EERIE_SELECTIONS)*obj->nbselections);
			pos += sizeof(EERIE_SELECTIONS) * obj->nbselections;

			for (long i = 0; i < af3Ddh->nb_selections; i++)
			{
				//todo free+++
				obj->selections[i].selected = (long *)malloc(sizeof(long) * obj->selections[i].nb_selected);
				memcpy(obj->selections[i].selected, dat + pos, sizeof(long)*obj->selections[i].nb_selected);
				pos += sizeof(long) * obj->selections[i].nb_selected;
			}
		}

		obj->pbox = NULL;
	}

	if (!obj)
	{
		printf("ARX_FTL_Load: error loading data\n");
		free(dat);
		return NULL;
	}

	// Alloc'n'Copy Collision Spheres Data
	if (afsh->offset_collision_spheres != -1)
	{
		afcsdh = (ARX_FTL_COLLISION_SPHERES_DATA_HEADER *)(dat + afsh->offset_collision_spheres);
		pos = afsh->offset_collision_spheres;
		pos += sizeof(ARX_FTL_COLLISION_SPHERES_DATA_HEADER);

		obj->sdata = (COLLISION_SPHERES_DATA *)malloc(sizeof(COLLISION_SPHERES_DATA));
		obj->sdata->nb_spheres = afcsdh->nb_spheres;

		obj->sdata->spheres = (COLLISION_SPHERE *)malloc(sizeof(COLLISION_SPHERE) * obj->sdata->nb_spheres);

		memcpy(obj->sdata->spheres, dat + pos, sizeof(COLLISION_SPHERE)*obj->sdata->nb_spheres);
		pos += sizeof(COLLISION_SPHERE) * obj->sdata->nb_spheres;
	}

	// Alloc'n'Copy Progressive DATA
	if (afsh->offset_progressive_data != -1)
	{
		afpdh = (ARX_FTL_PROGRESSIVE_DATA_HEADER *)(dat + afsh->offset_progressive_data);
		pos = afsh->offset_progressive_data;
		pos += sizeof(ARX_FTL_PROGRESSIVE_DATA_HEADER);
		pos += sizeof(PROGRESSIVE_DATA) * afpdh->nb_vertex;
	}

	// Alloc'n'Copy Clothes DATA
	if (afsh->offset_clothes_data != -1)
	{
		obj->cdata = (CLOTHES_DATA *)malloc(sizeof(CLOTHES_DATA));
		memset(obj->cdata, 0, sizeof(CLOTHES_DATA));

		afcdh = (ARX_FTL_CLOTHES_DATA_HEADER *)(dat + afsh->offset_clothes_data);
		obj->cdata->nb_cvert = (short)afcdh->nb_cvert;
		obj->cdata->nb_springs = (short)afcdh->nb_springs;
		pos = afsh->offset_clothes_data;
		pos += sizeof(ARX_FTL_CLOTHES_DATA_HEADER);

		// now load cvert
		obj->cdata->cvert = (CLOTHESVERTEX *)malloc(sizeof(CLOTHESVERTEX) * obj->cdata->nb_cvert);
		obj->cdata->backup = (CLOTHESVERTEX *)malloc(sizeof(CLOTHESVERTEX) * obj->cdata->nb_cvert);
		memcpy(obj->cdata->cvert, dat + pos, sizeof(CLOTHESVERTEX)*obj->cdata->nb_cvert);
		memcpy(obj->cdata->backup, dat + pos, sizeof(CLOTHESVERTEX)*obj->cdata->nb_cvert);
		pos += sizeof(CLOTHESVERTEX) * obj->cdata->nb_cvert;

		// now load springs
		obj->cdata->springs = (EERIE_SPRINGS *)malloc(sizeof(EERIE_SPRINGS) * obj->cdata->nb_springs);
		memcpy(obj->cdata->springs, dat + pos, sizeof(EERIE_SPRINGS)*obj->cdata->nb_springs);
		pos += sizeof(EERIE_SPRINGS) * obj->cdata->nb_springs;
	}

	free(dat);

	if (BH_MODE)
		EERIE_OBJECT_MakeBH(obj);

	EERIE_OBJECT_CenterObjectCoordinates(obj);
	EERIE_CreateCedricData(obj);
	EERIEOBJECT_CreatePFaces(obj);
	// Now we can release our cool FTL file
	EERIE_Object_Precompute_Fast_Access(obj);
	LogInfo<<"loaded "<< file;
	return obj;
}