/* -- FEXW 3D vector engine -- * Copyright (c) Mats Byggmastar 1996 * * 3D Studio object & keyframer reader */ #define FILELOAD 1 #define MEMLOAD 1 #include #include #include #include #include #include "3dsread.h" static void (* dread)(void * dest, int len); static void (* dsetpos)(uint pos); static uint (* dgetpos)(void); static char * errmsg; static jmp_buf EnvState; static void * xmalloc(int bytes) { return malloc(bytes); } static void xfree(void * mem) { free(mem); } static void * xrealloc(void * mem, int bytes) { return realloc(mem, bytes); } #ifdef FILELOAD static FILE * InFile=0; static void FileRead(void * dest, int len) { if(fread(dest, len, 1, InFile) != 1) { strcpy(errmsg, "Error reading file."); longjmp(EnvState, 1); } } static void FileSetpos(uint pos) { if(fseek(InFile, (long)pos, SEEK_SET) != 0) { strcpy(errmsg, "Error moving file pointer."); longjmp(EnvState, 1); } } static uint FileGetpos(void) { long pos; if((pos=ftell(InFile)) == -1L) { strcpy(errmsg, "Error reading file position."); longjmp(EnvState, 1); } return (uint) pos; } #endif #ifdef MEMLOAD static uchar * MemBuffer=0; static uint MemBufferLen=0, MemBufferIndex=0; static void MemRead(void * dest, int len) { // Never allow any reads past the membuffer. if(MemBufferIndex+len > MemBufferLen) { strcpy(errmsg, "Trying to read past memory buffer."); longjmp(EnvState, 1); } memcpy(dest, &MemBuffer[MemBufferIndex], len); MemBufferIndex += len; } static void MemSetpos(uint pos) { // It should be legal to move the position one byte // past the membuffer. The mem must not be read though. if(pos > MemBufferLen) { strcpy(errmsg, "Trying to set pointer past memory buffer."); longjmp(EnvState, 1); } MemBufferIndex=pos; } static uint MemGetpos(void) { return MemBufferIndex; } #endif static F3dsScene * Scene; static F3dsObject * GetObject(void) { void * mem; uint size = sizeof(F3dsObject)*(Scene->objects+1); if((mem=xrealloc(Scene->objlist, size)) == 0) { sprintf(errmsg, "Error reallocating memory for object list " "(%u bytes).", size); longjmp(EnvState, 1); } Scene->objlist=(F3dsObject *) mem; F3dsObject * obj=&Scene->objlist[Scene->objects++]; memset(obj, 0, sizeof(F3dsObject)); return obj; } static F3dsMaterial * GetMaterial(void) { void * mem; uint size = sizeof(F3dsMaterial)*(Scene->materials+1); if((mem=xrealloc(Scene->matlist, size)) == 0) { sprintf(errmsg, "Error reallocating memory for material list " "(%u bytes).", size); longjmp(EnvState, 1); } Scene->matlist=(F3dsMaterial *) mem; F3dsMaterial * mat=&Scene->matlist[Scene->materials++]; memset(mat, 0, sizeof(F3dsMaterial)); return mat; } static F3dsCamera * GetCamera(void) { void * mem; uint size = sizeof(F3dsCamera)*(Scene->cameras+1); if((mem=xrealloc(Scene->camlist, size)) == 0) { sprintf(errmsg, "Error reallocating memory for camera list " "(%u bytes).", size); longjmp(EnvState, 1); } Scene->camlist=(F3dsCamera *) mem; F3dsCamera * cam=&Scene->camlist[Scene->cameras++]; memset(cam, 0, sizeof(F3dsCamera)); return cam; } static F3dsLight * GetLight(void) { void * mem; uint size = sizeof(F3dsLight)*(Scene->lights+1); if((mem=xrealloc(Scene->liglist, size)) == 0) { sprintf(errmsg, "Error reallocating memory for light list ", "(%u bytes).", size); longjmp(EnvState, 1); } Scene->liglist=(F3dsLight *) mem; F3dsLight * lig=&Scene->liglist[Scene->lights++]; memset(lig, 0, sizeof(F3dsLight)); return lig; } static void * getmem(int size) { void * mem; if((mem=xmalloc(size))==0) { sprintf(errmsg, "Failed to allocate memory (%u bytes).", size); longjmp(EnvState, 1); } memset(mem, 0, size); return mem; } /* * Each 3DS data-chunk starts with a 6 byte header. The first item in the * header is a 2 byte (ushort) id-number. After that follows a uint which * gives the size of the data-chunk including the header. The size can be * used as an relative offset to the next chunk. */ // tab 4 enum { CHUNK_RGBF = 0x0010, CHUNK_RGBB = 0x0011, //CHUNK_RBGB2 = 0x0012, // ?? NOT HLS. CHUNK_PRJ = 0xC23D, CHUNK_MLI = 0x3DAA, CHUNK_MAIN = 0x4D4D, CHUNK_OBJMESH = 0x3D3D, CHUNK_BKGCOLOR = 0x1200, CHUNK_AMBCOLOR = 0x2100, CHUNK_OBJBLOCK = 0x4000, CHUNK_TRIMESH = 0x4100, CHUNK_VERTLIST = 0x4110, CHUNK_FACELIST = 0x4120, CHUNK_FACEMAT = 0x4130, CHUNK_MAPLIST = 0x4140, CHUNK_SMOOLIST = 0x4150, CHUNK_TRMATRIX = 0x4160, CHUNK_MESHCOLOR = 0x4165, CHUNK_TXTINFO = 0x4170, CHUNK_LIGHT = 0x4600, CHUNK_SPOTLIGHT = 0x4610, CHUNK_CAMERA = 0x4700, CHUNK_HIERARCHY = 0x4F00, CHUNK_VIEWPORT = 0x7001, 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_AMBIENTKEY = 0xB001, CHUNK_TRACKINFO = 0xB002, CHUNK_TRACKOBJNAME = 0xB010, CHUNK_TRACKPIVOT = 0xB013, CHUNK_TRACKPOS = 0xB020, CHUNK_TRACKROTATE = 0xB021, CHUNK_TRACKSCALE = 0xB022, CHUNK_TRACKMORPH = 0xB026, CHUNK_TRACKHIDE = 0xB029, 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, }; static void ReadName(char * name, uint maxlen) { uint n=0; do { dread(&name[n++], 1); } while(name[n-1]!='\0' && nvertices=nv; int k=nv; obj->vtxlist=(F3dsVertex *) getmem(sizeof(F3dsVertex)*k); for(int n=0; nvtxlist[n].x=c[0]; obj->vtxlist[n].y=c[1]; obj->vtxlist[n].z=c[2]; } } static void ReadFaceList(uint, F3dsObject * obj) { ushort c[4]; ushort nv; dread(&nv, sizeof(nv)); obj->faces=nv; int k=nv; obj->faclist=(F3dsFace *) getmem(sizeof(F3dsFace)*k); for(int n=0; nfaclist[n].p0=c[0]; obj->faclist[n].p1=c[1]; obj->faclist[n].p2=c[2]; obj->faclist[n].flags=c[3]; } } static void ReadMapList(uint, F3dsObject * obj) { float c[2]; ushort nv; dread(&nv, sizeof(nv)); if(nv != obj->vertices) { sprintf(errmsg, "Bad number of map coordinates [%s].", obj->name); longjmp(EnvState, 1); } int k=nv; for(int n=0; n 100.0) c[0] = 0.0; if(c[1] < -100.0 || c[1] > 100.0) c[1] = 0.0; obj->vtxlist[n].u=c[0]; obj->vtxlist[n].v=c[1]; } } static void ReadSmoothList(uint p, F3dsObject * obj) { uint c; int n=0; while(dgetpos() < p && n < obj->faces) { dread(&c, sizeof(c)); obj->faclist[n].smooth = c; n++; } } static void ReadTraMatrix(uint, F3dsObject * obj) { float c[3]; // Read 3x3 rotation matrix (world -> object space) for(int n=0; n<3; n++) { dread(c, sizeof(c)); obj->aff[n][0]=c[0]; obj->aff[n][1]=c[1]; obj->aff[n][2]=c[2]; } // Read 3x1 translation matrix (object -> world space) // Invert it and concatenate it with the rotation matrix to make // a complete affine transformation matrix. dread(c, sizeof(c)); // Store the 3x1 translation matrix as object pivot also obj->objpivx = c[0]; obj->objpivy = c[1]; obj->objpivz = c[2]; float x=-c[0]; float y=-c[1]; float z=-c[2]; obj->aff[3][0]=obj->aff[0][0]*x+obj->aff[0][1]*y+obj->aff[0][2]*z; obj->aff[3][1]=obj->aff[1][0]*x+obj->aff[1][1]*y+obj->aff[1][2]*z; obj->aff[3][2]=obj->aff[2][0]*x+obj->aff[2][1]*y+obj->aff[2][2]*z; // This 4x3 matrix now is a ready to use affine transformation matrix // for converting from world -> object space. The object vertices // are in world space in the 3DS file. } static void ReadFaceMat(uint, F3dsObject * obj) { ushort nv; char name[20]; // Material name is the first item ReadName(name, sizeof(name)); // Find the material number in the material list int matnum=0; for(int n=0; nmaterials; n++) if(!strcmp(Scene->matlist[n].name, name)) { matnum=n; break; } dread(&nv, sizeof(nv)); int k=nv; for(n=0; n obj->faces) nv = 0; obj->faclist[nv].material = matnum; } } static void ReadTxtInfoBlock(uint, F3dsObject * obj) { float c[2]; dsetpos(dgetpos()+sizeof(ushort)); // skip map_type dread(c, sizeof(c)); obj->utile = c[0]; obj->vtile = c[1]; dsetpos(dgetpos()+19*sizeof(float)); // skip rest of chunk } static void ReadTriMeshBlocks(uint p, char * name) { ushort id; uint len, pc; uchar c; F3dsObject * obj=GetObject(); strcpy(obj->name, name); while((pc=dgetpos()) < p) { dread(&id, sizeof(id)); dread(&len, sizeof(len)); switch((int)id) { // Note! The FACELIST chunk include FACEMAT and SMOOLIST chunks. case CHUNK_FACELIST: ReadFaceList (pc+len, obj); continue; case CHUNK_FACEMAT: ReadFaceMat (pc+len, obj); break; case CHUNK_SMOOLIST: ReadSmoothList(pc+len, obj); break; case CHUNK_VERTLIST: ReadVertList (pc+len, obj); break; case CHUNK_MAPLIST: ReadMapList (pc+len, obj); break; case CHUNK_TRMATRIX: ReadTraMatrix (pc+len, obj); break; case CHUNK_TXTINFO: ReadTxtInfoBlock(pc+len, obj); break; case CHUNK_MESHCOLOR: dread(&c, sizeof(c)); obj->color=c; break; } dsetpos(pc+len); } } static void ReadCameraBlock(uint p, char * name) { float c[8]; F3dsCamera * cam=GetCamera(); strcpy(cam->name, name); dread(&c, sizeof(c)); cam->px=c[0]; cam->py=c[1]; cam->pz=c[2]; cam->tx=c[3]; cam->ty=c[4]; cam->tz=c[5]; cam->roll=c[6]; cam->lens=c[7]; } static void ReadLightRGB(uint, F3dsLight * lig) { float c[3]; dread(&c, sizeof(c)); lig->r=c[0]; lig->g=c[1]; lig->b=c[2]; } static void ReadLightBlock(uint p, char * name) { ushort id; uint len, pc; float c[3]; F3dsLight * lig=GetLight(); strcpy(lig->name, name); dread(&c, sizeof(c)); lig->x=c[0]; lig->y=c[1]; lig->z=c[2]; while((pc=dgetpos()) < p) { dread(&id, sizeof(id)); dread(&len, sizeof(len)); switch((int)id) { case CHUNK_RGBF: ReadLightRGB(pc+len, lig); break; //case CHUNK_SPOTLIGHT: } dsetpos(pc+len); } } static void ReadObjectBlocks(uint p) { ushort id; uint len, pc; char name[16]; // Object name is the first item ReadName(name, sizeof(name)); while((pc=dgetpos()) < p) { dread(&id, sizeof(id)); dread(&len, sizeof(len)); switch((int)id) { case CHUNK_TRIMESH: ReadTriMeshBlocks(pc+len, name); break; case CHUNK_CAMERA: ReadCameraBlock(pc+len, name); break; case CHUNK_LIGHT: ReadLightBlock(pc+len, name); break; } dsetpos(pc+len); } } static void ReadMaterialBlocks(uint p) { ushort id; uint len, pc; F3dsMaterial * mat=GetMaterial(); while((pc=dgetpos()) < p) { dread(&id, sizeof(id)); dread(&len, sizeof(len)); switch((int)id) { case CHUNK_MATNAME: ReadName(mat->name, sizeof(mat->name)); break; //case CHUNK_AMBIENT: //case CHUNK_DIFFUSE: //case CHUNK_SPECULAR: //case CHUNK_TEXTURE: //case CHUNK_BUMPMAP: //case CHUNK_MAPFILE: } dsetpos(pc+len); } } static void ReadObjMeshBlocks(uint p) { ushort id; uint len, pc; while((pc=dgetpos()) < p) { dread(&id, sizeof(id)); dread(&len, sizeof(len)); switch((int)id) { case CHUNK_OBJBLOCK: ReadObjectBlocks(pc+len); break; case CHUNK_MATERIAL: ReadMaterialBlocks(pc+len); break; //case CHUNK_VIEWPORT //case CHUNK_AMBCOLOR: //case CHUNK_BKGCOLOR: } dsetpos(pc+len); } } static void ReadFramesBlock(uint) { uint c[2]; dread(c, sizeof(c)); Scene->startframe = c[0]; Scene->endframe = c[1]; } static void ReadTrackPivot(uint, F3dsObject * obj) { float c[3]; dread(c, sizeof(c)); obj->trackpivx = c[0]; obj->trackpivy = c[1]; obj->trackpivz = c[2]; } static void ReadSplineFlags(float * data, ushort flags) { for(int i=0; i<16; i++) if(flags & (1 << i)) dread(data+i, sizeof(float)); } static F3dsPosKey * ReadPosKeys(uint p, ushort * keys, ushort * kflags) { ushort n, unknown, frame, flags; float pos[3], data[16]; F3dsPosKey * key; dread(kflags, 2); dsetpos(dgetpos()+8); // unknown data dread(&n, sizeof(n)); *keys = n; dsetpos(dgetpos()+2); // unknown data key = (F3dsPosKey *) getmem((int)n*sizeof(F3dsPosKey)); for(int t=0; tobjlist; // Just in case... while((pc=dgetpos()) < p) { dread(&id, sizeof(id)); dread(&len, sizeof(len)); switch((int)id) { case CHUNK_OBJNUMBER: number = ReadObjectNumber(pc+len); break; case CHUNK_TRACKOBJNAME: { ReadName(name, sizeof(name)); // Find object with this name dread(data, sizeof(data)); for(int n=0; nobjects; n++) if(!strcmp(name, Scene->objlist[n].name)) { obj = Scene->objlist+n; obj->number = number; break; } obj->flags = data[0]; obj->parent = data[2]; } break; case CHUNK_TRACKPIVOT: ReadTrackPivot(pc+len, obj); break; case CHUNK_TRACKPOS: obj->poslist = ReadPosKeys(pc+len, &obj->poskeys, &obj->posflags); break; case CHUNK_TRACKROTATE: obj->rotlist = ReadRotKeys(pc+len, &obj->rotkeys, &obj->rotflags); break; case CHUNK_TRACKMORPH: obj->morlist = ReadMorKeys(pc+len, &obj->morkeys, &obj->morflags); break; case CHUNK_TRACKHIDE: obj->hidlist = ReadHidKeys(pc+len, &obj->hidkeys, &obj->hidflags); break; case CHUNK_TRACKSCALE: obj->scalist = ReadPosKeys(pc+len, &obj->scakeys, &obj->scaflags); break; } dsetpos(pc+len); } } static void ReadCameraTrackBlocks(uint p) { ushort id; uint len, pc; ushort posnumber=0; char name[16]={0}; ushort data[3]; F3dsCamera * cam = Scene->camlist; // Just in case... while((pc=dgetpos()) < p) { dread(&id, sizeof(id)); dread(&len, sizeof(len)); switch((int)id) { case CHUNK_OBJNUMBER: posnumber = ReadObjectNumber(pc+len); break; case CHUNK_TRACKOBJNAME: { ReadName(name, sizeof(name)); dread(data, sizeof(data)); // Find camera with this name for(int n=0; ncameras; n++) if(!strcmp(name, Scene->camlist[n].name)) { cam = Scene->camlist+n; cam->posnumber = posnumber; break; } cam->flags = data[0]; cam->posparent = data[2]; } break; case CHUNK_TRACKPOS: cam->poslist = ReadPosKeys(pc+len, &cam->poskeys, &cam->posflags); break; case CHUNK_TRACKFOV: cam->fovlist = ReadValKeys(pc+len, &cam->fovkeys, &cam->fovflags); break; case CHUNK_TRACKROLL: cam->rollist = ReadValKeys(pc+len, &cam->rolkeys, &cam->rolflags); break; } dsetpos(pc+len); } } static void ReadCameraTgtTrackBlocks(uint p) { ushort id; uint len, pc; ushort tarnumber=0; char name[16]={0}; ushort data[3]; F3dsCamera * cam = Scene->camlist; // Just in case... while((pc=dgetpos()) < p) { dread(&id, sizeof(id)); dread(&len, sizeof(len)); switch((int)id) { case CHUNK_OBJNUMBER: tarnumber = ReadObjectNumber(pc+len); break; case CHUNK_TRACKOBJNAME: { ReadName(name, sizeof(name)); dread(data, sizeof(data)); // Find camera with this name for(int n=0; ncameras; n++) if(!strcmp(name, Scene->camlist[n].name)) { cam = Scene->camlist+n; cam->tarnumber = tarnumber; break; } cam->flags = data[0]; cam->tarparent = data[2]; } break; case CHUNK_TRACKPOS: cam->tarlist = ReadPosKeys(pc+len, &cam->tarkeys, &cam->tarflags); break; } dsetpos(pc+len); } } static void ReadLightTrackBlocks(uint p) { ushort id; uint len, pc; ushort number=0; char name[16]={0}; ushort data[3]; F3dsLight * lig = Scene->liglist; // Just in case... while((pc=dgetpos()) < p) { dread(&id, sizeof(id)); dread(&len, sizeof(len)); switch((int)id) { case CHUNK_OBJNUMBER: number = ReadObjectNumber(pc+len); break; case CHUNK_TRACKOBJNAME: { ReadName(name, sizeof(name)); dread(data, sizeof(data)); // Find light with this name for(int n=0; nlights; n++) if(!strcmp(name, Scene->liglist[n].name)) { lig = Scene->liglist+n; lig->number = number; break; } lig->flags = data[0]; lig->parent = data[2]; } break; case CHUNK_TRACKPOS: lig->poslist = ReadPosKeys(pc+len, &lig->poskeys, &lig->posflags); break; } dsetpos(pc+len); } } static void ReadKeyframerBlocks(uint p) { ushort id; uint len, pc; while((pc=dgetpos()) < p) { dread(&id, sizeof(id)); dread(&len, sizeof(len)); switch((int)id) { case CHUNK_FRAMES: ReadFramesBlock(pc+len); break; case CHUNK_TRACKINFO: ReadTrackInfoBlocks(pc+len); break; case CHUNK_TRACKCAMERA: ReadCameraTrackBlocks(pc+len); break; case CHUNK_TRACKCAMTGT: ReadCameraTgtTrackBlocks(pc+len); break; case CHUNK_TRACKLIGHT: ReadLightTrackBlocks(pc+len); break; //case CHUNK_TRACKLIGTGT: //case CHUNK_TRACKSPOTL: //case CHUNK_AMBIENTKEY: } dsetpos(pc+len); } } static void ReadMainBlocks(uint p) { ushort id; uint len, pc; while((pc=dgetpos()) < p) { dread(&id, sizeof(id)); dread(&len, sizeof(len)); switch((int)id) { case CHUNK_OBJMESH: ReadObjMeshBlocks(pc+len); break; case CHUNK_KEYFRAMER: ReadKeyframerBlocks(pc+len); break; } dsetpos(pc+len); } } void F3dsFreeScene(F3dsScene * scene) { if(scene) { if(scene->liglist) { for(int n=0; nlights; n++) { if(scene->liglist[n].poslist) xfree(scene->liglist[n].poslist); } xfree(scene->liglist); } if(scene->camlist) { for(int n=0; ncameras; n++) { if(scene->camlist[n].poslist) xfree(scene->camlist[n].poslist); if(scene->camlist[n].tarlist) xfree(scene->camlist[n].tarlist); if(scene->camlist[n].fovlist) xfree(scene->camlist[n].fovlist); if(scene->camlist[n].rollist) xfree(scene->camlist[n].rollist); } xfree(scene->camlist); } if(scene->matlist) xfree(scene->matlist); if(scene->objlist) { for(int n=0; nobjects; n++) { if(scene->objlist[n].faclist) xfree(scene->objlist[n].faclist); if(scene->objlist[n].vtxlist) xfree(scene->objlist[n].vtxlist); if(scene->objlist[n].poslist) xfree(scene->objlist[n].poslist); if(scene->objlist[n].rotlist) xfree(scene->objlist[n].rotlist); if(scene->objlist[n].scalist) xfree(scene->objlist[n].scalist); if(scene->objlist[n].morlist) xfree(scene->objlist[n].morlist); if(scene->objlist[n].hidlist) xfree(scene->objlist[n].hidlist); } xfree(scene->objlist); } xfree(scene); } } F3dsScene * F3dsReadScene(char * msg, void * ptr, int what, uint size) { if(ptr==0) return 0; errmsg=msg; #ifdef FILELOAD if(what == FILE_3DS) { // Load from file InFile=(FILE *) ptr; dread=FileRead; dsetpos=FileSetpos; dgetpos=FileGetpos; } else #endif #ifdef MEMLOAD if(what == MEMORY_3DS) { // Read from mem MemBufferIndex=0; MemBufferLen=size; MemBuffer=(uchar *) ptr; dread=MemRead; dsetpos=MemSetpos; dgetpos=MemGetpos; } else #endif { sprintf(errmsg, "Invalid reading method selected (%d).", what); return 0; } if((Scene=(F3dsScene *) xmalloc(sizeof(F3dsScene)))==0) return 0; memset(Scene, 0, sizeof(F3dsScene)); int retval = setjmp(EnvState); if(retval==0) { // Return address set, start loading 3DS data. ushort id; uint len, pc; pc=dgetpos(); dread(&id, sizeof(id)); dread(&len, sizeof(len)); if((int)id!=CHUNK_MAIN) { F3dsFreeScene(Scene); strcpy(errmsg, "This is not 3ds data."); return 0; } ReadMainBlocks(pc+len); } else { // There was an error, free the allocated mem and return NULL. F3dsFreeScene(Scene); return 0; } // Calc the new world -> pivot space matrix for(int n=0; nobjects; n++) F3dsMakeWorldToPivotAff(Scene->objlist[n].wpaff, Scene->objlist + n); // Check the objects to see if they have a subtree for(int i=0; iobjects; i++) { Scene->objlist[i].haschild = 0; ushort number = Scene->objlist[i].number; for(int o=0; oobjects; o++) { if(number == Scene->objlist[o].parent) { Scene->objlist[i].haschild = 1; break; } } for(int k=0; kcameras; k++) { if(number == Scene->camlist[k].posparent || number == Scene->camlist[k].tarparent) { Scene->objlist[i].haschild = 1; break; } } for(int l=0; llights; l++) { if(number == Scene->liglist[l].parent) { Scene->objlist[i].haschild = 1; break; } } } return Scene; } static void FMulAff(float dst[4][3], float a[4][3], float b[4][3]) { for(int i=0; i<3; i++) for(int j=0; j<3; j++) { float ab = 0.0; for(int k=0; k<3; k++) ab += a[i][k] * b[k][j]; dst[i][j] = ab; } dst[3][0] = a[0][0]*b[3][0] + a[0][1]*b[3][1] + a[0][2]*b[3][2] + a[3][0]; dst[3][1] = a[1][0]*b[3][0] + a[1][1]*b[3][1] + a[1][2]*b[3][2] + a[3][1]; dst[3][2] = a[2][0]*b[3][0] + a[2][1]*b[3][1] + a[2][2]*b[3][2] + a[3][2]; } void F3dsMakeWorldToPivotAff(float aff[4][3], F3dsObject * obj3ds) { static float piv[4][3] = { { 1.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }, { 0.0, 0.0, 1.0 }, { 0.0, 0.0, 0.0 }}; piv[3][0] = -obj3ds->trackpivx; piv[3][1] = -obj3ds->trackpivy; piv[3][2] = -obj3ds->trackpivz; if(obj3ds->aff[0][0] == -1.0 && obj3ds->aff[0][1] == 0.0 && obj3ds->aff[0][2] == 0.0) { // Ignore the object roation matrix for now piv[3][0] -= obj3ds->objpivx; piv[3][1] -= obj3ds->objpivy; piv[3][2] -= obj3ds->objpivz; memcpy(aff, piv, sizeof(piv)); } else FMulAff(aff, piv, obj3ds->aff); } inline void swap(float * x, float * y) { float tmp = *x; *x = *y; *y = tmp; } void F3dsSwapYZ(F3dsScene * src) { for(int i=0; iobjects; i++) { F3dsObject * obj = src->objlist+i; int v; for(v=0; vvertices; v++) swap(&obj->vtxlist[v].y, &obj->vtxlist[v].z); for(v=0; vposkeys; v++) swap(&obj->poslist[v].y, &obj->poslist[v].z); for(v=0; vscakeys; v++) swap(&obj->scalist[v].y, &obj->scalist[v].z); for(v=0; vrotkeys; v++) swap(&obj->rotlist[v].y, &obj->rotlist[v].z); swap(&obj->objpivy, &obj->objpivz); swap(&obj->trackpivy, &obj->trackpivz); swap(&obj->aff[3][1], &obj->aff[3][2]); swap(&obj->aff[0][1], &obj->aff[0][2]); swap(&obj->aff[1][0], &obj->aff[2][0]); swap(&obj->aff[1][1], &obj->aff[2][2]); swap(&obj->aff[1][2], &obj->aff[2][1]); swap(&obj->wpaff[3][1], &obj->wpaff[3][2]); swap(&obj->wpaff[0][1], &obj->wpaff[0][2]); swap(&obj->wpaff[1][0], &obj->wpaff[2][0]); swap(&obj->wpaff[1][1], &obj->wpaff[2][2]); swap(&obj->wpaff[1][2], &obj->wpaff[2][1]); } for(int c=0; ccameras; c++) { F3dsCamera * cam = src->camlist+c; swap(&cam->py, &cam->pz); swap(&cam->ty, &cam->tz); int v; for(v=0; vtarkeys; v++) swap(&cam->tarlist[v].y, &cam->tarlist[v].z); for(v=0; vposkeys; v++) swap(&cam->poslist[v].y, &cam->poslist[v].z); } for(int l=0; llights; l++) { F3dsLight * lig = src->liglist+l; swap(&lig->y, &lig->z); int v; for(v=0; vposkeys; v++) swap(&lig->poslist[v].y, &lig->poslist[v].z); } }