Logo ROOT  
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
21class TEveTriangleSet;
22
23TEveTriangleSet *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//////////////////////////////////////
57class Material {
58public:
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
73typedef struct _Chunk {
74 UShort_t idnum;
75 UInt_t offset, len, endoffset;
76} Chunk;
77
78// vertex structure
79typedef struct _Vertex {
80 Float_t x, y, z;
81 Float_t u, v;
82} Vertex;
83
84// face structure
85typedef struct _Face {
86 UInt_t v1, v2, v3;
87} Face;
88
89// model structure
90class Model {
91public:
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
112Int_t ReadChunk(FILE*, Chunk*);
113
114// data reading routines
115Int_t ReadMainChunk(FILE*);
116Int_t Read3DChunk(FILE*, UInt_t);
117Int_t ReadObjectChunk(FILE*, UInt_t);
118Int_t ReadMeshChunk(FILE*, UInt_t, char*);
119Int_t ReadVerticesChunk(FILE*);
120Int_t ReadFacesChunk(FILE*);
121Int_t ReadMappingChunk(FILE*);
122Int_t ReadASCIIZ(FILE*, char*);
123Int_t ReadMaterialChunk(FILE *, UInt_t);
124Int_t ReadColor(FILE *, UInt_t);
125Int_t ReadTransparency(FILE *, UInt_t);
126Int_t ReadObjectMaterial(FILE *);
127Int_t ConvertModel();
128
129// global variables
130Int_t nummodels = 0;
131Model model;
132
133Int_t nummaterials = 0;
134Material *material[1024];
135
136//______________________________________________________________________________
137Int_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//______________________________________________________________________________
157Int_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//______________________________________________________________________________
172Int_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//______________________________________________________________________________
193Int_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//______________________________________________________________________________
222Int_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//______________________________________________________________________________
258Int_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//______________________________________________________________________________
303Int_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//______________________________________________________________________________
334Int_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//______________________________________________________________________________
343Int_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//______________________________________________________________________________
368Int_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//______________________________________________________________________________
413Int_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//______________________________________________________________________________
444Int_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//______________________________________________________________________________
479Int_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//______________________________________________________________________________
505Int_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//______________________________________________________________________________
525Int_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//______________________________________________________________________________
558void 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]) {
577 ts[i]->RefMainTrans().RotateLF(1, 2, TMath::Pi());
578 parent->AddElement(ts[i]);
579 }
580 }
582 }
583 for (i = 0; i < nummaterials; i++)
584 if (material[i] != 0) delete material[i];
585}
#define f(i)
Definition: RSha256.hxx:104
#define c(i)
Definition: RSha256.hxx:101
unsigned short UShort_t
Definition: RtypesCore.h:38
int Int_t
Definition: RtypesCore.h:43
unsigned char UChar_t
Definition: RtypesCore.h:36
unsigned int UInt_t
Definition: RtypesCore.h:44
float Float_t
Definition: RtypesCore.h:55
const Bool_t kTRUE
Definition: RtypesCore.h:89
R__EXTERN TEveManager * gEve
Definition: TEveManager.h:243
char name[80]
Definition: TGX11.cxx:109
virtual void AddElement(TEveElement *el)
Add el to the list of children.
virtual void SetMainTransparency(Char_t t)
Set main-transparency.
virtual TEveTrans & RefMainTrans()
Return reference to main transformation.
virtual void SetMainColor(Color_t color)
Set main color of the element.
void SetMainColorRGB(UChar_t r, UChar_t g, UChar_t b)
Convert RGB values to Color_t and call SetMainColor.
void AddElement(TEveElement *element, TEveElement *parent=0)
Add an element.
static TEveManager * Create(Bool_t map_window=kTRUE, Option_t *opt="FIV")
If global TEveManager* gEve is not set initialize it.
void Redraw3D(Bool_t resetCameras=kFALSE, Bool_t dropLogicals=kFALSE)
Definition: TEveManager.h:168
void RotateLF(Int_t i1, Int_t i2, Double_t amount)
Rotate in local frame. Does optimised version of MultRight.
Definition: TEveTrans.cxx:375
Made from a list of vertices and a list of triangles (triplets of vertex indices).
void SetTriangle(Int_t i, Int_t v0, Int_t v1, Int_t v2)
void SetVertex(Int_t i, Float_t x, Float_t y, Float_t z)
void GenerateTriangleNormals()
Generate triangle normals via cross product of triangle edges.
virtual void SetName(const char *name)
Set the name of the TNamed.
Definition: TNamed.cxx:140
Double_t y[n]
Definition: legend1.C:17
Double_t x[n]
Definition: legend1.C:17
void Vertex(const Double_t *v)
constexpr Double_t Pi()
Definition: TMath.h:38