www.pudn.com > 3d_engine.zip > 3DSREAD.C
// Mesh driver for 3ds4 files // Stolen form code of Jare/Iguana #define debug(x) //x #include#include #include #include #include //#include // Needed on SunOS #include "pvision.h" #include "indian.inc" char *_3DS_READER_VERSION="0.61b"; static PVWorld *zePVWorld; typedef unsigned char byte; typedef unsigned short word; typedef unsigned long dword; typedef struct { word id; dword len; } TChunkHeader, *PChunkHeader; enum { CHUNK_M3D_VERSION = 0x0002, CHUNK_MESH_VERSION = 0x3D3E, CHUNK_RGBF = 0x0010, CHUNK_RGBB = 0x0011, // CHUNK_RBGB2 = 0x0012, // ?? NOT HLS. CHUNK_MAIN = 0x4D4D, CHUNK_OBJMESH = 0x3D3D, CHUNK_BKGCOLOR = 0x1200, CHUNK_AMBCOLOR = 0x2100, CHUNK_OBJBLOCK = 0x4000, CHUNK_OBJHIDDEN = 0x4010, CHUNK_TRIMESH = 0x4100, CHUNK_VERTLIST = 0x4110, CHUNK_FACELIST = 0x4120, CHUNK_FACEMAT = 0x4130, CHUNK_MAPLIST = 0x4140, CHUNK_SMOOLIST = 0x4150, CHUNK_TRMATRIX = 0x4160, CHUNK_LIGHT = 0x4600, CHUNK_SPOTLIGHT = 0x4610, CHUNK_CAMERA = 0x4700, CHUNK_MATERIAL = 0xAFFF, CHUNK_MATNAME = 0xA000, CHUNK_AMBIENT = 0xA010, CHUNK_DIFFUSE = 0xA020, CHUNK_SPECULAR = 0xA030, CHUNK_TEXTURE = 0xA200, CHUNK_BUMPMAP = 0xA230, CHUNK_MAPFILE = 0xA300, CHUNK_KEYFRAMER = 0xB000, CHUNK_AMBIANT_TAG = 0xB001, CHUNK_OBJECT_TAG = 0xB002, CHUNK_CAMERA_TAG = 0xB003, CHUNK_TARGET_TAG = 0xB004, CHUNK_LIGHT_TAG = 0xB005, CHUNK_L_TARGET_TAG = 0xB006, CHUNK_SPOTLIGHT_TAG=0xB007, CHUNK_FRAMES = 0xB008, CHUNK_KFCURTIME = 0xB009, CHUNK_KFHDR = 0xB00A, CHUNK_NODE_HDR = 0xB010, CHUNK_INSTANCE_NAME = 0xB011, CHUNK_PRESCALE = 0xB012, CHUNK_PIVOT =0xB013, CHUNK_BOUNDBOX = 0xB014, CHUNK_MORPH_SMOOTH = 0xB015, CHUNK_POS_TRACK_TAG = 0xB020, CHUNK_ROT_TRACK_TAG = 0xB021, CHUNK_SCL_TRACK_TAG = 0xB022, CHUNK_FOV_TRACK_TAG = 0xB023, CHUNK_ROLL_TRACK_TAG = 0xB024, CHUNK_NODE_ID = 0xB030, }; ///////////////////////////////////////////////////////////////////////// // Lecture 3ds ///////////////////////////////////////////////////////////////////////// // Util pour tout le monde static void ReadASCIIZ(FILE *f,char name[255]) { char c[2]; c[1]='\0'; // Read ASCIIZ object name while ( (c[0] = fgetc(f)) != EOF && c[0] != '\0') { c[0]=toupper(c[0]); strcat(name,c); } } // Forward declaration. static int ChunkReader(FILE *f, long p); static int SkipReader(FILE *f, long p) { return COOL; } static int ObjBlockReader (FILE *f, long p) { char name[255]="\0"; PVMesh *no; ReadASCIIZ(f,name); debug(printf("\nAcquiring object : %s\n",name);) // Cehck if preceding allocated object was a true object if ((zePVWorld->Objs!=NULL) && (zePVWorld->Objs->NbrVertexes==0)) { debug(printf("Killed : %s\n",zePVWorld->Objs->Name);); free(zePVWorld->Objs->Name); no=zePVWorld->Objs; } else { if ((no=PV_CreateMesh())==NULL) return NO_MEMORY; PV_AddMesh(zePVWorld,no); } no->Name=strdup(name); // Read rest of chunks inside this one. return ChunkReader(f, p); } static int ObjHiddenReader(FILE *f, long p) { PVMesh *no=zePVWorld->Objs; debug(printf("Hidden\n");) no->Flags|=MESH_FORGET; return COOL; } static int VertListReader (FILE *f, long p) { word nv; float c[3]; PVMesh *no=zePVWorld->Objs; unsigned i; if (fread(&nv, sizeof(nv), 1, f) != 1) return BIZAR_ERROR; nv=Indians(nv); debug(printf("Acquiring vertices: %d\n", nv);) no->NbrVertexes=nv; zePVWorld->NbrVertexes+=nv; // Mem alloc if ( (no->Vertex=(PVVertex *)calloc(sizeof(PVVertex),nv))==NULL ) return NO_MEMORY; if ( (no->Rotated=(Point *)malloc(sizeof(Point)*(nv+NBR_CLIP_VERTEX)))==NULL ) return NO_MEMORY; if ( (no->Projected=(PVScreenPoint *)malloc(sizeof(PVScreenPoint)*(nv+NBR_CLIP_VERTEX)))==NULL ) return NO_MEMORY; while (nv-- > 0) { if (fread(&c, sizeof(c), 1, f) != 1) return BIZAR_ERROR; for(i=0;i<3;i++) c[i]=Indianf(c[i]); no->Vertex[no->NbrVertexes-nv-1].xf=c[0]; no->Vertex[no->NbrVertexes-nv-1].yf=-c[2]; no->Vertex[no->NbrVertexes-nv-1].zf=-c[1]; no->Vertex[no->NbrVertexes-nv-1].bf=c[0]*-c[2]; no->Vertex[no->NbrVertexes-nv-1].Flags=0; } return COOL; } static int FaceListReader (FILE *f, long p) { word nv; word c[4]; PVMesh *no=zePVWorld->Objs; unsigned i; if (fread(&nv, sizeof(nv), 1, f) != 1) return BIZAR_ERROR; nv=Indians(nv); debug(printf("Acquiring faces: %d\n", nv);) // Allocation des faces if ((no->Face=(PVFace *)malloc(sizeof(PVFace)*(nv+NBR_CLIP_FACE)) )==NULL ) return NO_MEMORY; no->NbrFaces=nv; zePVWorld->NbrFaces+=nv; // Le reste if ( (no->Visible=(PVFace **)malloc(sizeof(PVFace*)*(nv+NBR_CLIP_FACE)))==NULL ) return NO_MEMORY; while (nv-- > 0) { if (fread(&c, sizeof(c), 1, f) != 1) return BIZAR_ERROR; for(i=0;i<4;i++) c[i]=Indians(c[i]); no->Face[no->NbrFaces-nv-1].Flags=0; no->Face[no->NbrFaces-nv-1].Material=NULL; no->Face[no->NbrFaces-nv-1].V[0]=c[0]; no->Face[no->NbrFaces-nv-1].V[1]=c[1]; no->Face[no->NbrFaces-nv-1].V[2]=c[2]; no->Face[no->NbrFaces-nv-1].Father=no; if ((c[3] & 0x08)!=0) no->Face[no->NbrFaces-nv-1].Flags+=U_WRAP; if ((c[3] & 0x10)!=0) no->Face[no->NbrFaces-nv-1].Flags+=V_WRAP; no->Face[no->NbrFaces-nv-1].Material=NULL; no->Face[no->NbrFaces-nv-1].MaterialInfo=NULL; } // Calcul des normales PV_MeshNormCalc(no); // Et des boites englobantes PV_MeshBuildBoxes(no); // Read rest of chunks inside this one. return ChunkReader(f, p); } static int MapListReader (FILE *f, long p) { word nv,n; float c[2]; PVMesh *no=zePVWorld->Objs; unsigned i; if (fread(&nv, sizeof(nv), 1, f) != 1) return BIZAR_ERROR; nv=Indians(nv); debug(printf("Acquiring Mapping Info...(%d vertexes)\n",nv);) if ((no->Mapping=(PVMapInfo *)malloc(sizeof(PVMapInfo)*(nv+NBR_CLIP_VERTEX)))==NULL ) return NO_MEMORY; n=nv; while (nv-- > 0) { if (fread(&c, sizeof(c), 1, f) != 1) return BIZAR_ERROR; for(i=0;i<2;i++) c[i]=Indianf(c[i]); no->Mapping[n-nv-1].u=c[0]; // On met les textures dans le bon sens no->Mapping[n-nv-1].v=1-c[1]; } return COOL; } static int TrMatrixReader(FILE *f, long p) { float trans[3]; PVMesh *no=zePVWorld->Objs; Mat3x3 t,t2; unsigned i,j; Quat q; float tf; if (fread(&t, sizeof(Mat3x3), 1, f) != 1) return BIZAR_ERROR; for(i=0;i<3;i++) for(j=0;j<3;j++) t[i][j]=Indianf(t[i][j]); debug(printf("Rotation matrix:\n");) debug(printf(" %f, %f, %f\n", t[0][0], t[0][1], t[0][2]);) debug(printf(" %f, %f, %f\n", t[1][0], t[1][1], t[1][2]);) debug(printf(" %f, %f, %f\n", t[2][0], t[2][1], t[2][2]);) if (fread(&trans, sizeof(trans), 1, f) != 1) return BIZAR_ERROR; for(i=0;i<3;i++) trans[i]=Indianf(trans[i]); debug(printf("Pivot: %f, %f, %f\n",trans[0], trans[1], trans[2]);) no->Pivot.xf=trans[0]; no->Pivot.yf=-trans[2]; no->Pivot.zf=-trans[1]; no->Pivot.bf=no->Pivot.xf*no->Pivot.yf; //OrthonormalizeMatrix(t); // Suxx with some 3ds debug(printf("After orthonormalization:\n");) debug(printf(" %f, %f, %f\n", t[0][0], t[0][1], t[0][2]);) debug(printf(" %f, %f, %f\n", t[1][0], t[1][1], t[1][2]);) debug(printf(" %f, %f, %f\n", t[2][0], t[2][1], t[2][2]);) // 3ds SUXXXXXXXXXXXXXXXXXx les boucs MatrixToQuat(t,&q); tf=q.z; q.z=-q.y; q.y=-tf; q.w=-q.w; QuatToMatrix(&q,t2); OrthonormalizeMatrix(t2); debug(printf("After fucking 3ds:\n");) debug(printf(" %f, %f, %f\n", t2[0][0], t2[0][1], t2[0][2]);) debug(printf(" %f, %f, %f\n", t2[1][0], t2[1][1], t2[1][2]);) debug(printf(" %f, %f, %f\n", t2[2][0], t2[2][1], t2[2][2]);) PV_MeshTranslateVertexes(no,-no->Pivot.xf,-no->Pivot.yf,-no->Pivot.zf); PV_MeshRotateVertexes(no,t2); PV_MeshTranslateVertexes(no,no->Pivot.xf,no->Pivot.yf,no->Pivot.zf); no->Matrix[0][0]=t2[0][0]; no->Matrix[0][1]=t2[1][0]; no->Matrix[0][2]=t2[2][0]; no->Matrix[1][0]=t2[0][1]; no->Matrix[1][1]=t2[1][1]; no->Matrix[1][2]=t2[2][1]; no->Matrix[2][0]=t2[0][2]; no->Matrix[2][1]=t2[1][2]; no->Matrix[2][2]=t2[2][2]; return COOL; } static int FaceMatReader (FILE *f, long p) { char name[255]="\0"; word n, nf; // Read ASCIIZ material name ReadASCIIZ(f,name); debug(printf("Acquiring materials (%s)...\n", name);); if (fread(&n, sizeof(n), 1, f) != 1) return BIZAR_ERROR; n=Indians(n); while (n-- > 0) { if (fread(&nf, sizeof(nf), 1, f) != 1) return BIZAR_ERROR; nf=Indians(nf); zePVWorld->Objs->Face[nf].Material=strdup(name); } return COOL; } /* static int LightReader(FILE *f, long p) { float c[3]; PVLight *l; unsigned i; l=PV_CreateLight(PVL_DIRECTIONAL,zePVWorld->Objs->Name); if(l==NULL) return NO_MEMORY; if (fread(&c, sizeof(c), 1, f) != 1) return BIZAR_ERROR; for(i=0;i<3;i++) c[i]=Indianf(c[i]); debug(printf("Light X: %f, Y: %f, Z: %f\n", c[0], c[1], c[2]);); PV_SetLightPosition(l,c[0],-c[2],-c[1]); PV_AddLight(zePVWorld,l); return ChunkReader(f, p); } static int RGBFReader (FILE *f, long p) { float c[3]; if (fread(&c, sizeof(c), 1, f) != 1) return BIZAR_ERROR; printf(" Red: %f, Green: %f, Blue: %f\n", c[0], c[1], c[2]); return COOL; } */ /* void SmooListReader (FILE *f, int ind, long p) { dword s; int i; while (ftell(f) < p) { if (fread(&s, sizeof(s), 1, f) != 1) return; printf("%*sSmoothing groups: ", ind, ""); for (i = 0; i < 32; i++) if (s & (1 << i)) printf("%d, ", i + 1); printf("\n"); } } void SpotLightReader(FILE *f, int ind, long p) { float c[5]; if (fread(&c, sizeof(c), 1, f) != 1) return; printf("%*s Target X: %f, Y: %f, Z: %f; Hotspot %f, Falloff %f\n", ind, "", c[0], c[1], c[2], c[3], c[4]); } */ // ------------------------------------ static struct { word id; int (*func)(FILE *f, long p); } ChunkNames[] = { //{CHUNK_RGBF, RGBFReader}, //{CHUNK_RGBB, SkipReader}, //{CHUNK_M3D_VERSION, SkipReader}, //{CHUNK_MESH_VERSION, SkipReader}, {CHUNK_MAIN, NULL}, {CHUNK_OBJMESH, NULL}, //{CHUNK_BKGCOLOR, SkipReader}, //{CHUNK_AMBCOLOR, SkipReader}, {CHUNK_OBJBLOCK, ObjBlockReader}, {CHUNK_OBJHIDDEN, ObjHiddenReader}, {CHUNK_TRIMESH, NULL}, {CHUNK_VERTLIST, VertListReader}, {CHUNK_FACELIST, FaceListReader}, {CHUNK_FACEMAT, FaceMatReader}, {CHUNK_MAPLIST, MapListReader}, //{CHUNK_SMOOLIST, SkipReader}, {CHUNK_TRMATRIX, TrMatrixReader}, //{CHUNK_LIGHT, LightReader}, //{CHUNK_SPOTLIGHT, "Spotlight", SpotLightReader}, //{CHUNK_CAMERA, "Camera", CameraReader}, //{CHUNK_LIGHT, SkipReader}, //{CHUNK_SPOTLIGHT, SkipReader}, //{CHUNK_CAMERA, SkipReader}, //{CHUNK_MATERIAL, NULL}, //{CHUNK_MATNAME, SkipReader}, //{CHUNK_AMBIENT, SkipReader}, //{CHUNK_DIFFUSE, SkipReader}, //{CHUNK_SPECULAR, SkipReader}, //{CHUNK_TEXTURE, SkipReader}, //{CHUNK_BUMPMAP, SkipReader}, //{CHUNK_MAPFILE, SkipReader}, //{CHUNK_KEYFRAMER, SkipReader}, //{CHUNK_FRAMES, SkipReader}, //{CHUNK_AMBIANT_TAG,SkipReader}, //{CHUNK_OBJECT_TAG, NULL}, //{CHUNK_CAMERA_TAG, NULL}, //{CHUNK_TARGET_TAG, NULL}, //{CHUNK_LIGHT_TAG, SkipReader}, //{CHUNK_L_TARGET_TAG, SkipReader}, //{CHUNK_SPOTLIGHT_TAG, SkipReader}, //{CHUNK_KFCURTIME, SkipReader}, //{CHUNK_KFHDR, NULL}, //{CHUNK_NODE_HDR, SkipReader}, /*{CHUNK_INSTANCE_NAME, NULL}, {CHUNK_PRESCALE, NULL}, {CHUNK_PIVOT, SkipReader}, {CHUNK_BOUNDBOX, NULL}, {CHUNK_MORPH_SMOOTH, SkipReader}, {CHUNK_POS_TRACK_TAG, SkipReader}, {CHUNK_ROT_TRACK_TAG, SkipReader}, {CHUNK_SCL_TRACK_TAG, SkipReader}, {CHUNK_FOV_TRACK_TAG, SkipReader}, {CHUNK_ROLL_TRACK_TAG, SkipReader}, {CHUNK_NODE_ID, SkipReader},*/ }; static int FindChunk(word id) { int i; for (i = 0; i < sizeof(ChunkNames)/sizeof(ChunkNames[0]); i++) if (id == ChunkNames[i].id) return i; return -1; } // ------------------------------------ static int ChunkReader(FILE *f, long p) { TChunkHeader h; int n,b; long pc; while ((pc=ftell(f)) < p) { if(fread(&h.id,sizeof(h.id),1,f)!=1) break; if(fread(&h.len,sizeof(h.len),1,f)!=1) break; h.id=Indians(h.id); h.len=Indiani(h.len); n = FindChunk(h.id); if (n < 0) { // Chunk inconnu, Hop on saute fseek(f, pc + h.len, SEEK_SET); } else { pc = pc + h.len; if (ChunkNames[n].func != NULL) { if((b=ChunkNames[n].func(f, pc))!=COOL) return b; } else if((b=ChunkReader(f, pc))!=COOL) return b; fseek(f, pc, SEEK_SET); } if (ferror(f)) return FILE_IOERROR; } return COOL; } int PVAPI LoadMeshFrom3DS(char *name,PVWorld *z) { FILE *_3ds; unsigned long fsize; int h; if (z==NULL) return ARG_INVALID; zePVWorld=z; debug(printf("þ 3DStudio Mesh file reader for Panard Vision V%s (Debug Mode Actived)\n",_3DS_READER_VERSION);) if ((_3ds=fopen(name,"rb"))==NULL ) return FILE_IOERROR; fseek(_3ds, 0, SEEK_END); fsize = ftell(_3ds); fseek(_3ds, 0, SEEK_SET); h=ChunkReader(_3ds,fsize); fclose(_3ds); // Kill le dernier mesh si nescessaire if ((zePVWorld->Objs!=NULL) && (zePVWorld->Objs->NbrVertexes==0)) PV_RemoveMeshByPtr(zePVWorld,zePVWorld->Objs); return h; }