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 + -
显示快捷键?