EERIE_3DOBJ * Eerie_Copy(const EERIE_3DOBJ * obj) { EERIE_3DOBJ * nouvo = new EERIE_3DOBJ(); nouvo->vertexlist = obj->vertexlist; nouvo->vertexlist3 = obj->vertexlist3; nouvo->ndata = NULL; nouvo->pbox = NULL; nouvo->pdata = NULL; nouvo->cdata = NULL; nouvo->sdata = NULL; nouvo->m_skeleton = NULL; nouvo->vertexlocal = NULL; nouvo->angle = obj->angle; nouvo->pos = obj->pos; nouvo->cub.xmax = obj->cub.xmax; nouvo->cub.xmin = obj->cub.xmin; nouvo->cub.ymax = obj->cub.ymax; nouvo->cub.ymin = obj->cub.ymin; nouvo->cub.zmax = obj->cub.zmax; nouvo->cub.zmin = obj->cub.zmin; if(!obj->file.empty()) nouvo->file = obj->file; if(!obj->name.empty()) nouvo->name = obj->name; nouvo->origin = obj->origin; nouvo->point0 = obj->point0; nouvo->quat = obj->quat; if(obj->ndata) nouvo->ndata = copyStruct(obj->ndata, obj->vertexlist.size()); else nouvo->ndata = NULL; nouvo->facelist = obj->facelist; nouvo->grouplist = obj->grouplist; nouvo->actionlist = obj->actionlist; nouvo->selections = obj->selections; nouvo->texturecontainer = obj->texturecontainer; nouvo->fastaccess = obj->fastaccess; EERIE_CreateCedricData(nouvo); if(obj->pbox) { nouvo->pbox = new PHYSICS_BOX_DATA(); nouvo->pbox->nb_physvert = obj->pbox->nb_physvert; nouvo->pbox->stopcount = 0; nouvo->pbox->radius = obj->pbox->radius; nouvo->pbox->vert = copyStruct(obj->pbox->vert, obj->pbox->nb_physvert); } nouvo->linked.clear(); nouvo->originaltextures = NULL; return nouvo; }
// Converts a Theo Object to an EERIE object static EERIE_3DOBJ * TheoToEerie(const char * adr, long size, const res::path & texpath, const res::path & fic) { LogWarning << "TheoToEerie " << fic; if(!adr) return NULL; res::path txpath = texpath.empty() ? "graph/obj3d/textures" : texpath; if(size < 10) { return NULL; } size_t pos = 0; const THEO_HEADER * pth = reinterpret_cast<const THEO_HEADER *>(adr + pos); pos += sizeof(THEO_HEADER); if(pth->version < 3003 || pth->version > 3011) { LogError << "TheoToEerie: invalid version in " << fic << ": found " << pth->version << " expected 3004 to 3011"; return NULL; } EERIE_3DOBJ * eerie = new EERIE_3DOBJ; eerie->clear(); eerie->file = fic; if(pth->type_write == 0) { // read the texture LogError << "WARNING object " << fic << " SAVE MAP IN OBJECT = INVALID... Using Dummy Textures..."; eerie->texturecontainer.resize(pth->nb_maps); for(long i = 0; i < pth->nb_maps; i++) { pos += sizeof(THEO_TEXTURE); eerie->texturecontainer[i] = GetAnyTexture(); } } else { if((pth->type_write & SAVE_MAP_BMP) || (pth->type_write & SAVE_MAP_TGA)) { eerie->texturecontainer.resize(pth->nb_maps); for(long i = 0; i < pth->nb_maps; i++) { res::path name; if(pth->version >= 3008) { const THEO_SAVE_MAPS_IN_3019 * tsmi3019 = reinterpret_cast<const THEO_SAVE_MAPS_IN_3019 *>(adr + pos); pos += sizeof(THEO_SAVE_MAPS_IN_3019); name = res::path::load(util::loadString(tsmi3019->texture_name)).remove_ext(); } else { const THEO_SAVE_MAPS_IN * tsmi = reinterpret_cast<const THEO_SAVE_MAPS_IN *>(adr + pos); pos += sizeof(THEO_SAVE_MAPS_IN); name = res::path::load(util::loadString(tsmi->texture_name)).remove_ext(); } if(!name.empty()) { eerie->texturecontainer[i] = TextureContainer::Load(txpath / name, TextureContainer::Level); } } } } pos = pth->object_seek; loadObjectData(eerie, adr, &pos, pth->version); eerie->angle = Anglef::ZERO; eerie->pos = Vec3f_ZERO; // NORMALS CALCULATIONS //Compute Faces Areas for(size_t i = 0; i < eerie->facelist.size(); i++) { const Vec3f & p0 = eerie->vertexlist[eerie->facelist[i].vid[0]].v; const Vec3f & p1 = eerie->vertexlist[eerie->facelist[i].vid[1]].v; const Vec3f & p2 = eerie->vertexlist[eerie->facelist[i].vid[2]].v; eerie->facelist[i].temp = glm::distance((p0 + p1) * .5f, p2) * glm::distance(p0, p1) * .5f; } for(size_t i = 0; i < eerie->facelist.size(); i++) { CalcObjFaceNormal( &eerie->vertexlist[eerie->facelist[i].vid[0]].v, &eerie->vertexlist[eerie->facelist[i].vid[1]].v, &eerie->vertexlist[eerie->facelist[i].vid[2]].v, &eerie->facelist[i] ); float area = eerie->facelist[i].temp; for(long j = 0; j < 3; j++) { float mod = area * area; Vec3f nrml = eerie->facelist[i].norm * mod; float count = mod; for(size_t i2 = 0; i2 < eerie->facelist.size(); i2++) { if(i != i2) { float area2 = eerie->facelist[i].temp; for(long j2 = 0; j2 < 3; j2++) { if(closerThan(eerie->vertexlist[eerie->facelist[i2].vid[j2]].v, eerie->vertexlist[eerie->facelist[i].vid[j]].v, .1f)) { mod = (area2 * area2); nrml += eerie->facelist[i2].norm * mod; count += mod; } } } } count = 1.f / count; eerie->vertexlist[eerie->facelist[i].vid[j]].vert.p = nrml * count; } } for(size_t i = 0; i < eerie->facelist.size(); i++) { for(long j = 0; j < 3; j++) { eerie->vertexlist[eerie->facelist[i].vid[j]].norm = eerie->vertexlist[eerie->facelist[i].vid[j]].vert.p; } } // Apply Normals Spherical correction for NPC head long neck_orgn = GetGroupOriginByName(eerie, "neck"); long head_idx = EERIE_OBJECT_GetGroup(eerie, "head"); if(head_idx >= 0 && neck_orgn >= 0) { VertexGroup & headGroup = eerie->grouplist[head_idx]; Vec3f center = Vec3f_ZERO; Vec3f origin = eerie->vertexlist[neck_orgn].v; float count = (float)headGroup.indexes.size(); if(count > 0.f) { for(size_t idx = 0 ; idx < headGroup.indexes.size(); idx++) { center += eerie->vertexlist[ headGroup.indexes[idx] ].v; } center = (center * (1.f / count) + origin + origin) * (1.0f / 3); float max_threshold = glm::distance(origin, center); for(size_t i = 0; i < headGroup.indexes.size(); i++) { EERIE_VERTEX * ev = &eerie->vertexlist[headGroup.indexes[i]]; float d = glm::distance(ev->v, origin); float factor = 1.f; if(d < max_threshold) { factor = d / max_threshold; } float ifactor = 1.f - factor; Vec3f fakenorm; fakenorm = ev->v - center; fakenorm = glm::normalize(fakenorm); ev->norm = ev->norm * ifactor + fakenorm * factor; ev->norm = glm::normalize(ev->norm); } } } // NORMALS CALCULATIONS END //*********************************************************** eerie->m_skeleton = NULL; EERIE_CreateCedricData(eerie); return eerie; }
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; }
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); }
//*********************************************************************************************** // 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; }