Logo ROOT   6.07/09
Reference Guide
view3ds.C
Go to the documentation of this file.
1 /// \file
2 /// \ingroup tutorial_eve
3 /// Loading and display of basic 3DS models.
4 ///
5 /// \image html eve_view3ds.png
6 /// \macro_code
7 ///
8 /// \author Bertrand Bellenot
9 
10 #include "TCanvas.h"
11 #include "TStyle.h"
12 #include "TFile.h"
13 #include "TStopwatch.h"
14 #include "TError.h"
15 
16 #include <math.h>
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 
21 class TEveTriangleSet;
22 
23 TEveTriangleSet *ts[2048];
24 
25 // Believe3D Model file defines
26 #define MAGICNUMBER 0xB3D0
27 
28 // types of 3DS Chunks
29 #define CHUNKMAIN 0x4D4D
30 #define CHUNKMAINVERSION 0x0002
31 #define CHUNK3D 0x3D3D
32 #define CHUNK3DVERSION 0x3D3E
33 #define CHUNK3DOBJECT 0x4000
34 #define CHUNK3DOBJECTMESH 0x4100
35 #define CHUNK3DOBJECTMESHVERTICES 0x4110
36 #define CHUNK3DOBJECTMESHFACES 0x4120
37 #define CHUNK3DOBJECTMESHMATGROUP 0x4130
38 #define CHUNK3DOBJECTMESHMAPPING 0x4140
39 
40 #define CHUNK3DMATERIAL 0xAFFF
41 // Sub defines of MATERIAL
42 #define MATNAME 0xA000
43 #define MATDIFFUSE 0xA020
44 #define MATSPECULAR 0xA030
45 #define MATTRANSPARENCY 0xA050
46 
47 #define COLOR_F 0x0010
48 #define COLOR_24 0x0011
49 #define LIN_COLOR_24 0x0012
50 #define LIN_COLOR_F 0x0013
51 #define INT_PERCENTAGE 0x0030
52 #define FLOAT_PERCENTAGE 0x0031
53 
54 //////////////////////////////////////
55 //The tMaterialInfo Struct
56 //////////////////////////////////////
57 class Material {
58 public:
59  char name[256];
60  UChar_t color[3];
61  UShort_t transparency;
62 
63  Material() {
64  sprintf(name, "");
65  color[0] = color[1] = color[2] = 0;
66  transparency = 0;
67  }
68  ~Material() { }
69 };
70 
71 
72 // Chunk structure
73 typedef struct _Chunk {
74  UShort_t idnum;
75  UInt_t offset, len, endoffset;
76 } Chunk;
77 
78 // vertex structure
79 typedef struct _Vertex {
80  Float_t x, y, z;
81  Float_t u, v;
82 } Vertex;
83 
84 // face structure
85 typedef struct _Face {
86  UInt_t v1, v2, v3;
87 } Face;
88 
89 // model structure
90 class Model {
91 public:
92  char name[256];
93  char matname[256];
94  Vertex *vlist;
95  Face *flist;
96  UInt_t numverts, numfaces;
97 
98  Model() {
99  sprintf(name,"");
100  sprintf(matname,"");
101  vlist = 0;
102  flist = 0;
103  numverts = numfaces = 0;
104  }
105  ~Model() {
106  if (vlist != 0) delete [] vlist;
107  if (flist != 0) delete [] flist;
108  }
109 };
110 
111 // chunk reading routines
112 Int_t ReadChunk(FILE*, Chunk*);
113 
114 // data reading routines
115 Int_t ReadMainChunk(FILE*);
116 Int_t Read3DChunk(FILE*, UInt_t);
117 Int_t ReadObjectChunk(FILE*, UInt_t);
118 Int_t ReadMeshChunk(FILE*, UInt_t, char*);
119 Int_t ReadVerticesChunk(FILE*);
120 Int_t ReadFacesChunk(FILE*);
121 Int_t ReadMappingChunk(FILE*);
122 Int_t ReadASCIIZ(FILE*, char*);
123 Int_t ReadMaterialChunk(FILE *, UInt_t);
124 Int_t ReadColor(FILE *, UInt_t);
125 Int_t ReadTransparency(FILE *, UInt_t);
126 Int_t ReadObjectMaterial(FILE *);
127 Int_t ConvertModel();
128 
129 // global variables
130 Int_t nummodels = 0;
131 Model model;
132 
133 Int_t nummaterials = 0;
134 Material *material[1024];
135 
136 //______________________________________________________________________________
137 Int_t Read3DSFile(const char *fname)
138 {
139  // main function
140 
141  FILE *infile;
142 
143  infile = fopen(fname, "rb");
144  if (infile == 0) {
145  printf("Error : Input File Could Not Be Opened!\n");
146  return -1;
147  }
148  UShort_t magic = MAGICNUMBER;
149  if (ReadMainChunk(infile) != 0) {
150  printf("Error : Input File Could Not Be Read!\n");
151  }
152  fclose(infile);
153  return 0;
154 }
155 
156 //______________________________________________________________________________
157 Int_t ReadChunk(FILE *f, Chunk *c)
158 {
159  // reads a chunk from an opened file
160 
161  if (feof(f)) return(-1);
162  c->idnum = 0;
163  c->offset = c->len = 0;
164  c->offset = (UInt_t) ftell(f);
165  fread(&c->idnum, sizeof(UShort_t), 1, f);
166  fread(&c->len, sizeof(UInt_t), 1, f);
167  c->endoffset = c->offset + c->len;
168  return(0);
169 }
170 
171 //______________________________________________________________________________
172 Int_t ReadMainChunk(FILE *f)
173 {
174  // handles the main body of the 3DS file
175 
176  Chunk chunk;
177 
178  ReadChunk(f, &chunk);
179  if (chunk.idnum != CHUNKMAIN) return(-1);
180  while ((ReadChunk(f, &chunk) == 0) && (!feof(f))) {
181  if (chunk.idnum == CHUNK3D) {
182  Read3DChunk(f, chunk.endoffset);
183  }
184  else {
185  //printf("Debug : Unknown Chunk [Main Chunk] [0x%x]\n", chunk.idnum);
186  fseek(f, chunk.offset + chunk.len, SEEK_SET);
187  }
188  }
189  return 0;
190 }
191 
192 //______________________________________________________________________________
193 Int_t Read3DChunk(FILE *f, UInt_t len)
194 {
195  // reads the 3D Edit Chunk
196 
197  Chunk chunk;
198 
199  while ((ReadChunk(f, &chunk) == 0) && (!feof(f))) {
200  if (chunk.idnum == CHUNK3DOBJECT) {
201  ReadObjectChunk(f, chunk.endoffset);
202  fseek(f, chunk.endoffset, SEEK_SET);
203  }
204  else if (chunk.idnum == CHUNK3DMATERIAL) {
205  ReadMaterialChunk(f, chunk.endoffset);
206  fseek(f, chunk.endoffset, SEEK_SET);
207  }
208  else {
209  if (chunk.endoffset < len) {
210  //printf("Debug : Unknown Chunk [3D Chunk] [0x%x]\n", chunk.idnum);
211  fseek(f, chunk.endoffset, SEEK_SET);
212  }
213  else {
214  break;
215  }
216  }
217  }
218  return 0;
219 }
220 
221 //______________________________________________________________________________
222 Int_t ReadMaterialChunk(FILE *f, UInt_t len)
223 {
224  // reads the Material sub-chunk of the 3D Edit Chunk
225 
226  Chunk chunk;
227  char name[256];
228  material[nummaterials] = new Material();
229  while ((ReadChunk(f, &chunk) == 0) && (!feof(f))) {
230  if (chunk.idnum == MATNAME) {
231  ReadASCIIZ(f, name);
232  strcpy(material[nummaterials]->name, name);
233  fseek(f, chunk.endoffset, SEEK_SET);
234  }
235  else if (chunk.idnum == MATDIFFUSE) {
236  ReadColor(f, chunk.endoffset);
237  fseek(f, chunk.endoffset, SEEK_SET);
238  }
239  else if (chunk.idnum == MATTRANSPARENCY) {
240  ReadTransparency(f, chunk.endoffset);
241  fseek(f, chunk.endoffset, SEEK_SET);
242  }
243  else {
244  if (chunk.endoffset < len) {
245  //printf("Debug : Unknown Chunk [Object Chunk] [0x%x]\n", chunk.idnum);
246  fseek(f, chunk.endoffset, SEEK_SET);
247  }
248  else {
249  break;
250  }
251  }
252  }
253  nummaterials++;
254  return 0;
255 }
256 
257 //______________________________________________________________________________
258 Int_t ReadColor(FILE *f, UInt_t len)
259 {
260  // reads the Color property of the Material Chunk
261 
262  Chunk chunk;
263  float fr, fg, fb;
264  while ((ReadChunk(f, &chunk) == 0) && (!feof(f))) {
265  if (chunk.idnum == LIN_COLOR_24) {
266  fread(&material[nummaterials]->color[0], sizeof(UChar_t), 1, f);
267  fread(&material[nummaterials]->color[1], sizeof(UChar_t), 1, f);
268  fread(&material[nummaterials]->color[2], sizeof(UChar_t), 1, f);
269  fseek(f, chunk.endoffset, SEEK_SET);
270  }
271  else if (chunk.idnum == COLOR_24) {
272  fread(&material[nummaterials]->color[0], sizeof(UChar_t), 1, f);
273  fread(&material[nummaterials]->color[1], sizeof(UChar_t), 1, f);
274  fread(&material[nummaterials]->color[2], sizeof(UChar_t), 1, f);
275  fseek(f, chunk.endoffset, SEEK_SET);
276  }
277  else if (chunk.idnum == LIN_COLOR_F) {
278  fread(&fr, sizeof(Float_t), 1, f);
279  fread(&fg, sizeof(Float_t), 1, f);
280  fread(&fb, sizeof(Float_t), 1, f);
281  fseek(f, chunk.endoffset, SEEK_SET);
282  }
283  else if (chunk.idnum == COLOR_F) {
284  fread(&fr, sizeof(Float_t), 1, f);
285  fread(&fg, sizeof(Float_t), 1, f);
286  fread(&fb, sizeof(Float_t), 1, f);
287  fseek(f, chunk.endoffset, SEEK_SET);
288  }
289  else {
290  if (chunk.endoffset < len) {
291  //printf("Debug : Unknown Chunk [Mesh Chunk] [0x%x]\n", chunk.idnum);
292  fseek(f, chunk.endoffset, SEEK_SET);
293  }
294  else {
295  break;
296  }
297  }
298  }
299  return 0;
300 }
301 
302 //______________________________________________________________________________
303 Int_t ReadTransparency(FILE *f, UInt_t len)
304 {
305  // reads the Transparency property of the Material Chunk
306 
307  Chunk chunk;
308  float ftransp;
309  UShort_t stransp;
310  while ((ReadChunk(f, &chunk) == 0) && (!feof(f))) {
311  if (chunk.idnum == INT_PERCENTAGE) {
312  fread(&stransp, sizeof(UShort_t), 1, f);
313  material[nummaterials]->transparency = stransp;
314  fseek(f, chunk.endoffset, SEEK_SET);
315  }
316  else if (chunk.idnum == FLOAT_PERCENTAGE) {
317  fread(&ftransp, sizeof(float), 1, f);
318  fseek(f, chunk.endoffset, SEEK_SET);
319  }
320  else {
321  if (chunk.endoffset < len) {
322  //printf("Debug : Unknown Chunk [Mesh Chunk] [0x%x]\n", chunk.idnum);
323  fseek(f, chunk.endoffset, SEEK_SET);
324  }
325  else {
326  break;
327  }
328  }
329  }
330  return 0;
331 }
332 
333 //______________________________________________________________________________
334 Int_t ReadObjectMaterial(FILE *f)
335 {
336  // reads the name of material associated to the current Chunk
337 
338  ReadASCIIZ(f, model.matname);
339  return 0;
340 }
341 
342 //______________________________________________________________________________
343 Int_t ReadObjectChunk(FILE *f, UInt_t len)
344 {
345  // reads the Object sub-chunk of the 3D Edit Chunk
346 
347  Chunk chunk;
348  char name[256];
349  ReadASCIIZ(f, name);
350  while ((ReadChunk(f, &chunk) == 0) && (!feof(f))) {
351  if (chunk.idnum == CHUNK3DOBJECTMESH) {
352  ReadMeshChunk(f, chunk.endoffset, name);
353  }
354  else {
355  if (chunk.endoffset < len) {
356  //printf("Debug : Unknown Chunk [Object Chunk] [0x%x]\n", chunk.idnum);
357  fseek(f, chunk.endoffset, SEEK_SET);
358  }
359  else {
360  break;
361  }
362  }
363  }
364  return 0;
365 }
366 
367 //______________________________________________________________________________
368 Int_t ReadMeshChunk(FILE *f, UInt_t len, char *objname)
369 {
370  // reads the TriMesh sub-chunk of the Object Chunk
371 
372  Chunk chunk;
373  model.vlist = 0;
374  model.flist = 0;
375  model.numverts = model.numfaces = 0;
376  sprintf(model.name, "%s", objname);
377  printf("Reading Mesh : %s\n", objname);
378  while ((ReadChunk(f, &chunk) == 0) && (!feof(f))) {
379  if (chunk.idnum == CHUNK3DOBJECTMESHVERTICES) {
380  ReadVerticesChunk(f);
381  }
382  else if (chunk.idnum == CHUNK3DOBJECTMESHFACES) {
383  ReadFacesChunk(f);
384  }
385  else if (chunk.idnum == CHUNK3DOBJECTMESHMAPPING) {
386  ReadMappingChunk(f);
387  }
388  else if (chunk.idnum == CHUNK3DOBJECTMESHMATGROUP) {
389  ReadObjectMaterial(f);
390  }
391  else {
392  if (chunk.endoffset < len) {
393  //printf("Debug : Unknown Chunk [Mesh Chunk] [0x%x]\n", chunk.idnum);
394  fseek(f, chunk.endoffset, SEEK_SET);
395  }
396  else {
397  break;
398  }
399  }
400  }
401  ConvertModel();
402  if (model.vlist != 0) delete [] model.vlist;
403  if (model.flist != 0) delete [] model.flist;
404  model.vlist = 0;
405  model.flist = 0;
406  model.numverts = model.numfaces = 0;
407  sprintf(model.name,"");
408  nummodels++;
409  return 0;
410 }
411 
412 //______________________________________________________________________________
413 Int_t ReadVerticesChunk(FILE *f)
414 {
415  // reads Vertex data of the TriMesh Chunk
416 
417  Int_t i;
418  UShort_t numv = 0;
419  Float_t x, y, z;
420 
421  fread(&numv, sizeof(UShort_t), 1, f);
422  printf("Reading %i Vertices...", numv);
423  model.vlist = new Vertex[numv];
424  if (model.vlist == 0) {
425  for (i = 0; i < numv; i++) {
426  fread(&x, sizeof(Float_t), 1, f);
427  fread(&y, sizeof(Float_t), 1, f);
428  fread(&z, sizeof(Float_t), 1, f);
429  }
430  printf("\nWarning : Insufficient Memory to Load Vertices!\n");
431  return -1;
432  }
433  for (i = 0; i < numv; i++) {
434  fread(&model.vlist[i].x, sizeof(Float_t), 1, f);
435  fread(&model.vlist[i].y, sizeof(Float_t), 1, f);
436  fread(&model.vlist[i].z, sizeof(Float_t), 1, f);
437  }
438  model.numverts = (UInt_t) numv;
439  printf("Done!\n");
440  return 0;
441 }
442 
443 //______________________________________________________________________________
444 Int_t ReadFacesChunk(FILE *f)
445 {
446  // reads Face data of the TriMesh Chunk
447 
448  Int_t i;
449  UShort_t numf = 0, v1, v2, v3, attr;
450 
451  fread(&numf, sizeof(UShort_t), 1, f);
452  printf("Reading %i Faces...", numf);
453  model.flist = new Face[numf];
454  if (model.flist == 0) {
455  for (i = 0; i < numf; i++) {
456  fread(&v1, sizeof(UShort_t), 1, f);
457  fread(&v2, sizeof(UShort_t), 1, f);
458  fread(&v3, sizeof(UShort_t), 1, f);
459  fread(&attr, sizeof(UShort_t), 1, f);
460  }
461  printf("\nWarning : Insufficient Memory to Load Faces!\n");
462  return -1;
463  }
464  for (i = 0; i < numf; i++) {
465  fread(&v1, sizeof(UShort_t), 1, f);
466  fread(&v2, sizeof(UShort_t), 1, f);
467  fread(&v3, sizeof(UShort_t), 1, f);
468  fread(&attr, sizeof(UShort_t), 1, f);
469  model.flist[i].v1 = (UInt_t)(v1);
470  model.flist[i].v2 = (UInt_t)(v2);
471  model.flist[i].v3 = (UInt_t)(v3);
472  }
473  model.numfaces = (UInt_t)(numf);
474  printf("Done!\n");
475  return 0;
476 }
477 
478 //______________________________________________________________________________
479 Int_t ReadMappingChunk(FILE *f)
480 {
481  // reads Texture Mapping data of the TriMesh Chunk
482 
483  UShort_t numuv = 0, i;
484  Float_t u, v;
485 
486  fread(&numuv, sizeof(UShort_t), 1, f);
487  printf("Reading %i Texture Coordinates...", numuv);
488  if (numuv != model.numverts) {
489  for (i = 0; i < numuv; i++) {
490  fread(&u, sizeof(Float_t), 1, f);
491  fread(&v, sizeof(Float_t), 1, f);
492  }
493  printf("\nWarning : Number of Vertices and Mapping Data do not match!\n");
494  return -1;
495  }
496  for (i = 0; i < numuv; i++) {
497  fread(&model.vlist[i].u, sizeof(Float_t), 1, f);
498  fread(&model.vlist[i].v, sizeof(Float_t), 1, f);
499  }
500  printf("Done!\n");
501  return 0;
502 }
503 
504 //______________________________________________________________________________
505 Int_t ReadASCIIZ(FILE *f, char *name)
506 {
507  // reads a null-terminated string from the given file
508 
509  char c = -1;
510  Int_t index = 0;
511 
512  do {
513  fread(&c, sizeof(char), 1, f);
514  name[index] = c;
515  index++;
516  if (index == 255) {
517  name[index] = 0;
518  c = 0;
519  }
520  } while ((c != 0) && (!feof(f)));
521  return 0;
522 }
523 
524 //______________________________________________________________________________
525 Int_t ConvertModel()
526 {
527  // Convert from Model structure to TEveTriangleSet
528 
529  Int_t i;
530 
531  ts[nummodels] = new TEveTriangleSet(model.numverts, model.numfaces);
532  if (ts[nummodels] == 0)
533  return -1;
534  for (i=0; i<model.numverts; ++i) {
535  ts[nummodels]->SetVertex(i, model.vlist[i].x, model.vlist[i].y,
536  model.vlist[i].z);
537  }
538  for (i=0; i<model.numfaces; ++i) {
539  ts[nummodels]->SetTriangle(i, model.flist[i].v1, model.flist[i].v2,
540  model.flist[i].v3);
541  }
542  ts[nummodels]->SetName(model.name);
543  ts[nummodels]->SetMainTransparency(0);
544  ts[nummodels]->SetMainColor(0);
545  for (i = 0; i < nummaterials; i++) {
546  if (strcmp(model.matname, material[i]->name) == 0) {
547  ts[nummodels]->SetMainTransparency(material[i]->transparency);
548  ts[nummodels]->SetMainColorRGB(material[i]->color[0],
549  material[i]->color[1],
550  material[i]->color[2]);
551  break;
552  }
553  }
554  return 0;
555 }
556 
557 //______________________________________________________________________________
558 void view3ds(const char *fname = "nasashuttle.3ds")
559 {
560  // Main.
561 
563 
564  Int_t i;
565  for (i=0;i<2048;i++) ts[i] = 0;
566  for (i=0;i<1024;i++) material[i] = 0;
567  model.vlist = 0;
568  model.flist = 0;
569  nummodels = 0;
570  if (Read3DSFile(fname) == 0) {
571  TEveTriangleSet* parent = new TEveTriangleSet(0, 0);
572  parent->SetName(fname);
573  gEve->AddElement(parent);
574  for (i=0;i<nummodels;i++) {
575  if (ts[i]) {
576  ts[i]->GenerateTriangleNormals();
577  ts[i]->RefMainTrans().RotateLF(1, 2, TMath::Pi());
578  parent->AddElement(ts[i]);
579  }
580  }
581  gEve->Redraw3D(kTRUE);
582  }
583  for (i = 0; i < nummaterials; i++)
584  if (material[i] != 0) delete material[i];
585 }
float Float_t
Definition: RtypesCore.h:53
return c
unsigned short UShort_t
Definition: RtypesCore.h:36
virtual void SetName(const char *name)
Set the name of the TNamed.
Definition: TNamed.cxx:131
void GenerateTriangleNormals()
Generate triangle normals via cross product of triangle edges.
int Int_t
Definition: RtypesCore.h:41
void Redraw3D(Bool_t resetCameras=kFALSE, Bool_t dropLogicals=kFALSE)
Definition: TEveManager.h:168
void SetTriangle(Int_t i, Int_t v0, Int_t v1, Int_t v2)
void AddElement(TEveElement *element, TEveElement *parent=0)
Add an element.
Double_t x[n]
Definition: legend1.C:17
static TEveManager * Create(Bool_t map_window=kTRUE, Option_t *opt="FIV")
If global TEveManager* gEve is not set initialize it.
SVector< double, 2 > v
Definition: Dict.h:5
R__EXTERN TEveManager * gEve
Definition: TEveManager.h:243
void SetMainColorRGB(UChar_t r, UChar_t g, UChar_t b)
Convert RGB values to Color_t and call SetMainColor.
unsigned int UInt_t
Definition: RtypesCore.h:42
virtual void AddElement(TEveElement *el)
Add el to the list of children.
virtual void SetMainColor(Color_t color)
Set main color of the element.
virtual void SetMainTransparency(Char_t t)
Set main-transparency.
Double_t Pi()
Definition: TMath.h:44
double f(double x)
Made from a list of vertices and a list of triangles (triplets of vertex indices).
Double_t y[n]
Definition: legend1.C:17
void RotateLF(Int_t i1, Int_t i2, Double_t amount)
Rotate in local frame. Does optimised version of MultRight.
Definition: TEveTrans.cxx:375
void SetVertex(Int_t i, Float_t x, Float_t y, Float_t z)
you should not use this method at all Int_t Int_t z
Definition: TRolke.cxx:630
virtual TEveTrans & RefMainTrans()
Return reference to main transformation.
unsigned char UChar_t
Definition: RtypesCore.h:34
const Bool_t kTRUE
Definition: Rtypes.h:91
char name[80]
Definition: TGX11.cxx:109
void Vertex(const Double_t *v)