3dsread.c

来自「一个高性能的3D游戏引擎源代码」· C语言 代码 · 共 506 行

C
506
字号
// Mesh driver for 3ds4 files
// Stolen form code of Jare/Iguana


#define debug(x) //x

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <malloc.h>
#include <ctype.h>
//#include <unistd.h>          // 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("

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?