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;wRot.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; 
}