www.pudn.com > 3d_engine.zip > 3DSPM.C
// Animation driver for 3ds4 files // Stolen form code of Jare/Iguana #define debug(x) //x #include#include #include #include #include //#include // Needed on SunOS #include "pmotion.h" #include "pvision.h" #include "3dspm.h" #include "indian.inc" char *_3DS_ANIM_READER_VERSION="0.2b"; static PMotion *zemotion; static PVWorld *zeworld; static int CurrentID; static unsigned CurrentType; static PMNode *CurrentNode; typedef unsigned char byte; typedef unsigned short word; typedef unsigned long dword; #pragma pack(2) typedef struct { word id; dword len; } TChunkHeader, *PChunkHeader; #pragma pack() enum { CHUNK_MAIN = 0x4D4D, CHUNK_KEYFRAMER = 0xB000, CHUNK_AMBIENTKEY = 0xB001, CHUNK_TRACKINFO = 0xB002, CHUNK_TRACKOBJNAME = 0xB010, CHUNK_TRACKPIVOT = 0xB013, CHUNK_TRACKPOS = 0xB020, CHUNK_TRACKROTATE = 0xB021, CHUNK_TRACKSCALE = 0xB022, CHUNK_OBJNUMBER = 0xB030, CHUNK_TRACKCAMERA = 0xB003, CHUNK_TRACKFOV = 0xB023, CHUNK_TRACKROLL = 0xB024, CHUNK_TRACKCAMTGT = 0xB004, CHUNK_TRACKLIGHT = 0xB005, CHUNK_TRACKLIGTGT = 0xB006, CHUNK_TRACKSPOTL = 0xB007, CHUNK_FRAMES = 0xB008, }; ///////////////////////////////////////////////////////////////////////// // Lecture 3ds ///////////////////////////////////////////////////////////////////////// // Util pour tout le monde static void ReadASCIIZ(FILE *f,char *name) { 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); } debug(printf("%s\"\n",name);); } // Forward declaration. static int ChunkReader(FILE *f, long p); static int SkipReader(FILE *f, long p) { return COOL; } // ------------------------------------ KeyFraming static int FramesReader(FILE *f, long p) { dword c[2]; int i; if (fread(&c, sizeof(c), 1, f) != 1) return BIZAR_ERROR; for(i=0;i<2;i++) c[i]=Indiani(c[i]); debug(printf(" Anim Start: %ld, End: %ld\n",c[0], c[1]);); zemotion->MaxTime=c[1]; return COOL; } static int TrackObjNameReader(FILE *f, long p) { int i; word w[2]; word parent; char name[255]="\0"; PMNode *n,*m; void *t; // Read ASCIIZ name debug(printf("Track object name \"");); ReadASCIIZ(f, &name[0]); if (fread(&w, sizeof(w), 1, f) != 1) return BIZAR_ERROR; for(i=0;i<2;i++) w[i]=Indians(w[i]); if (fread(&parent, sizeof(parent), 1, f) != 1) return BIZAR_ERROR; parent=Indians(parent); debug(printf("Object name data: Flags 0x%X, 0x%X, Parent %d\n",w[0], w[1], parent);); // Search mesh in the world debug(printf("Processing Node %s\n",name);); switch(CurrentType) { case MESH: t=PV_GetMeshPtr(zeworld,name); debug(if(t!=NULL) printf("Linked with mesh %s from world\n",((PVMesh*)t)->Name);); if(t==NULL) CurrentType=UNKNOW; break; case CAM_TARGET: case CAM_POS: t=(void*)PV_GetCurrentCam(); debug(if(t!=NULL) printf("Linked with camera %s\n",((PVCam*)t)->Name);); break; case LIGHT_TARGET: case LIGHT_POS: t=PV_GetLightPtr(zeworld,name); debug(if(t!=NULL) printf("Linked with light %s from world\n",((PVLight*)t)->Name);); if(t==NULL) CurrentType=UNKNOW; break; } if((n=PM_CreateNode(CurrentID))==NULL) return NO_MEMORY; n->Type=CurrentType; n->Object=t; CurrentType=UNKNOW; // Add to the tree m=PM_GetNodePtrByID(zemotion->RootObj,parent==65535?-1:parent); if(m==NULL) return OBJ_ID_NOT_FOUND; PM_AddChild(m,n); CurrentNode=n; return COOL; } static int PivotPointReader(FILE *f, long p) { float pos[3]; int i; if (fread(&pos, sizeof(pos), 1, f) != 1) return BIZAR_ERROR; for(i=0;i<3;i++) pos[i]=Indianf(pos[i]); debug(printf(" Pivot at X: %f, Y: %f, Z: %f\n",pos[0], pos[1], pos[2]);); if(CurrentNode->Type==MESH) { ((PVMesh*)(CurrentNode->Object))->Pivot.xf+=pos[0]; ((PVMesh*)(CurrentNode->Object))->Pivot.yf+=-pos[2]; ((PVMesh*)(CurrentNode->Object))->Pivot.zf+=-pos[1]; ((PVMesh*)(CurrentNode->Object))->Pivot.bf=((PVMesh*)(CurrentNode->Object))->Pivot.xf*((PVMesh*)(CurrentNode->Object))->Pivot.yf; } return COOL; } static void SplineFlagsReader(FILE *f, word flags) { int i; float dat; /* Key info flags for position, rotation and scaling: Until I know the meaning of each bit in flags I assume all mean a following float data. */ // NOTE THIS IS NOT A CHUNK, but A PART OF SEVERAL CHUNKS for (i = 0; i < 16; i++) { static const char *flagnames[] = { "Tension", "Continuity", "Bias", "Ease To", "Ease From", }; if (flags & (1 << i)) { if (fread(&dat, sizeof(dat), 1, f) != 1) return; dat=Indianf(dat); if (i < sizeof(flagnames)/sizeof(*flagnames)) printf(" %-15s = %f\n",flagnames[i], dat); else printf(" %-15s = %f\n","Unknown", dat); } } } static int TrackReader(FILE *f, long p) { debug(printf("þ Reading Mesh\n");); CurrentType=MESH; return ChunkReader(f, p); } static int CamTgtReader(FILE *f, long p) { debug(printf("þ Reading Cam Target\n");); CurrentType=CAM_TARGET; return ChunkReader(f, p); } static int CamReader(FILE *f, long p) { debug(printf("þ Reading Cam Track\n");); CurrentType=CAM_POS; return ChunkReader(f, p); } static int LightTgtReader(FILE *f, long p) { debug(printf("þ Reading Light Target\n");); CurrentType=LIGHT_TARGET; return ChunkReader(f, p); } static int LightReader(FILE *f, long p) { debug(printf("þ Reading Light Track\n");); CurrentType=LIGHT_POS; return ChunkReader(f, p); } static int TrackPosReader(FILE *f, long p) { word n, nf; float pos[3]; word unkown; word flags; unsigned i=0,j; fseek(f, 10, SEEK_CUR); if (fread(&n, sizeof(n), 1, f) != 1) return BIZAR_ERROR; n=Indians(n); debug(printf("Position keys: %d\n",n);); if((CurrentNode->Pos.Keys=(PMPKey*)malloc(sizeof(PMPKey)*n))==NULL) return NO_MEMORY; CurrentNode->Pos.NbKeys=n; fseek(f, 2, SEEK_CUR); while (n-- > 0) { if (fread(&nf, sizeof(nf), 1, f) != 1) return BIZAR_ERROR; nf=Indians(nf); if (fread(&unkown, sizeof(unkown), 1, f) != 1) return BIZAR_ERROR; if (fread(&flags, sizeof(flags), 1, f) != 1) return BIZAR_ERROR; flags=Indians(flags); debug(printf(" Frame %3d: Flags 0x%X\n",nf, flags);); SplineFlagsReader(f, flags); if (fread(&pos, sizeof(pos), 1, f) != 1) return BIZAR_ERROR; for(j=0;j<3;j++) pos[j]=Indianf(pos[j]); debug(printf(" X: %f, Y: %f, Z: %f\n",pos[0], pos[1], pos[2]);); CurrentNode->Pos.Keys[i].Time=nf; CurrentNode->Pos.Keys[i].x=pos[0]; CurrentNode->Pos.Keys[i].y=-pos[2]; CurrentNode->Pos.Keys[i].z=-pos[1]; if(CurrentNode->Type==MESH) { if ((CurrentNode->Father!=NULL)&&(CurrentNode->Father->Type==MESH)) { CurrentNode->Pos.Keys[i].x-=((PVMesh*)(CurrentNode->Object))->Pivot.xf-((PVMesh*)CurrentNode->Father->Object)->Pivot.xf; CurrentNode->Pos.Keys[i].y-=((PVMesh*)(CurrentNode->Object))->Pivot.yf-((PVMesh*)CurrentNode->Father->Object)->Pivot.yf; CurrentNode->Pos.Keys[i].z-=((PVMesh*)(CurrentNode->Object))->Pivot.zf-((PVMesh*)CurrentNode->Father->Object)->Pivot.zf; } else { CurrentNode->Pos.Keys[i].x-=((PVMesh*)(CurrentNode->Object))->Pivot.xf; CurrentNode->Pos.Keys[i].y-=((PVMesh*)(CurrentNode->Object))->Pivot.yf; CurrentNode->Pos.Keys[i].z-=((PVMesh*)(CurrentNode->Object))->Pivot.zf; } debug(printf("Final Poskey: %f %f %f\n",CurrentNode->Pos.Keys[i].x,CurrentNode->Pos.Keys[i].y,CurrentNode->Pos.Keys[i].z);); } i++; } return COOL; } static int TrackRotReader(FILE *f, long p) { word n, nf; float pos[4],pos2; word unkown; word flags; unsigned i=0,z,w,j; Quat q,q2; debug(Mat3x3 t;); fseek(f, 10, SEEK_CUR); if (fread(&n, sizeof(n), 1, f) != 1) return BIZAR_ERROR; n=Indians(n); debug(printf("Rotation keys: %d\n",n);); if((CurrentNode->Rot.Keys=(PMRKey*)malloc(sizeof(PMRKey)*n))==NULL) return NO_MEMORY; CurrentNode->Rot.NbKeys=n; fseek(f, 2, SEEK_CUR); while (n-- > 0) { if (fread(&nf, sizeof(nf), 1, f) != 1) return BIZAR_ERROR; nf=Indians(nf); if (fread(&unkown, sizeof(unkown), 1, f) != 1) return BIZAR_ERROR; if (fread(&flags, sizeof(flags), 1, f) != 1) return BIZAR_ERROR; flags=Indians(flags); debug(printf(" Frame %3d: Flags 0x%X\n",nf, flags);); SplineFlagsReader(f, flags); if (fread(&pos, sizeof(pos), 1, f) != 1) return BIZAR_ERROR; for(j=0;j<4;j++) pos[j]=Indianf(pos[j]); debug(printf(" Angle: %f§, X: %f, Y: %f, Z: %f\n",pos[0]*180.0/PI, pos[1], pos[2], pos[3]);); // Keep angle <180, create new keys if needed z=(pos[0]/PI)+1; if(nf==0) z=1; debug(printf("Nbr Intermediate keys : %d\n",z-1);); if(z>1) { if((CurrentNode->Rot.Keys=(PMRKey*)realloc(CurrentNode->Rot.Keys,sizeof(PMRKey)*(CurrentNode->Rot.NbKeys+z)))==NULL) return NO_MEMORY; CurrentNode->Rot.NbKeys+=z; } for(w=0;w Rot.Keys[i].Time=CurrentNode->Rot.Keys[i-1].Time+nf/z; else CurrentNode->Rot.Keys[i].Time=nf; OrientationToQuat(pos[1],-pos[3],-pos[2],pos2,&q); debug(QuatToMatrix(&q,t);); debug(printf("Equating 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(i!=0) QuatMul(&q,&CurrentNode->Rot.Keys[i-1].q,&q2); else q2=q; CurrentNode->Rot.Keys[i].q=q2; debug(printf("Keys added %f %f %f %f deg at %f\n",pos[1],-pos[3],-pos[2],pos2*180/PI,CurrentNode->Rot.Keys[i].Time);); i++; } } return COOL; } /* static int TrackScaleReader(FILE *f, long p) { word n, nf; float pos[3]; word unkown; word flags; int i; fseek(f, 10, SEEK_CUR); if (fread(&n, sizeof(n), 1, f) != 1) return BIZAR_ERROR; n=Indians(n); printf("Scale keys: %d\n", n); fseek(f, 2, SEEK_CUR); while (n-- > 0) { if (fread(&nf, sizeof(nf), 1, f) != 1) return BIZAR_ERROR; nf=Indians(nf); if (fread(&unkown, sizeof(unkown), 1, f) != 1) return BIZAR_ERROR; if (fread(&flags, sizeof(flags), 1, f) != 1) return BIZAR_ERROR; flags=Indians(flags); printf(" Frame %3d: Flags 0x%X\n",nf, flags); SplineFlagsReader(f, flags); if (fread(&pos, sizeof(pos), 1, f) != 1) return BIZAR_ERROR; for(i=0;i<3;i++) pos[i]=Indianf(pos[i]); printf(" X: %f, Y: %f, Z: %f\n",pos[0], pos[1], pos[2]); } return COOL; } */ static int ROLLTrackReader(FILE *f, long p) { word n, nf; float roll; word unkown; word flags; unsigned i=0; fseek(f, 10, SEEK_CUR); if (fread(&n, sizeof(n), 1, f) != 1) return BIZAR_ERROR; n=Indians(n); debug(printf("Roll keys: %d\n", n);); if((CurrentNode->Roll.Keys=(PMRollKey*)malloc(sizeof(PMRollKey)*n))==NULL) return NO_MEMORY; CurrentNode->Roll.NbKeys=n; fseek(f, 2, SEEK_CUR); while (n-- > 0) { if (fread(&nf, sizeof(nf), 1, f) != 1) return BIZAR_ERROR; nf=Indians(nf); if (fread(&unkown, sizeof(unkown), 1, f) != 1) return BIZAR_ERROR; if (fread(&flags, sizeof(flags), 1, f) != 1) return BIZAR_ERROR; flags=Indians(flags); debug(printf(" Frame %3d: Flags 0x%X\n",nf, flags);); SplineFlagsReader(f, flags); if (fread(&roll, sizeof(roll), 1, f) != 1) return BIZAR_ERROR; roll=Indianf(roll); debug(printf(" Roll:%f\n",roll);); CurrentNode->Roll.Keys[i].Time=nf; CurrentNode->Roll.Keys[i].Roll=roll*PI/180; i++; } return COOL; } static int ObjNumberReader(FILE *f, long p) { word n; if (fread(&n, sizeof(n), 1, f) != 1) return BIZAR_ERROR; n=Indians(n); debug(printf("Object number: %d\n", n);); CurrentID=n; return COOL; } // ------------------------------------ static struct { word id; int (*func)(FILE *f, long p); } ChunkNames[] = { {CHUNK_MAIN, NULL}, {CHUNK_KEYFRAMER, NULL}, {CHUNK_AMBIENTKEY, NULL}, {CHUNK_TRACKINFO, TrackReader}, {CHUNK_FRAMES, FramesReader}, {CHUNK_TRACKOBJNAME,TrackObjNameReader}, {CHUNK_TRACKPIVOT, PivotPointReader}, {CHUNK_TRACKPOS, TrackPosReader}, {CHUNK_TRACKROTATE, TrackRotReader}, //{CHUNK_TRACKSCALE, TrackScaleReader}, {CHUNK_OBJNUMBER, ObjNumberReader}, {CHUNK_TRACKCAMERA, CamReader}, {CHUNK_TRACKCAMTGT, CamTgtReader}, {CHUNK_TRACKLIGHT, LightReader}, {CHUNK_TRACKLIGTGT, LightTgtReader}, //{CHUNK_TRACKSPOTL, NULL}, //{CHUNK_TRACKFOV, NULL}, {CHUNK_TRACKROLL, ROLLTrackReader}, }; 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, sizeof(h), 1, f) != 1) break; pour eviter des blemes avec les compilos optimisants // Portability 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 LoadAnimFrom3DS(char *name,PMotion *m,PVWorld *w) { FILE *_3ds; unsigned long fsize; int h; if((m==NULL)||(w==NULL)) return ARG_INVALID; zemotion=m; zeworld=w; debug(printf("þ 3DStudio Animation file reader for Panard Vision V%s (Debug Mode Actived)\n",_3DS_ANIM_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); return h; }