mirror of
https://github.com/WinampDesktop/winamp.git
synced 2024-09-24 15:54:12 +00:00
245 lines
6.1 KiB
C
245 lines
6.1 KiB
C
|
/******************************************************************************
|
||
|
Plush Version 1.2
|
||
|
read_3ds.c
|
||
|
3DS Object Reader
|
||
|
Copyright (c) 1996-2000, Justin Frankel
|
||
|
******************************************************************************/
|
||
|
|
||
|
#include "plush.h"
|
||
|
|
||
|
typedef struct {
|
||
|
pl_uInt16 id;
|
||
|
void (*func)(FILE *f, pl_uInt32 p);
|
||
|
} _pl_3DSChunk;
|
||
|
|
||
|
static pl_Obj *obj;
|
||
|
static pl_Obj *bobj;
|
||
|
static pl_Obj *lobj;
|
||
|
static pl_sInt16 currentobj;
|
||
|
static pl_Mat *_m;
|
||
|
|
||
|
static pl_Float _pl3DSReadFloat(FILE *f);
|
||
|
static pl_uInt32 _pl3DSReadDWord(FILE *f);
|
||
|
static pl_uInt16 _pl3DSReadWord(FILE *f);
|
||
|
static void _pl3DSChunkReader(FILE *f, pl_uInt32 p);
|
||
|
static void _pl3DSRGBFReader(FILE *f, pl_uInt32 p);
|
||
|
static void _pl3DSRGBBReader(FILE *f, pl_uInt32 p);
|
||
|
static void _pl3DSASCIIZReader(FILE *f, pl_uInt32 p, char *as);
|
||
|
static void _pl3DSObjBlockReader(FILE *f, pl_uInt32 p);
|
||
|
static void _pl3DSTriMeshReader(FILE *f, pl_uInt32 p);
|
||
|
static void _pl3DSVertListReader(FILE *f, pl_uInt32 p);
|
||
|
static void _pl3DSFaceListReader(FILE *f, pl_uInt32 p);
|
||
|
static void _pl3DSFaceMatReader(FILE *f, pl_uInt32 p);
|
||
|
static void MapListReader(FILE *f, pl_uInt32 p);
|
||
|
static pl_sInt16 _pl3DSFindChunk(pl_uInt16 id);
|
||
|
|
||
|
static _pl_3DSChunk _pl3DSChunkNames[] = {
|
||
|
{0x4D4D,NULL}, /* Main */
|
||
|
{0x3D3D,NULL}, /* Object Mesh */
|
||
|
{0x4000,_pl3DSObjBlockReader},
|
||
|
{0x4100,_pl3DSTriMeshReader},
|
||
|
{0x4110,_pl3DSVertListReader},
|
||
|
{0x4120,_pl3DSFaceListReader},
|
||
|
{0x4130,_pl3DSFaceMatReader},
|
||
|
{0x4140,MapListReader},
|
||
|
{0xAFFF,NULL}, /* Material */
|
||
|
{0xA010,NULL}, /* Ambient */
|
||
|
{0xA020,NULL}, /* Diff */
|
||
|
{0xA030,NULL}, /* Specular */
|
||
|
{0xA200,NULL}, /* Texture */
|
||
|
{0x0010,_pl3DSRGBFReader},
|
||
|
{0x0011,_pl3DSRGBBReader},
|
||
|
};
|
||
|
|
||
|
pl_Obj *plRead3DSObj(char *fn, pl_Mat *m) {
|
||
|
FILE *f;
|
||
|
pl_uInt32 p;
|
||
|
_m = m;
|
||
|
obj = bobj = lobj = 0;
|
||
|
currentobj = 0;
|
||
|
f = fopen(fn, "rb");
|
||
|
if (!f) return 0;
|
||
|
fseek(f, 0, 2);
|
||
|
p = ftell(f);
|
||
|
rewind(f);
|
||
|
_pl3DSChunkReader(f, p);
|
||
|
fclose(f);
|
||
|
return bobj;
|
||
|
}
|
||
|
|
||
|
static pl_Float _pl3DSReadFloat(FILE *f) {
|
||
|
pl_uInt32 *i;
|
||
|
pl_IEEEFloat32 c;
|
||
|
i = (pl_uInt32 *) &c;
|
||
|
*i = _pl3DSReadDWord(f);
|
||
|
return ((pl_Float) c);
|
||
|
}
|
||
|
|
||
|
static pl_uInt32 _pl3DSReadDWord(FILE *f) {
|
||
|
pl_uInt32 r;
|
||
|
r = fgetc(f);
|
||
|
r |= fgetc(f)<<8;
|
||
|
r |= fgetc(f)<<16;
|
||
|
r |= fgetc(f)<<24;
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
static pl_uInt16 _pl3DSReadWord(FILE *f) {
|
||
|
pl_uInt16 r;
|
||
|
r = fgetc(f);
|
||
|
r |= fgetc(f)<<8;
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
static void _pl3DSRGBFReader(FILE *f, pl_uInt32 p) {
|
||
|
pl_Float c[3];
|
||
|
c[0] = _pl3DSReadFloat(f);
|
||
|
c[1] = _pl3DSReadFloat(f);
|
||
|
c[2] = _pl3DSReadFloat(f);
|
||
|
}
|
||
|
|
||
|
static void _pl3DSRGBBReader(FILE *f, pl_uInt32 p) {
|
||
|
unsigned char c[3];
|
||
|
if (fread(&c, sizeof(c), 1, f) != 1) return;
|
||
|
}
|
||
|
|
||
|
static void _pl3DSASCIIZReader(FILE *f, pl_uInt32 p, char *as) {
|
||
|
char c;
|
||
|
if (!as) while ((c = fgetc(f)) != EOF && c != '\0');
|
||
|
else {
|
||
|
while ((c = fgetc(f)) != EOF && c != '\0') *as++ = c;
|
||
|
*as = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void _pl3DSObjBlockReader(FILE *f, pl_uInt32 p) {
|
||
|
_pl3DSASCIIZReader(f,p,0);
|
||
|
_pl3DSChunkReader(f, p);
|
||
|
}
|
||
|
|
||
|
static void _pl3DSTriMeshReader(FILE *f, pl_uInt32 p) {
|
||
|
pl_uInt32 i;
|
||
|
pl_Face *face;
|
||
|
obj = plObjCreate(0,0);
|
||
|
_pl3DSChunkReader(f, p);
|
||
|
i = obj->NumFaces;
|
||
|
face = obj->Faces;
|
||
|
while (i--) {
|
||
|
face->Vertices[0] = obj->Vertices + (pl_uInt32) face->Vertices[0];
|
||
|
face->Vertices[1] = obj->Vertices + (pl_uInt32) face->Vertices[1];
|
||
|
face->Vertices[2] = obj->Vertices + (pl_uInt32) face->Vertices[2];
|
||
|
face->MappingU[0] = face->Vertices[0]->xformedx;
|
||
|
face->MappingV[0] = face->Vertices[0]->xformedy;
|
||
|
face->MappingU[1] = face->Vertices[1]->xformedx;
|
||
|
face->MappingV[1] = face->Vertices[1]->xformedy;
|
||
|
face->MappingU[2] = face->Vertices[2]->xformedx;
|
||
|
face->MappingV[2] = face->Vertices[2]->xformedy;
|
||
|
face++;
|
||
|
}
|
||
|
plObjCalcNormals(obj);
|
||
|
if (currentobj == 0) {
|
||
|
currentobj = 1;
|
||
|
lobj = bobj = obj;
|
||
|
} else {
|
||
|
lobj->Children[0] = obj;
|
||
|
lobj = obj;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void _pl3DSVertListReader(FILE *f, pl_uInt32 p) {
|
||
|
pl_uInt16 nv;
|
||
|
pl_Vertex *v;
|
||
|
nv = _pl3DSReadWord(f);
|
||
|
obj->NumVertices = nv;
|
||
|
v = obj->Vertices = (pl_Vertex *) calloc(sizeof(pl_Vertex)*nv,1);
|
||
|
while (nv--) {
|
||
|
v->x = _pl3DSReadFloat(f);
|
||
|
v->y = _pl3DSReadFloat(f);
|
||
|
v->z = _pl3DSReadFloat(f);
|
||
|
if (feof(f)) return;
|
||
|
v++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void _pl3DSFaceListReader(FILE *f, pl_uInt32 p) {
|
||
|
pl_uInt16 nv;
|
||
|
pl_uInt16 c[3];
|
||
|
pl_uInt16 flags;
|
||
|
pl_Face *face;
|
||
|
|
||
|
nv = _pl3DSReadWord(f);
|
||
|
obj->NumFaces = nv;
|
||
|
face = obj->Faces = (pl_Face *) calloc(sizeof(pl_Face)*nv,1);
|
||
|
while (nv--) {
|
||
|
c[0] = _pl3DSReadWord(f);
|
||
|
c[1] = _pl3DSReadWord(f);
|
||
|
c[2] = _pl3DSReadWord(f);
|
||
|
flags = _pl3DSReadWord(f);
|
||
|
if (feof(f)) return;
|
||
|
face->Vertices[0] = (pl_Vertex *) (c[0]&0x0000FFFF);
|
||
|
face->Vertices[1] = (pl_Vertex *) (c[1]&0x0000FFFF);
|
||
|
face->Vertices[2] = (pl_Vertex *) (c[2]&0x0000FFFF);
|
||
|
face->Material = _m;
|
||
|
face++;
|
||
|
}
|
||
|
_pl3DSChunkReader(f, p);
|
||
|
}
|
||
|
|
||
|
static void _pl3DSFaceMatReader(FILE *f, pl_uInt32 p) {
|
||
|
pl_uInt16 n, nf;
|
||
|
|
||
|
_pl3DSASCIIZReader(f, p,0);
|
||
|
|
||
|
n = _pl3DSReadWord(f);
|
||
|
while (n--) {
|
||
|
nf = _pl3DSReadWord(f);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void MapListReader(FILE *f, pl_uInt32 p) {
|
||
|
pl_uInt16 nv;
|
||
|
pl_Float c[2];
|
||
|
pl_Vertex *v;
|
||
|
nv = _pl3DSReadWord(f);
|
||
|
v = obj->Vertices;
|
||
|
if (nv == obj->NumVertices) while (nv--) {
|
||
|
c[0] = _pl3DSReadFloat(f);
|
||
|
c[1] = _pl3DSReadFloat(f);
|
||
|
if (feof(f)) return;
|
||
|
v->xformedx = (pl_sInt32) (c[0]*65536.0);
|
||
|
v->xformedy = (pl_sInt32) (c[1]*65536.0);
|
||
|
v++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static pl_sInt16 _pl3DSFindChunk(pl_uInt16 id) {
|
||
|
pl_sInt16 i;
|
||
|
for (i = 0; i < sizeof(_pl3DSChunkNames)/sizeof(_pl3DSChunkNames[0]); i++)
|
||
|
if (id == _pl3DSChunkNames[i].id) return i;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
static void _pl3DSChunkReader(FILE *f, pl_uInt32 p) {
|
||
|
pl_uInt32 hlen;
|
||
|
pl_uInt16 hid;
|
||
|
pl_sInt16 n;
|
||
|
pl_uInt32 pc;
|
||
|
|
||
|
while (ftell(f) < (int)p) {
|
||
|
pc = ftell(f);
|
||
|
hid = _pl3DSReadWord(f); if (feof(f)) return;
|
||
|
hlen = _pl3DSReadDWord(f); if (feof(f)) return;
|
||
|
if (hlen == 0) return;
|
||
|
n = _pl3DSFindChunk(hid);
|
||
|
if (n < 0) fseek(f, pc + hlen, 0);
|
||
|
else {
|
||
|
pc += hlen;
|
||
|
if (_pl3DSChunkNames[n].func != NULL) _pl3DSChunkNames[n].func(f, pc);
|
||
|
else _pl3DSChunkReader(f, pc);
|
||
|
fseek(f, pc, 0);
|
||
|
}
|
||
|
if (ferror(f)) break;
|
||
|
}
|
||
|
}
|
||
|
|