//reads a binary file containing a 3d model static polymodel *read_model_file(polymodel *pm,const char *filename,robot_info *r) { short version; int len, next_chunk; ubyte model_buf[MODEL_BUF_SIZE]; auto ifile = PHYSFSX_openReadBuffered(filename); if (!ifile) Error("Can't open file <%s>",filename); Assert(PHYSFS_fileLength(ifile) <= MODEL_BUF_SIZE); Pof_addr = 0; Pof_file_end = PHYSFS_read(ifile, model_buf, 1, PHYSFS_fileLength(ifile)); ifile.reset(); const int model_id = pof_read_int(model_buf); if (model_id != 0x4f505350) /* 'OPSP' */ Error("Bad ID in model file <%s>",filename); version = pof_read_short(model_buf); if (version < PM_COMPATIBLE_VERSION || version > PM_OBJFILE_VERSION) Error("Bad version (%d) in model file <%s>",version,filename); int pof_id; while (new_pof_read_int(pof_id, model_buf) == 1) { pof_id = INTEL_INT(pof_id); //id = pof_read_int(model_buf); len = pof_read_int(model_buf); next_chunk = Pof_addr + len; switch (pof_id) { case ID_OHDR: { //Object header vms_vector pmmin,pmmax; pm->n_models = pof_read_int(model_buf); pm->rad = pof_read_int(model_buf); Assert(pm->n_models <= MAX_SUBMODELS); pof_read_vecs(&pmmin,1,model_buf); pof_read_vecs(&pmmax,1,model_buf); break; } case ID_SOBJ: { //Subobject header int n; n = pof_read_short(model_buf); Assert(n < MAX_SUBMODELS); pm->submodel_parents[n] = pof_read_short(model_buf); pof_read_vecs(&pm->submodel_norms[n],1,model_buf); pof_read_vecs(&pm->submodel_pnts[n],1,model_buf); pof_read_vecs(&pm->submodel_offsets[n],1,model_buf); pm->submodel_rads[n] = pof_read_int(model_buf); //radius pm->submodel_ptrs[n] = pof_read_int(model_buf); //offset break; } #ifndef DRIVE case ID_GUNS: { //List of guns on this object if (r) { vms_vector gun_dir; r->n_guns = pof_read_int(model_buf); Assert(r->n_guns <= MAX_GUNS); for (int i=0;i<r->n_guns;i++) { const uint_fast32_t gun_id = pof_read_short(model_buf); /* * D1 v1.0 boss02.pof has id=4 and r->n_guns==4. * Relax the assert to check only for memory * corruption. */ Assert(gun_id < sizeof(r->gun_submodels) / sizeof(r->gun_submodels[0])); auto &submodel = r->gun_submodels[gun_id]; submodel = pof_read_short(model_buf); Assert(submodel != 0xff); pof_read_vecs(&r->gun_points[gun_id], 1, model_buf); if (version >= 7) pof_read_vecs(&gun_dir,1,model_buf); } } else pof_cfseek(model_buf,len,SEEK_CUR); break; } case ID_ANIM: //Animation data if (r) { unsigned n_frames; n_frames = pof_read_short(model_buf); Assert(n_frames == N_ANIM_STATES); for (int m=0;m<pm->n_models;m++) range_for (auto &f, partial_range(anim_angs, n_frames)) pof_read_angs(&f[m], 1, model_buf); robot_set_angles(r,pm,anim_angs); } else pof_cfseek(model_buf,len,SEEK_CUR); break; #endif case ID_TXTR: { //Texture filename list int n; char name_buf[128]; n = pof_read_short(model_buf); while (n--) { pof_read_string(name_buf,128,model_buf); } break; } case ID_IDTA: //Interpreter data pm->model_data_size = len; pm->model_data = make_unique<ubyte[]>(pm->model_data_size); pof_cfread(pm->model_data.get(),1,len,model_buf); break; default: pof_cfseek(model_buf,len,SEEK_CUR); break; } if ( version >= 8 ) // Version 8 needs 4-byte alignment!!! pof_cfseek(model_buf,next_chunk,SEEK_SET); }
//reads the gun information for a model //fills in arrays gun_points & gun_dirs, returns the number of guns read int read_model_guns(char *filename,vms_vector *gun_points, vms_vector *gun_dirs, int *gun_submodels) { PHYSFS_file *ifile; short version; int id,len; int n_guns=0; ubyte model_buf[MODEL_BUF_SIZE]; if ((ifile=PHYSFSX_openReadBuffered(filename))==NULL) Error("Can't open file <%s>",filename); Assert(PHYSFS_fileLength(ifile) <= MODEL_BUF_SIZE); Pof_addr = 0; Pof_file_end = PHYSFS_read(ifile, model_buf, 1, PHYSFS_fileLength(ifile)); PHYSFS_close(ifile); id = pof_read_int(model_buf); if (id!=0x4f505350) /* 'OPSP' */ Error("Bad ID in model file <%s>",filename); version = pof_read_short(model_buf); Assert(version >= 7); //must be 7 or higher for this data if (version < PM_COMPATIBLE_VERSION || version > PM_OBJFILE_VERSION) Error("Bad version (%d) in model file <%s>",version,filename); while (new_pof_read_int(id,model_buf) == 1) { id = INTEL_INT(id); //id = pof_read_int(model_buf); len = pof_read_int(model_buf); if (id == ID_GUNS) { //List of guns on this object int i; n_guns = pof_read_int(model_buf); for (i=0;i<n_guns;i++) { int id,sm; id = pof_read_short(model_buf); sm = pof_read_short(model_buf); if (gun_submodels) gun_submodels[id] = sm; else if (sm!=0) Error("Invalid gun submodel in file <%s>",filename); pof_read_vecs(&gun_points[id],1,model_buf); pof_read_vecs(&gun_dirs[id],1,model_buf); } } else pof_cfseek(model_buf,len,SEEK_CUR); } return n_guns; }
//reads the gun information for a model //fills in arrays gun_points & gun_dirs, returns the number of guns read int read_model_guns(char *filename,vms_vector *gun_points, vms_vector *gun_dirs, int *gun_submodels) { CFILE *ifile; short version; int id,len; int n_guns=0; ubyte *model_buf; model_buf = (ubyte *)d_malloc( MODEL_BUF_SIZE * sizeof(ubyte) ); if (!model_buf) Error("Can't allocate space to read model %s\n", filename); if ((ifile=cfopen(filename,"rb"))==NULL) Error("Can't open file <%s>",filename); Assert(ifile->size <= MODEL_BUF_SIZE); Pof_addr = 0; Pof_file_end = cfread(model_buf, 1, ifile->size, ifile); cfclose(ifile); id = pof_read_int(model_buf); if (id!=0x4f505350) /* 'OPSP' */ Error("Bad ID in model file <%s>",filename); version = pof_read_short(model_buf); Assert(version >= 7); //must be 7 or higher for this data if (version < PM_COMPATIBLE_VERSION || version > PM_OBJFILE_VERSION) Error("Bad version (%d) in model file <%s>",version,filename); while (new_pof_read_int(id,model_buf) == 1) { id = INTEL_INT(id); //id = pof_read_int(model_buf); len = pof_read_int(model_buf); if (id == ID_GUNS) { //List of guns on this object //con_printf(DEBUG_LEVEL, "Got chunk GUNS, len=%d\n",len); int i; n_guns = pof_read_int(model_buf); for (i=0;i<n_guns;i++) { int id,sm; id = pof_read_short(model_buf); sm = pof_read_short(model_buf); if (gun_submodels) gun_submodels[id] = sm; else if (sm!=0) Error("Invalid gun submodel in file <%s>",filename); pof_read_vecs(&gun_points[id],1,model_buf); pof_read_vecs(&gun_dirs[id],1,model_buf); } } else pof_cfseek(model_buf,len,SEEK_CUR); } d_free(model_buf); return n_guns; }
//reads a binary file containing a 3d model polymodel *read_model_file(polymodel *pm,char *filename,robot_info *r) { PHYSFS_file *ifile; short version; int id,len, next_chunk; ubyte model_buf[MODEL_BUF_SIZE]; if ((ifile=PHYSFSX_openReadBuffered(filename))==NULL) Error("Can't open file <%s>",filename); Assert(PHYSFS_fileLength(ifile) <= MODEL_BUF_SIZE); Pof_addr = 0; Pof_file_end = PHYSFS_read(ifile, model_buf, 1, PHYSFS_fileLength(ifile)); PHYSFS_close(ifile); id = pof_read_int(model_buf); if (id!=0x4f505350) /* 'OPSP' */ Error("Bad ID in model file <%s>",filename); version = pof_read_short(model_buf); if (version < PM_COMPATIBLE_VERSION || version > PM_OBJFILE_VERSION) Error("Bad version (%d) in model file <%s>",version,filename); while (new_pof_read_int(id,model_buf) == 1) { id = INTEL_INT(id); //id = pof_read_int(model_buf); len = pof_read_int(model_buf); next_chunk = Pof_addr + len; switch (id) { case ID_OHDR: { //Object header vms_vector pmmin,pmmax; pm->n_models = pof_read_int(model_buf); pm->rad = pof_read_int(model_buf); Assert(pm->n_models <= MAX_SUBMODELS); pof_read_vecs(&pmmin,1,model_buf); pof_read_vecs(&pmmax,1,model_buf); break; } case ID_SOBJ: { //Subobject header int n; n = pof_read_short(model_buf); Assert(n < MAX_SUBMODELS); pm->submodel_parents[n] = pof_read_short(model_buf); pof_read_vecs(&pm->submodel_norms[n],1,model_buf); pof_read_vecs(&pm->submodel_pnts[n],1,model_buf); pof_read_vecs(&pm->submodel_offsets[n],1,model_buf); pm->submodel_rads[n] = pof_read_int(model_buf); //radius pm->submodel_ptrs[n] = pof_read_int(model_buf); //offset break; } #ifndef DRIVE case ID_GUNS: { //List of guns on this object if (r) { int i; vms_vector gun_dir; r->n_guns = pof_read_int(model_buf); Assert(r->n_guns <= MAX_GUNS); for (i=0;i<r->n_guns;i++) { int id; id = pof_read_short(model_buf); r->gun_submodels[id] = pof_read_short(model_buf); Assert(r->gun_submodels[id] != 0xff); pof_read_vecs(&r->gun_points[id],1,model_buf); if (version >= 7) pof_read_vecs(&gun_dir,1,model_buf); } } else pof_cfseek(model_buf,len,SEEK_CUR); break; } case ID_ANIM: //Animation data if (r) { int n_frames,f,m; n_frames = pof_read_short(model_buf); Assert(n_frames == N_ANIM_STATES); for (m=0;m<pm->n_models;m++) for (f=0;f<n_frames;f++) pof_read_angvecs(&anim_angs[f][m], 1, model_buf); robot_set_angles(r,pm,anim_angs); } else pof_cfseek(model_buf,len,SEEK_CUR); break; #endif case ID_TXTR: { //Texture filename list int n; char name_buf[128]; n = pof_read_short(model_buf); while (n--) { pof_read_string(name_buf,128,model_buf); } break; } case ID_IDTA: //Interpreter data pm->model_data = d_malloc(len); pm->model_data_size = len; pof_cfread(pm->model_data,1,len,model_buf); break; default: pof_cfseek(model_buf,len,SEEK_CUR); break; } if ( version >= 8 ) // Version 8 needs 4-byte alignment!!! pof_cfseek(model_buf,next_chunk,SEEK_SET); } #ifdef WORDS_NEED_ALIGNMENT align_polygon_model_data(pm); #endif #ifdef WORDS_BIGENDIAN swap_polygon_model_data(pm->model_data); #endif return pm; }
//reads a binary file containing a 3d model polymodel *read_model_file(polymodel *pm,char *filename,robot_info *r) { CFILE *ifile; short version; int id,len, next_chunk; int anim_flag = 0; ubyte *model_buf; model_buf = (ubyte *)d_malloc( MODEL_BUF_SIZE * sizeof(ubyte) ); if (!model_buf) Error("Can't allocate space to read model %s\n", filename); if ((ifile=cfopen(filename,"rb"))==NULL) Error("Can't open file <%s>",filename); Assert(ifile->size <= MODEL_BUF_SIZE); Pof_addr = 0; Pof_file_end = cfread(model_buf, 1, cfilelength(ifile), ifile); cfclose(ifile); id = pof_read_int(model_buf); if (id!=0x4f505350) /* 'OPSP' */ Error("Bad ID in model file <%s>",filename); version = pof_read_short(model_buf); if (version < PM_COMPATIBLE_VERSION || version > PM_OBJFILE_VERSION) Error("Bad version (%d) in model file <%s>",version,filename); if ( FindArg( "-bspgen" )) printf( "bspgen -c1" ); while (new_pof_read_int(id,model_buf) == 1) { id = INTEL_INT(id); //id = pof_read_int(model_buf); len = pof_read_int(model_buf); next_chunk = Pof_addr + len; switch (id) { case ID_OHDR: { //Object header vms_vector pmmin,pmmax; //con_printf(DEBUG_LEVEL, "Got chunk OHDR, len=%d\n",len); pm->n_models = pof_read_int(model_buf); pm->rad = pof_read_int(model_buf); Assert(pm->n_models <= MAX_SUBMODELS); pof_read_vecs(&pmmin,1,model_buf); pof_read_vecs(&pmmax,1,model_buf); if ( FindArg( "-bspgen" )) { vms_vector v; fix l; vm_vec_sub(&v, &pmmax, &pmmin ); l = v.x; if ( v.y > l ) l = v.y; if ( v.z > l ) l = v.z; printf( " -l%.3f", f2fl(l) ); } break; } case ID_SOBJ: { //Subobject header int n; anim_flag++; //con_printf(DEBUG_LEVEL, "Got chunk SOBJ, len=%d\n",len); n = pof_read_short(model_buf); Assert(n < MAX_SUBMODELS); pm->submodel_parents[n] = pof_read_short(model_buf); pof_read_vecs(&pm->submodel_norms[n],1,model_buf); pof_read_vecs(&pm->submodel_pnts[n],1,model_buf); pof_read_vecs(&pm->submodel_offsets[n],1,model_buf); pm->submodel_rads[n] = pof_read_int(model_buf); //radius pm->submodel_ptrs[n] = pof_read_int(model_buf); //offset break; } #ifndef DRIVE case ID_GUNS: { //List of guns on this object //con_printf(DEBUG_LEVEL, "Got chunk GUNS, len=%d\n",len); if (r) { int i; vms_vector gun_dir; ubyte gun_used[MAX_GUNS]; r->n_guns = pof_read_int(model_buf); if ( r->n_guns ) anim_flag++; Assert(r->n_guns <= MAX_GUNS); for (i=0;i<r->n_guns;i++) gun_used[i] = 0; for (i=0;i<r->n_guns;i++) { int id; id = pof_read_short(model_buf); Assert(id < r->n_guns); Assert(gun_used[id] == 0); gun_used[id] = 1; r->gun_submodels[id] = pof_read_short(model_buf); Assert(r->gun_submodels[id] != 0xff); pof_read_vecs(&r->gun_points[id],1,model_buf); if (version >= 7) pof_read_vecs(&gun_dir,1,model_buf); } } else pof_cfseek(model_buf,len,SEEK_CUR); break; } case ID_ANIM: //Animation data //con_printf(DEBUG_LEVEL, "Got chunk ANIM, len=%d\n",len); anim_flag++; if (r) { int n_frames,f,m; n_frames = pof_read_short(model_buf); Assert(n_frames == N_ANIM_STATES); for (m=0;m<pm->n_models;m++) for (f=0;f<n_frames;f++) pof_read_angs(&anim_angs[f][m], 1, model_buf); robot_set_angles(r,pm,anim_angs); } else pof_cfseek(model_buf,len,SEEK_CUR); break; #endif case ID_TXTR: { //Texture filename list int n; char name_buf[128]; //con_printf(DEBUG_LEVEL, "Got chunk TXTR, len=%d\n",len); n = pof_read_short(model_buf); //con_printf(DEBUG_LEVEL, " num textures = %d\n",n); while (n--) { pof_read_string(name_buf,128,model_buf); //con_printf(DEBUG_LEVEL, "<%s>\n",name_buf); } break; } case ID_IDTA: //Interpreter data //con_printf(DEBUG_LEVEL, "Got chunk IDTA, len=%d\n",len); pm->model_data = d_malloc(len); pm->model_data_size = len; pof_cfread(pm->model_data,1,len,model_buf); break; default: //con_printf(DEBUG_LEVEL, "Unknown chunk <%c%c%c%c>, len = %d\n",id,id>>8,id>>16,id>>24,len); pof_cfseek(model_buf,len,SEEK_CUR); break; } if ( version >= 8 ) // Version 8 needs 4-byte alignment!!! pof_cfseek(model_buf,next_chunk,SEEK_SET); } // for (i=0;i<pm->n_models;i++) // pm->submodel_ptrs[i] += (int) pm->model_data; if ( FindArg( "-bspgen" )) { char *p = strchr( filename, '.' ); *p = 0; if ( anim_flag > 1 ) printf( " -a" ); printf( " %s.3ds\n", filename ); *p = '.'; } d_free(model_buf); #ifdef WORDS_NEED_ALIGNMENT align_polygon_model_data(pm); #endif #ifdef WORDS_BIGENDIAN swap_polygon_model_data(pm->model_data); #endif //verify(pm->model_data); return pm; }