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