--- /dev/null
+#include "TCanvas.h"
+#include "TStyle.h"
+#include "TFile.h"
+#include "TStopwatch.h"
+#include "TError.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+namespace Reve {
+ class TriangleSet;
+}
+Reve::TriangleSet *ts[2048];
+
+// Believe3D Model file defines
+#define MAGICNUMBER 0xB3D0
+
+// types of 3DS Chunks
+#define CHUNKMAIN 0x4D4D
+#define CHUNKMAINVERSION 0x0002
+#define CHUNK3D 0x3D3D
+#define CHUNK3DVERSION 0x3D3E
+#define CHUNK3DOBJECT 0x4000
+#define CHUNK3DOBJECTMESH 0x4100
+#define CHUNK3DOBJECTMESHVERTICES 0x4110
+#define CHUNK3DOBJECTMESHFACES 0x4120
+#define CHUNK3DOBJECTMESHMATGROUP 0x4130
+#define CHUNK3DOBJECTMESHMAPPING 0x4140
+
+#define CHUNK3DMATERIAL 0xAFFF
+// Sub defines of MATERIAL
+#define MATNAME 0xA000
+#define MATDIFFUSE 0xA020
+#define MATSPECULAR 0xA030
+#define MATTRANSPARENCY 0xA050
+
+#define COLOR_F 0x0010
+#define COLOR_24 0x0011
+#define LIN_COLOR_24 0x0012
+#define LIN_COLOR_F 0x0013
+#define INT_PERCENTAGE 0x0030
+#define FLOAT_PERCENTAGE 0x0031
+
+//////////////////////////////////////
+//The tMaterialInfo Struct
+//////////////////////////////////////
+class Material {
+public:
+ char name[256];
+ UChar_t color[3];
+ UShort_t transparency;
+
+ Material() {
+ sprintf(name, "");
+ color[0] = color[1] = color[2] = 0;
+ transparency = 0;
+ }
+ ~Material() { }
+};
+
+
+// Chunk structure
+typedef struct _Chunk {
+ UShort_t idnum;
+ ULong_t offset, len, endoffset;
+} Chunk;
+
+// vertex structure
+typedef struct _Vertex {
+ Float_t x, y, z;
+ Float_t u, v;
+} Vertex;
+
+// face structure
+typedef struct _Face {
+ ULong_t v1, v2, v3;
+} Face;
+
+// model structure
+class Model {
+public:
+ char name[256];
+ char matname[256];
+ Vertex *vlist;
+ Face *flist;
+ ULong_t numverts, numfaces;
+
+ Model() {
+ sprintf(name,"");
+ sprintf(matname,"");
+ vlist = 0;
+ flist = 0;
+ numverts = numfaces = 0;
+ }
+ ~Model() {
+ if (vlist != 0) delete [] vlist;
+ if (flist != 0) delete [] flist;
+ }
+};
+
+// chunk reading routines
+Int_t ReadChunk(FILE*, Chunk*);
+
+// data reading routines
+Int_t ReadMainChunk(FILE*);
+Int_t Read3DChunk(FILE*, ULong_t);
+Int_t ReadObjectChunk(FILE*, ULong_t);
+Int_t ReadMeshChunk(FILE*, ULong_t, char*);
+Int_t ReadVerticesChunk(FILE*);
+Int_t ReadFacesChunk(FILE*);
+Int_t ReadMappingChunk(FILE*);
+Int_t ReadASCIIZ(FILE*, char*);
+Int_t ReadMaterialChunk(FILE *, ULong_t);
+Int_t ReadColor(FILE *, ULong_t);
+Int_t ReadTransparency(FILE *, ULong_t);
+Int_t ReadObjectMaterial(FILE *);
+Int_t ConvertModel();
+
+// global variables
+Int_t nummodels = 0;
+Model model = {"","",0,0,0,0};
+
+Int_t nummaterials = 0;
+Material *material[1024];
+
+//______________________________________________________________________________
+Int_t Read3DSFile(const char *fname)
+{
+ // main function
+
+ FILE *infile;
+
+ infile = fopen(fname, "rb");
+ if (infile == 0) {
+ printf("Error : Input File Could Not Be Opened!\n");
+ return -1;
+ }
+ UShort_t magic = MAGICNUMBER;
+ if (ReadMainChunk(infile) != 0) {
+ printf("Error : Input File Could Not Be Read!\n");
+ }
+ fclose(infile);
+ return 0;
+}
+
+//______________________________________________________________________________
+Int_t ReadChunk(FILE *f, Chunk *c)
+{
+ // reads a chunk from an opened file
+
+ if (feof(f)) return(-1);
+ c->idnum = 0;
+ c->offset = c->len = 0;
+ c->offset = (ULong_t) ftell(f);
+ fread(&c->idnum, sizeof(UShort_t), 1, f);
+ fread(&c->len, sizeof(ULong_t), 1, f);
+ c->endoffset = c->offset + c->len;
+ return(0);
+}
+
+//______________________________________________________________________________
+Int_t ReadMainChunk(FILE *f)
+{
+ // handles the main body of the 3DS file
+
+ Chunk chunk;
+
+ ReadChunk(f, &chunk);
+ if (chunk.idnum != CHUNKMAIN) return(-1);
+ while ((ReadChunk(f, &chunk) == 0) && (!feof(f))) {
+ if (chunk.idnum == CHUNK3D) {
+ Read3DChunk(f, chunk.endoffset);
+ }
+ else {
+ //printf("Debug : Unknown Chunk [Main Chunk] [0x%x]\n", chunk.idnum);
+ fseek(f, chunk.offset + chunk.len, SEEK_SET);
+ }
+ }
+ return 0;
+}
+
+//______________________________________________________________________________
+Int_t Read3DChunk(FILE *f, ULong_t len)
+{
+ // reads the 3D Edit Chunk
+
+ Chunk chunk;
+
+ while ((ReadChunk(f, &chunk) == 0) && (!feof(f))) {
+ if (chunk.idnum == CHUNK3DOBJECT) {
+ ReadObjectChunk(f, chunk.endoffset);
+ fseek(f, chunk.endoffset, SEEK_SET);
+ }
+ else if (chunk.idnum == CHUNK3DMATERIAL) {
+ ReadMaterialChunk(f, chunk.endoffset);
+ fseek(f, chunk.endoffset, SEEK_SET);
+ }
+ else {
+ if (chunk.endoffset < len) {
+ //printf("Debug : Unknown Chunk [3D Chunk] [0x%x]\n", chunk.idnum);
+ fseek(f, chunk.endoffset, SEEK_SET);
+ }
+ else {
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+//______________________________________________________________________________
+Int_t ReadMaterialChunk(FILE *f, ULong_t len)
+{
+ // reads the Material sub-chunk of the 3D Edit Chunk
+
+ Chunk chunk;
+ char name[256];
+ char rgb[3];
+ material[nummaterials] = new Material();
+ while ((ReadChunk(f, &chunk) == 0) && (!feof(f))) {
+ if (chunk.idnum == MATNAME) {
+ ReadASCIIZ(f, name);
+ strcpy(material[nummaterials]->name, name);
+ fseek(f, chunk.endoffset, SEEK_SET);
+ }
+ else if (chunk.idnum == MATDIFFUSE) {
+ ReadColor(f, chunk.endoffset);
+ fseek(f, chunk.endoffset, SEEK_SET);
+ }
+ else if (chunk.idnum == MATTRANSPARENCY) {
+ ReadTransparency(f, chunk.endoffset);
+ fseek(f, chunk.endoffset, SEEK_SET);
+ }
+ else {
+ if (chunk.endoffset < len) {
+ //printf("Debug : Unknown Chunk [Object Chunk] [0x%x]\n", chunk.idnum);
+ fseek(f, chunk.endoffset, SEEK_SET);
+ }
+ else {
+ break;
+ }
+ }
+ }
+ nummaterials++;
+ return 0;
+}
+
+//______________________________________________________________________________
+Int_t ReadColor(FILE *f, ULong_t len)
+{
+ // reads the Color property of the Material Chunk
+
+ Chunk chunk;
+ float fr, fg, fb;
+ int irgb[3];
+ while ((ReadChunk(f, &chunk) == 0) && (!feof(f))) {
+ if (chunk.idnum == LIN_COLOR_24) {
+ fread(&material[nummaterials]->color[0], sizeof(UChar_t), 1, f);
+ fread(&material[nummaterials]->color[1], sizeof(UChar_t), 1, f);
+ fread(&material[nummaterials]->color[2], sizeof(UChar_t), 1, f);
+ fseek(f, chunk.endoffset, SEEK_SET);
+ }
+ else if (chunk.idnum == COLOR_24) {
+ fread(&material[nummaterials]->color[0], sizeof(UChar_t), 1, f);
+ fread(&material[nummaterials]->color[1], sizeof(UChar_t), 1, f);
+ fread(&material[nummaterials]->color[2], sizeof(UChar_t), 1, f);
+ fseek(f, chunk.endoffset, SEEK_SET);
+ }
+ else if (chunk.idnum == LIN_COLOR_F) {
+ fread(&fr, sizeof(Float_t), 1, f);
+ fread(&fg, sizeof(Float_t), 1, f);
+ fread(&fb, sizeof(Float_t), 1, f);
+ fseek(f, chunk.endoffset, SEEK_SET);
+ }
+ else if (chunk.idnum == COLOR_F) {
+ fread(&fr, sizeof(Float_t), 1, f);
+ fread(&fg, sizeof(Float_t), 1, f);
+ fread(&fb, sizeof(Float_t), 1, f);
+ fseek(f, chunk.endoffset, SEEK_SET);
+ }
+ else {
+ if (chunk.endoffset < len) {
+ //printf("Debug : Unknown Chunk [Mesh Chunk] [0x%x]\n", chunk.idnum);
+ fseek(f, chunk.endoffset, SEEK_SET);
+ }
+ else {
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+//______________________________________________________________________________
+Int_t ReadTransparency(FILE *f, ULong_t len)
+{
+ // reads the Transparency property of the Material Chunk
+
+ Chunk chunk;
+ char byte[2];
+ float ftransp;
+ UShort_t stransp;
+ while ((ReadChunk(f, &chunk) == 0) && (!feof(f))) {
+ if (chunk.idnum == INT_PERCENTAGE) {
+ fread(&stransp, sizeof(UShort_t), 1, f);
+ material[nummaterials]->transparency = stransp;
+ fseek(f, chunk.endoffset, SEEK_SET);
+ }
+ else if (chunk.idnum == FLOAT_PERCENTAGE) {
+ fread(&ftransp, sizeof(float), 1, f);
+ fseek(f, chunk.endoffset, SEEK_SET);
+ }
+ else {
+ if (chunk.endoffset < len) {
+ //printf("Debug : Unknown Chunk [Mesh Chunk] [0x%x]\n", chunk.idnum);
+ fseek(f, chunk.endoffset, SEEK_SET);
+ }
+ else {
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+//______________________________________________________________________________
+Int_t ReadObjectMaterial(FILE *f)
+{
+ // reads the name of material associated to the current Chunk
+
+ ReadASCIIZ(f, model.matname);
+ return 0;
+}
+
+//______________________________________________________________________________
+Int_t ReadObjectChunk(FILE *f, ULong_t len)
+{
+ // reads the Object sub-chunk of the 3D Edit Chunk
+
+ Chunk chunk;
+ char name[256];
+ ReadASCIIZ(f, name);
+ while ((ReadChunk(f, &chunk) == 0) && (!feof(f))) {
+ if (chunk.idnum == CHUNK3DOBJECTMESH) {
+ ReadMeshChunk(f, chunk.endoffset, name);
+ }
+ else {
+ if (chunk.endoffset < len) {
+ //printf("Debug : Unknown Chunk [Object Chunk] [0x%x]\n", chunk.idnum);
+ fseek(f, chunk.endoffset, SEEK_SET);
+ }
+ else {
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+//______________________________________________________________________________
+Int_t ReadMeshChunk(FILE *f, ULong_t len, char *objname)
+{
+ // reads the TriMesh sub-chunk of the Object Chunk
+
+ Int_t i;
+ Chunk chunk;
+ model.vlist = 0;
+ model.flist = 0;
+ model.numverts = model.numfaces = 0;
+ sprintf(model.name, "%s", objname);
+ printf("Reading Mesh : %s\n", objname);
+ while ((ReadChunk(f, &chunk) == 0) && (!feof(f))) {
+ if (chunk.idnum == CHUNK3DOBJECTMESHVERTICES) {
+ ReadVerticesChunk(f);
+ }
+ else if (chunk.idnum == CHUNK3DOBJECTMESHFACES) {
+ ReadFacesChunk(f);
+ }
+ else if (chunk.idnum == CHUNK3DOBJECTMESHMAPPING) {
+ ReadMappingChunk(f);
+ }
+ else if (chunk.idnum == CHUNK3DOBJECTMESHMATGROUP) {
+ ReadObjectMaterial(f);
+ }
+ else {
+ if (chunk.endoffset < len) {
+ //printf("Debug : Unknown Chunk [Mesh Chunk] [0x%x]\n", chunk.idnum);
+ fseek(f, chunk.endoffset, SEEK_SET);
+ }
+ else {
+ break;
+ }
+ }
+ }
+ if (model.numverts != 0 && model.numfaces != 0 &&
+ model.vlist != 0 && model.flist != 0) {
+ ConvertModel();
+ }
+ if (model.vlist != 0) delete [] model.vlist;
+ if (model.flist != 0) delete [] model.flist;
+ model.vlist = 0;
+ model.flist = 0;
+ model.numverts = model.numfaces = 0;
+ sprintf(model.name,"");
+ nummodels++;
+ return 0;
+}
+
+//______________________________________________________________________________
+Int_t ReadVerticesChunk(FILE *f)
+{
+ // reads Vertex data of the TriMesh Chunk
+
+ Int_t i;
+ UShort_t numv = 0;
+ Float_t x, y, z;
+
+ fread(&numv, sizeof(UShort_t), 1, f);
+ printf("Reading %i Vertices...", numv);
+ model.vlist = new Vertex[numv];
+ if (model.vlist == 0) {
+ for (i = 0; i < numv; i++) {
+ fread(&x, sizeof(Float_t), 1, f);
+ fread(&y, sizeof(Float_t), 1, f);
+ fread(&z, sizeof(Float_t), 1, f);
+ }
+ printf("\nWarning : Insufficient Memory to Load Vertices!\n");
+ return -1;
+ }
+ for (i = 0; i < numv; i++) {
+ fread(&model.vlist[i].x, sizeof(Float_t), 1, f);
+ fread(&model.vlist[i].y, sizeof(Float_t), 1, f);
+ fread(&model.vlist[i].z, sizeof(Float_t), 1, f);
+ }
+ model.numverts = (ULong_t) numv;
+ printf("Done!\n");
+ return 0;
+}
+
+//______________________________________________________________________________
+Int_t ReadFacesChunk(FILE *f)
+{
+ // reads Face data of the TriMesh Chunk
+
+ Int_t i;
+ UShort_t numf = 0, v1, v2, v3, attr;
+
+ fread(&numf, sizeof(UShort_t), 1, f);
+ printf("Reading %i Faces...", numf);
+ model.flist = new Face[numf];
+ if (model.flist == 0) {
+ for (i = 0; i < numf; i++) {
+ fread(&v1, sizeof(UShort_t), 1, f);
+ fread(&v2, sizeof(UShort_t), 1, f);
+ fread(&v3, sizeof(UShort_t), 1, f);
+ fread(&attr, sizeof(UShort_t), 1, f);
+ }
+ printf("\nWarning : Insufficient Memory to Load Faces!\n");
+ return -1;
+ }
+ for (i = 0; i < numf; i++) {
+ fread(&v1, sizeof(UShort_t), 1, f);
+ fread(&v2, sizeof(UShort_t), 1, f);
+ fread(&v3, sizeof(UShort_t), 1, f);
+ fread(&attr, sizeof(UShort_t), 1, f);
+ model.flist[i].v1 = (ULong_t)(v1);
+ model.flist[i].v2 = (ULong_t)(v2);
+ model.flist[i].v3 = (ULong_t)(v3);
+ }
+ model.numfaces = (ULong_t)(numf);
+ printf("Done!\n");
+ return 0;
+}
+
+//______________________________________________________________________________
+Int_t ReadMappingChunk(FILE *f)
+{
+ // reads Texture Mapping data of the TriMesh Chunk
+
+ UShort_t numuv = 0, i;
+ Float_t u, v;
+
+ fread(&numuv, sizeof(UShort_t), 1, f);
+ printf("Reading %i Texture Coordinates...", numuv);
+ if (numuv != model.numverts) {
+ for (i = 0; i < numuv; i++) {
+ fread(&u, sizeof(Float_t), 1, f);
+ fread(&v, sizeof(Float_t), 1, f);
+ }
+ printf("\nWarning : Number of Vertices and Mapping Data do not match!\n");
+ return -1;
+ }
+ for (i = 0; i < numuv; i++) {
+ fread(&model.vlist[i].u, sizeof(Float_t), 1, f);
+ fread(&model.vlist[i].v, sizeof(Float_t), 1, f);
+ }
+ printf("Done!\n");
+ return 0;
+}
+
+//______________________________________________________________________________
+Int_t ReadASCIIZ(FILE *f, char *name)
+{
+ // reads a null-terminated string from the given file
+
+ char c = -1;
+ Int_t index = 0;
+
+ do {
+ fread(&c, sizeof(char), 1, f);
+ name[index] = c;
+ index++;
+ if (index == 255) {
+ name[index] = 0;
+ c = 0;
+ }
+ } while ((c != 0) && (!feof(f)));
+ return 0;
+}
+
+//______________________________________________________________________________
+Int_t ConvertModel()
+{
+ // Convert from Model structure to Reve::TriangleSet
+
+ Int_t i;
+
+ ts[nummodels] = new Reve::TriangleSet(model.numverts, model.numfaces);
+ if (ts[nummodels] == 0)
+ return -1;
+ for (i=0; i<model.numverts; ++i) {
+ ts[nummodels]->SetVertex(i, model.vlist[i].x, model.vlist[i].y,
+ model.vlist[i].z);
+ }
+ for (i=0; i<model.numfaces; ++i) {
+ ts[nummodels]->SetTriangle(i, model.flist[i].v1, model.flist[i].v2,
+ model.flist[i].v3);
+ }
+ ts[nummodels]->SetName(model.name);
+ ts[nummodels]->SetTransparency(0);
+ ts[nummodels]->SetColor(0);
+ for (i = 0; i < nummaterials; i++) {
+ if (strcmp(model.matname, material[i]->name) == 0) {
+ ts[nummodels]->SetTransparency(material[i]->transparency);
+ ts[nummodels]->SetColor(Color_t(TColor::GetColor(material[i]->color[0],
+ material[i]->color[1], material[i]->color[2])));
+ break;
+ }
+ }
+ return 0;
+}
+
+//______________________________________________________________________________
+void view3ds(const char *fname = "nasashuttle.3ds") //"eventhorizon.3ds")
+{
+ // main...
+
+ Int_t i;
+ for (i=0;i<2048;i++) ts[i] = 0;
+ for (i=0;i<1024;i++) material[i] = 0;
+ model.vlist = 0;
+ model.flist = 0;
+ nummodels = 0;
+ if (Read3DSFile(fname) == 0) {
+ for (i=0;i<nummodels;i++) {
+ if (ts[i]) {
+ ts[i]->GenerateTriangleNormals();
+ gReve->AddRenderElement(ts[i]);
+ }
+ }
+ gReve->Redraw3D(kTRUE);
+ }
+ for (i = 0; i < nummaterials; i++)
+ if (material[i] != 0) delete material[i];
+}