int testload( char *filename, unsigned int *failID, int *failpos ) { lwObject *obj; obj = lwGetObject( filename, failID, failpos ); if ( obj ) { printf( "Layers: %d\n" "Surfaces: %d\n" "Envelopes: %d\n" "Clips: %d\n" "Points (first layer): %d\n" "Polygons (first layer): %d\n\n", obj->nlayers, obj->nsurfs, obj->nenvs, obj->nclips, obj->layer->point.count, obj->layer->polygon.count ); nobjects++; nlayers += obj->nlayers; nsurfs += obj->nsurfs; nenvs += obj->nenvs; nclips += obj->nclips; npoints += obj->layer->point.count; npolygons += obj->layer->polygon.count; /* uncomment this to generate vmap output */ print_vmaps( obj ); lwFreeObject( obj ); return 1; } else { printf( "Couldn't load %s.\n", filename ); return 0; } }
lwObject *lwGetObject5( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ) { lwObject *object; lwLayer *layer; lwNode *node; unsigned int id, formsize, type, cksize; /* open the file */ if ( !fp ) return NULL; /* read the first 12 bytes */ set_flen( 0 ); id = getU4( fp ); formsize = getU4( fp ); type = getU4( fp ); if ( 12 != get_flen() ) { return NULL; } /* LWOB? */ if ( id != ID_FORM || type != ID_LWOB ) { if ( failpos ) *failpos = 12; return NULL; } /* allocate an object and a default layer */ object = _pico_calloc( 1, sizeof( lwObject )); if ( !object ) goto Fail; layer = _pico_calloc( 1, sizeof( lwLayer )); if ( !layer ) goto Fail; object->layer = layer; object->nlayers = 1; /* get the first chunk header */ id = getU4( fp ); cksize = getU4( fp ); if ( 0 > get_flen() ) goto Fail; /* process chunks as they're encountered */ while ( 1 ) { cksize += cksize & 1; switch ( id ) { case ID_PNTS: if ( !lwGetPoints( fp, cksize, &layer->point )) goto Fail; break; case ID_POLS: if ( !lwGetPolygons5( fp, cksize, &layer->polygon, layer->point.offset )) goto Fail; break; case ID_SRFS: if ( !lwGetTags( fp, cksize, &object->taglist )) goto Fail; break; case ID_SURF: node = ( lwNode * ) lwGetSurface5( fp, cksize, object ); if ( !node ) goto Fail; lwListAdd( (void *) &object->surf, node ); object->nsurfs++; break; default: _pico_memstream_seek( fp, cksize, PICO_SEEK_CUR ); break; } /* end of the file? */ if ( formsize <= _pico_memstream_tell( fp ) - 8 ) break; /* get the next chunk header */ set_flen( 0 ); id = getU4( fp ); cksize = getU4( fp ); if ( 8 != get_flen() ) goto Fail; } lwGetBoundingBox( &layer->point, layer->bbox ); lwGetPolyNormals( &layer->point, &layer->polygon ); if ( !lwGetPointPolygons( &layer->point, &layer->polygon )) goto Fail; if ( !lwResolvePolySurfaces( &layer->polygon, &object->taglist, &object->surf, &object->nsurfs )) goto Fail; lwGetVertNormals( &layer->point, &layer->polygon ); return object; Fail: if ( failID ) *failID = id; if ( fp ) { if ( failpos ) *failpos = _pico_memstream_tell( fp ); } lwFreeObject( object ); return NULL; }
lwObject *lwGetObject( char *filename, unsigned int *failID, int *failpos ) { FILE *fp = NULL; lwObject *object; lwLayer *layer; lwNode *node; unsigned int id, formsize, type, cksize; int i, rlen; /* open the file */ fp = fopen( filename, "rb" ); if ( !fp ) return NULL; /* read the first 12 bytes */ set_flen( 0 ); id = getU4( fp ); formsize = getU4( fp ); type = getU4( fp ); if ( 12 != get_flen() ) { fclose( fp ); return NULL; } /* is this a LW object? */ if ( id != ID_FORM ) { fclose( fp ); if ( failpos ) *failpos = 12; return NULL; } if ( type != ID_LWO2 ) { fclose( fp ); if ( type == ID_LWOB ) return lwGetObject5( filename, failID, failpos ); else { if ( failpos ) *failpos = 12; return NULL; } } /* allocate an object and a default layer */ object = calloc( 1, sizeof( lwObject )); if ( !object ) goto Fail; layer = calloc( 1, sizeof( lwLayer )); if ( !layer ) goto Fail; object->layer = layer; /* get the first chunk header */ id = getU4( fp ); cksize = getU4( fp ); if ( 0 > get_flen() ) goto Fail; /* process chunks as they're encountered */ while ( 1 ) { cksize += cksize & 1; switch ( id ) { case ID_LAYR: if ( object->nlayers > 0 ) { layer = calloc( 1, sizeof( lwLayer )); if ( !layer ) goto Fail; lwListAdd( &object->layer, layer ); } object->nlayers++; set_flen( 0 ); layer->index = getU2( fp ); layer->flags = getU2( fp ); layer->pivot[ 0 ] = getF4( fp ); layer->pivot[ 1 ] = getF4( fp ); layer->pivot[ 2 ] = getF4( fp ); layer->name = getS0( fp ); rlen = get_flen(); if ( rlen < 0 || rlen > cksize ) goto Fail; if ( rlen <= cksize - 2 ) layer->parent = getU2( fp ); if ( rlen < cksize ) fseek( fp, cksize - rlen, SEEK_CUR ); break; case ID_PNTS: if ( !lwGetPoints( fp, cksize, &layer->point )) goto Fail; break; case ID_POLS: if ( !lwGetPolygons( fp, cksize, &layer->polygon, layer->point.offset )) goto Fail; break; case ID_VMAP: case ID_VMAD: node = ( lwNode * ) lwGetVMap( fp, cksize, layer->point.offset, layer->polygon.offset, id == ID_VMAD ); if ( !node ) goto Fail; lwListAdd( &layer->vmap, node ); layer->nvmaps++; break; case ID_PTAG: if ( !lwGetPolygonTags( fp, cksize, &object->taglist, &layer->polygon )) goto Fail; break; case ID_BBOX: set_flen( 0 ); for ( i = 0; i < 6; i++ ) layer->bbox[ i ] = getF4( fp ); rlen = get_flen(); if ( rlen < 0 || rlen > cksize ) goto Fail; if ( rlen < cksize ) fseek( fp, cksize - rlen, SEEK_CUR ); break; case ID_TAGS: if ( !lwGetTags( fp, cksize, &object->taglist )) goto Fail; break; case ID_ENVL: node = ( lwNode * ) lwGetEnvelope( fp, cksize ); if ( !node ) goto Fail; lwListAdd( &object->env, node ); object->nenvs++; break; case ID_CLIP: node = ( lwNode * ) lwGetClip( fp, cksize ); if ( !node ) goto Fail; lwListAdd( &object->clip, node ); object->nclips++; break; case ID_SURF: node = ( lwNode * ) lwGetSurface( fp, cksize ); if ( !node ) goto Fail; lwListAdd( &object->surf, node ); object->nsurfs++; break; case ID_DESC: case ID_TEXT: case ID_ICON: default: fseek( fp, cksize, SEEK_CUR ); break; } /* end of the file? */ if ( formsize <= ftell( fp ) - 8 ) break; /* get the next chunk header */ set_flen( 0 ); id = getU4( fp ); cksize = getU4( fp ); if ( 8 != get_flen() ) goto Fail; } fclose( fp ); fp = NULL; if ( object->nlayers == 0 ) object->nlayers = 1; layer = object->layer; while ( layer ) { lwGetBoundingBox( &layer->point, layer->bbox ); lwGetPolyNormals( &layer->point, &layer->polygon ); if ( !lwGetPointPolygons( &layer->point, &layer->polygon )) goto Fail; if ( !lwResolvePolySurfaces( &layer->polygon, &object->taglist, &object->surf, &object->nsurfs )) goto Fail; lwGetVertNormals( &layer->point, &layer->polygon ); if ( !lwGetPointVMaps( &layer->point, layer->vmap )) goto Fail; if ( !lwGetPolyVMaps( &layer->polygon, layer->vmap )) goto Fail; layer = layer->next; } return object; Fail: if ( failID ) *failID = id; if ( fp ) { if ( failpos ) *failpos = ftell( fp ); fclose( fp ); } lwFreeObject( object ); return NULL; }
bool CEditableObject::Import_LWO(const char* fn, bool bNeedOptimize) { lwObject *I=0; // UI->SetStatus("Importing..."); // UI->ProgressStart(100,"Read file:"); // UI->ProgressUpdate(1); string512 fname; strcpy(fname,fn); #ifdef _EDITOR I=LWO_ImportObject(fname,I); #else unsigned int failID; int failpos; I = lwGetObject( fname, &failID, &failpos ); #endif // UI->ProgressUpdate(100); if (I){ bool bResult=true; ELog.Msg( mtInformation, "CEditableObject: import lwo %s...", fname ); // parse lwo object { m_Meshes.reserve (I->nlayers); m_Surfaces.reserve (I->nsurfs); // surfaces st_lwSurface* Isf=0; { int i=0; // UI->ProgressStart(I->nsurfs,"Check surf:"); for (Isf=I->surf; Isf; Isf=Isf->next){ // UI->ProgressUpdate(i); Isf->alpha_mode=i; // перетираем для внутренних целей !!! CSurface* Osf = new CSurface(); m_Surfaces.push_back(Osf); if (Isf->name&&Isf->name[0]) Osf->SetName(Isf->name); else Osf->SetName("Default"); Osf->m_Flags.set(CSurface::sf2Sided,(Isf->sideflags==3)?TRUE:FALSE); AnsiString en_name="default", lc_name="default", gm_name="default"; XRShader* sh_info = 0; if (Isf->nshaders&&(stricmp(Isf->shader->name,SH_PLUGIN_NAME)==0)){ sh_info = (XRShader*)Isf->shader->data; en_name = sh_info->en_name; lc_name = sh_info->lc_name; gm_name = sh_info->gm_name; }else ELog.Msg(mtError,"CEditableObject: Shader not found on surface '%s'.",Osf->_Name()); #ifdef _EDITOR if (!Device.Resources->_FindBlender(en_name.c_str())){ ELog.Msg(mtError,"CEditableObject: Render shader '%s' - can't find in library.\nUsing 'default' shader on surface '%s'.", en_name.c_str(), Osf->_Name()); en_name = "default"; } if (!Device.ShaderXRLC.Get(lc_name.c_str())){ ELog.Msg(mtError,"CEditableObject: Compiler shader '%s' - can't find in library.\nUsing 'default' shader on surface '%s'.", lc_name.c_str(), Osf->_Name()); lc_name = "default"; } if (!GMLib.GetMaterial(gm_name.c_str())){ ELog.Msg(mtError,"CEditableObject: Game material '%s' - can't find in library.\nUsing 'default' material on surface '%s'.", lc_name.c_str(), Osf->_Name()); gm_name = "default"; } #endif // fill texture layers int cidx; st_lwClip* Icl; u32 dwNumTextures=0; for (st_lwTexture* Itx=Isf->color.tex; Itx; Itx=Itx->next){ string1024 tname=""; dwNumTextures++; cidx = -1; if (Itx->type==ID_IMAP) cidx=Itx->param.imap.cindex; else{ ELog.DlgMsg(mtError, "Import LWO (Surface '%s'): 'Texture' is not Image Map!",Osf->_Name()); bResult=false; break; } if (cidx!=-1){ // get textures for (Icl=I->clip; Icl; Icl=Icl->next) if ((cidx==Icl->index)&&(Icl->type==ID_STIL)){ strcpy(tname,Icl->source.still.name); break; } if (tname[0]==0){ ELog.DlgMsg(mtError, "Import LWO (Surface '%s'): 'Texture' name is empty or non 'STIL' type!",Osf->_Name()); bResult=false; break; } string256 tex_name; _splitpath( tname, 0, 0, tex_name, 0 ); Osf->SetTexture(EFS.AppendFolderToName(tex_name,1,TRUE)); // get vmap refs Osf->SetVMap(Itx->param.imap.vmap_name); } } if (!bResult) break; if (!Osf->_VMap()||!Osf->_VMap()[0]){ ELog.DlgMsg(mtError, "Invalid surface '%s'. VMap empty.",Osf->_Name()); bResult = false; break; } if (!Osf->_Texture()||!Osf->_Texture()[0]){ ELog.DlgMsg(mtError, "Can't create shader. Invalid surface '%s'. Textures empty.",Osf->_Name()); bResult = false; break; } if (en_name.c_str()==0){ ELog.DlgMsg(mtError, "Can't create shader. Invalid surface '%s'. Shader empty.",Osf->_Name()); bResult = false; break; } Osf->SetShader (en_name.c_str()); Osf->SetShaderXRLC (lc_name.c_str()); Osf->SetGameMtl (gm_name.c_str()); Osf->SetFVF (D3DFVF_XYZ|D3DFVF_NORMAL|(dwNumTextures<<D3DFVF_TEXCOUNT_SHIFT)); i++; } } if (bResult){ // mesh layers st_lwLayer* Ilr=0; int k=0; for (Ilr=I->layer; Ilr; Ilr=Ilr->next){ // create new mesh CEditableMesh* MESH= new CEditableMesh(this); m_Meshes.push_back(MESH); if (Ilr->name) MESH->SetName(Ilr->name); else MESH->SetName(""); MESH->m_Box.set(Ilr->bbox[0],Ilr->bbox[1],Ilr->bbox[2], Ilr->bbox[3],Ilr->bbox[4],Ilr->bbox[5]); // parse mesh(lwo-layer) data // vmaps st_lwVMap* Ivmap=0; int vmap_count=0; if (Ilr->nvmaps==0){ ELog.DlgMsg(mtError, "Import LWO: Mesh layer must contain UV!"); bResult=false; break; } // индексы соответствия импортируемых мап static VMIndexLink VMIndices; VMIndices.clear(); for (Ivmap=Ilr->vmap; Ivmap; Ivmap=Ivmap->next){ switch(Ivmap->type){ case ID_TXUV:{ if (Ivmap->dim!=2){ ELog.DlgMsg(mtError, "Import LWO: 'UV Map' must contain 2 value!"); bResult=false; break; } MESH->m_VMaps.push_back(new st_VMap(Ivmap->name,vmtUV,!!Ivmap->perpoly)); st_VMap* Mvmap=MESH->m_VMaps.back(); int vcnt=Ivmap->nverts; // VMap Mvmap->copyfrom(*Ivmap->val,vcnt); // flip uv for (int k=0; k<Mvmap->size(); k++){ Fvector2& uv = Mvmap->getUV(k); uv.y=1.f-uv.y; } // vmap index VMIndices[Ivmap] = vmap_count++; }break; case ID_WGHT:{ if (Ivmap->dim!=1){ ELog.DlgMsg(mtError, "Import LWO: 'Weight' must contain 1 value!"); bResult=false; break; } MESH->m_VMaps.push_back(new st_VMap(Ivmap->name,vmtWeight,false)); st_VMap* Mvmap=MESH->m_VMaps.back(); int vcnt=Ivmap->nverts; // VMap Mvmap->copyfrom(*Ivmap->val,vcnt); // vmap index VMIndices[Ivmap] = vmap_count++; }break; case ID_PICK: ELog.Msg(mtError,"Found 'PICK' VMAP. Import failed."); bResult = false; break; case ID_MNVW: ELog.Msg(mtError,"Found 'MNVW' VMAP. Import failed."); bResult = false; break; case ID_MORF: ELog.Msg(mtError,"Found 'MORF' VMAP. Import failed."); bResult = false; break; case ID_SPOT: ELog.Msg(mtError,"Found 'SPOT' VMAP. Import failed."); bResult = false; break; case ID_RGB: ELog.Msg(mtError,"Found 'RGB' VMAP. Import failed."); bResult = false; break; case ID_RGBA: ELog.Msg(mtError,"Found 'RGBA' VMAP. Import failed."); bResult = false; break; } if (!bResult) break; } if (!bResult) break; // points // UI->ProgressStart(Ilr->point.count,"Fill points:"); { MESH->m_VertCount = Ilr->point.count; MESH->m_Vertices = xr_alloc<Fvector>(MESH->m_VertCount); int id = Ilr->polygon.count/50; if (id==0) id = 1; for (int i=0; i<Ilr->point.count; ++i) { st_lwPoint& Ipt = Ilr->point.pt[i]; Fvector& Mpt = MESH->m_Vertices[i]; Mpt.set (Ipt.pos); } } if (!bResult) break; // polygons MESH->m_FaceCount = Ilr->polygon.count; MESH->m_Faces = xr_alloc<st_Face>(MESH->m_FaceCount); MESH->m_SmoothGroups = xr_alloc<u32>(MESH->m_FaceCount); Memory.mem_fill32 (MESH->m_SmoothGroups,u32(-1),MESH->m_FaceCount); MESH->m_VMRefs.reserve (Ilr->polygon.count*3); IntVec surf_ids; surf_ids.resize(Ilr->polygon.count); int id = Ilr->polygon.count/50; if (id==0) id = 1; for (int i=0; i<Ilr->polygon.count; ++i) { st_Face& Mpol=MESH->m_Faces[i]; st_lwPolygon& Ipol=Ilr->polygon.pol[i]; if (Ipol.nverts!=3) { ELog.DlgMsg(mtError, "Import LWO: Face must contain only 3 vertices!"); bResult=false; break; } for (int pv_i=0; pv_i<3; ++pv_i) { st_lwPolVert& Ipv=Ipol.v[pv_i]; st_FaceVert& Mpv=Mpol.pv[pv_i]; Mpv.pindex =Ipv.index; MESH->m_VMRefs.push_back(st_VMapPtLst()); st_VMapPtLst& m_vm_lst = MESH->m_VMRefs.back(); DEFINE_VECTOR (st_VMapPt,VMapPtVec,VMapPtIt); VMapPtVec vm_lst; Mpv.vmref = MESH->m_VMRefs.size()-1; // parse uv-map int vmpl_cnt =Ipv.nvmaps; st_lwPoint& Ipt =Ilr->point.pt[Mpv.pindex]; int vmpt_cnt =Ipt.nvmaps; if (!vmpl_cnt&&!vmpt_cnt){ ELog.DlgMsg (mtError,"Found mesh without UV's!",0); bResult = false; break; } AStringVec names; if (vmpl_cnt){ // берем из poly for (int vm_i=0; vm_i<vmpl_cnt; vm_i++){ if (Ipv.vm[vm_i].vmap->type!=ID_TXUV) continue; vm_lst.push_back(st_VMapPt()); st_VMapPt& pt = vm_lst.back(); pt.vmap_index = VMIndices[Ipv.vm[vm_i].vmap];// номер моей VMap names.push_back (Ipv.vm[vm_i].vmap->name); pt.index = Ipv.vm[vm_i].index; } } if (vmpt_cnt){ // берем из points for (int vm_i=0; vm_i<vmpt_cnt; vm_i++){ if (Ipt.vm[vm_i].vmap->type!=ID_TXUV) continue; if (std::find(names.begin(),names.end(),Ipt.vm[vm_i].vmap->name)!=names.end()) continue; vm_lst.push_back(st_VMapPt()); st_VMapPt& pt = vm_lst.back(); pt.vmap_index = VMIndices[Ipt.vm[vm_i].vmap]; // номер моей VMap pt.index = Ipt.vm[vm_i].index; } } std::sort(vm_lst.begin(),vm_lst.end(),CompareFunc); // parse weight-map int vm_cnt =Ipt.nvmaps; for (int vm_i=0; vm_i<vm_cnt; vm_i++){ if (Ipt.vm[vm_i].vmap->type!=ID_WGHT) continue; vm_lst.push_back(st_VMapPt()); st_VMapPt& pt = vm_lst.back(); pt.vmap_index = VMIndices[Ipt.vm[vm_i].vmap]; // номер моей VMap pt.index = Ipt.vm[vm_i].index; } m_vm_lst.count = vm_lst.size(); m_vm_lst.pts = xr_alloc<st_VMapPt>(m_vm_lst.count); Memory.mem_copy (m_vm_lst.pts,&*vm_lst.begin(),m_vm_lst.count*sizeof(st_VMapPt)); } if (!bResult) break; // Ipol.surf->alpha_mode - заполнено как номер моего surface surf_ids[i] = Ipol.surf->alpha_mode; } if (!bResult) break; for (u32 pl_id=0; pl_id<MESH->GetFCount(); pl_id++) MESH->m_SurfFaces[m_Surfaces[surf_ids[pl_id]]].push_back(pl_id); if (!bResult) break; k++; //MESH->DumpAdjacency(); if (bNeedOptimize) MESH->OptimizeMesh(false); //MESH->DumpAdjacency(); MESH->RebuildVMaps(); // !!!!!! } } } #ifdef _EDITOR LWO_CloseFile(I); #else lwFreeObject(I); #endif // UI->ProgressEnd(); // UI->SetStatus(""); if (bResult) VerifyMeshNames(); else ELog.DlgMsg(mtError,"Can't parse LWO object."); if (bResult) m_LoadName = (strext(fname))? strcpy(strext(fname),".object"):strcat(strext(fname),".object"); return bResult; }else ELog.DlgMsg(mtError,"Can't import LWO object file."); // UI->ProgressEnd(); // UI->SetStatus(""); return false; }
mesh_t *LoadLWO(char *filename) { unsigned int failID = 0; int failpos; char *sfailID[5]; mesh_t *mesh; lwObject *lwobj = lwGetObject5(filename, &failID, &failpos); memset(sfailID, 0, 5); memcpy(sfailID, &failID, 4); if(failID > 0) printf("failID: %s\n", sfailID); if(lwobj != 0) { //printf("nlayers : %i\n", lwobj->nlayers); if(lwobj->nlayers > 1) return 0; // Read layers and polygons mesh = new mesh_t; int ti = 0; for(int l = 0; l < lwobj->nlayers; l++) { lwPolygonList *polylist = &lwobj->layer[l].polygon; lwPointList *pointlist = &lwobj->layer[l].point; // printf("poly count: %i\n", polylist->count); // printf("point count: %i\n", pointlist->count); int tri_count = 0; for(int p = 0; p < polylist->count; p++) { lwPolygon *poly = &polylist->pol[p]; if(poly->nverts >= 3) { tri_count += (poly->nverts-2); } } mesh->numtris = tri_count; // Allocate mesh->tris = new tri_t[mesh->numtris]; mesh->norms = new norm_t[mesh->numtris]; mesh->c = new col_t[mesh->numtris]; //printf("numtries: %i\n", mesh->numtris); lwPoint *point = pointlist->pt; for(int p = 0; p < polylist->count; p++) { // printf("poly nverts: %i\n", poly->nverts); lwPolygon *poly = &polylist->pol[p]; // printf("surf name: %s\n", poly->surf->name); if(poly->nverts == 3) { lwPoint *v1 = &point[ poly->v[0].index ]; lwPoint *v2 = &point[ poly->v[1].index ]; lwPoint *v3 = &point[ poly->v[2].index ]; float *n1 = poly->v[0].norm; float *n2 = poly->v[1].norm; float *n3 = poly->v[2].norm; SetTri(mesh, ti, v1, v2, v3, n1, n2, n3, poly->surf->color.rgb); ti++; } else { if(poly->nverts > 3) { lwPolygon *poly = &polylist->pol[p]; lwPoint *v1 = &point[ poly->v[0].index ]; lwPoint *v2 = &point[ poly->v[1].index ]; lwPoint *v3 = &point[ poly->v[2].index ]; float *n1 = poly->v[0].norm; float *n2 = poly->v[1].norm; float *n3 = poly->v[2].norm; SetTri(mesh, ti, v1, v2, v3, n1, n2, n3, poly->surf->color.rgb); // printf("normal %g, %g, %g\n", poly->v[0].norm[0], poly->v[0].norm[1], poly->v[0].norm[2]); ti++; for(int i=2; i < poly->nverts-1; i++) { lwPoint *v2 = &point[ poly->v[i].index ]; lwPoint *v3 = &point[ poly->v[i+1].index ]; float *n2 = poly->v[i].norm; float *n3 = poly->v[i+1].norm; SetTri(mesh, ti, v1, v2, v3, n1, n2, n3, poly->surf->color.rgb); ti++; } } else { printf("poly nverts: %i\n", poly->nverts); } } } } } else { printf("failID : %i , failpos: %i\n", failID, failpos); } lwFreeObject(lwobj); return mesh; }