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