1 /**************************************************************************\
2 * Copyright (c) Kongsberg Oil & Gas Technologies AS
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 *
12 * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * Neither the name of the copyright holder nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32
33 //
34 // 3DS File Loader for Open Inventor
35 //
36 // developed by PC John (peciva@fit.vutbr.cz)
37 //
38 //
39 // Comments about 3ds files: Structure of the 3ds files is well known
40 // (http://www.cyberloonies.com/3dsftk.html). However, it is often hard to
41 // understand what is the informations in 3ds file about and how to
42 // interpret them. For example, texture coordinates are not always
43 // represented by OpenGL texture coordinates, and I can't find out
44 // what is their meaning.
45 //
46 //
47 // All loaded models are centered around [0,0,0] and normalized to
48 // size 10 by default.
49 //
50 // If loading fails during reading 3ds file, file pointer position is
51 // undefined.
52 //
53 // By default only error messages are generated. COIN_DEBUG_3DS environment
54 // variable can be used to specify amount of debug messages:
55 // 0 .. only error messages (default)
56 // 1 .. warnings that usually concerns data parsed from the 3ds file
57 // 2 .. print basic 3ds file structure info
58 // 3 .. print everything
59 //
60 //
61 // TODO list:
62 //
63 // - incomplete texture implementation - in 3ds files there is possible to
64 // make materials with about 20 textures (diffuse color texture, specular
65 // texture, bump-map texture,...) There is not a support for them in the
66 // Inventor yet.
67 //
68 // - Texture coordinates are not always loaded right, because 3ds uses
69 // many strange mapping modes. Deeper understanding of 3ds will be needed
70 // to fix this.
71 //
72 // - Backface culling functionality is disabled because it does not work
73 // right on some models. It looks like some models are CLOCKWISE and other
74 // COUNTERCLOCKWISE.
75 //
76 // - unimplemented lights
77 //
78 // - per-vertex normals generation
79 //
80 // - investigate the color of the default material objects
81 //
82 // - ?environment? (ambient light, fog,...)
83 //
84 // - ?emissiveColor? (maybe MAT_SELF_ILLUM and MAT_SELF_ILPCT chunks)
85 //
86 // - some animations?
87 //
88 // - public API to control the loading
89 //
90 //
91
92
93 #include "SoStream.h"
94
95 #include "coindefs.h"
96
97 #include <Inventor/SbPlane.h>
98 #include <Inventor/SbRotation.h>
99 #include <Inventor/nodes/SoCoordinate3.h>
100 #include <Inventor/nodes/SoIndexedTriangleStripSet.h>
101 #include <Inventor/nodes/SoMaterial.h>
102 #include <Inventor/nodes/SoMaterialBinding.h>
103 #include <Inventor/nodes/SoMatrixTransform.h>
104 #include <Inventor/nodes/SoNormal.h>
105 #include <Inventor/nodes/SoNormalBinding.h>
106 #include <Inventor/nodes/SoShapeHints.h>
107 #include <Inventor/nodes/SoSeparator.h>
108 #include <Inventor/nodes/SoTexture2.h>
109 #include <Inventor/nodes/SoTextureCoordinate2.h>
110 #include <Inventor/nodes/SoTextureCoordinateBinding.h>
111 #include <Inventor/nodes/SoTexture2Transform.h>
112 #include <Inventor/nodes/SoTriangleStripSet.h>
113 #include <Inventor/errors/SoDebugError.h>
114 #include <Inventor/SoInput.h>
115 #include <Inventor/C/tidbits.h>
116 #include <cstring>
117
118
119
120 #define DISABLE_BACKFACE_CULLING
121
122 #define MATNAME_LENGTH 17 // 16 + \0
123 #define OBJNAME_LENGTH 11 // 10 + \0
124
125
126 // File Header Chunks
127 #define M3DMAGIC 0x4D4D
128 #define M3D_VERSION 0x0002
129 #define MLIBMAGIC 0x3DAA
130 #define CMAGIC 0xC23D
131
132 // Major Section Chunks
133 #define MDATA 0x3D3D
134 #define KFDATA 0xB000
135
136 // Viewport Control Chunks
137 #define VIEWPORT_LAYOUT 0x7001
138 #define VIEWPORT_DATA 0x7011
139 #define VIEWPORT_DATA_3 0x7012
140 #define VIEWPORT_SIZE 0x7020
141
142
143 // MDATA Section Chunks
144 // Common Chunks
145 #define COLOR_F 0x0010
146 #define COLOR_24 0x0011
147 #define LIN_COLOR_24 0x0012
148 #define LIN_COLOR_F 0x0013
149 #define INT_PERCENTAGE 0x0030
150 #define FLOAT_PERCENTAGE 0x0031
151
152 // Section Settings Chunks
153 #define MESH_VERSION 0x3D3E
154 #define MASTER_SCALE 0x0100
155 #define LO_SHADOW_BIAS 0x1400
156 #define HI_SHADOW_BIAS 0x1410
157 #define SHADOW_MAP_SIZE 0x1420
158 #define SHADOW_SAMPLES 0x1430
159 #define SHADOW_RANGE 0x1440
160 #define SHADOW_FILTER 0x1450
161 #define RAY_BIAS 0x1460
162 #define O_CONSTS 0x1500
163 #define AMBIENT_LIGHT 0x2100
164
165 // Background Settings Chunks
166 #define BIT_MAP 0x1100
167 #define SOLID_BGND 0x1200
168 #define V_GRADIENT 0x1300
169 #define USE_BIT_MAP 0x1101
170 #define USE_SOLID_BGND 0x1201
171 #define USE_V_GRADIENT 0x1301
172
173 // Atmosphere Settings Chunks
174 #define FOG 0x2200
175 #define FOG_BGND 0x2210
176 #define LAYER_FOG 0x2302
177 #define DISTANCE_CUE 0x2300
178 #define DCUE_BGND 0x2310
179 #define USE_FOG 0x2201
180 #define USE_LAYER_FOG 0x2303
181 #define USE_DISTANCE_CUE 0x2301
182
183 // Viewport Chunks
184 #define DEFAULT_VIEW 0x3000
185 #define VIEW_TOP 0x3010
186 #define VIEW_BOTTOM 0x3020
187 #define VIEW_LEFT 0x3030
188 #define VIEW_RIGHT 0x3040
189 #define VIEW_FRONT 0x3050
190 #define VIEW_BACK 0x3060
191 #define VIEW_USER 0x3070
192 #define VIEW_CAMERA 0x3080
193
194 // Materials Chunks
195 #define MAT_ENTRY 0xAFFF
196 #define MAT_NAME 0xA000
197 #define MAT_AMBIENT 0xA010
198 #define MAT_DIFFUSE 0xA020
199 #define MAT_SPECULAR 0xA030
200 #define MAT_SHININESS 0xA040
201 #define MAT_SHIN2PCT 0xA041
202 #define MAT_TRANSPARENCY 0xA050
203 #define MAT_XPFALL 0xA052
204 #define MAT_USE_XPFALL 0xA240
205 #define MAT_REFBLUR 0xA053
206 #define MAT_SHADING 0xA100
207 #define MAT_USE_REFBLUR 0xA250
208 #define MAT_SELF_ILLUM 0xA080
209 #define MAT_TWO_SIDE 0xA081
210 #define MAT_DECAL 0xA082
211 #define MAT_ADDITIVE 0xA083
212 #define MAT_WIRE 0xA085
213 #define MAT_FACEMAP 0xA088
214 #define MAT_PHONGSOFT 0xA08C
215 #define MAT_WIREABS 0xA08E
216 #define MAT_WIRESIZE 0xA087
217 #define MAT_TEXMAP 0xA200
218 #define MAT_SXP_TEXT_DATA 0xA320
219 #define MAT_TEXMASK 0xA3EH
220 #define MAT_SXP_TEXTMASK_DATA 0xA32A
221 #define MAT_TEX2MAP 0xA33A
222 #define MAT_SXP_TEXT2_DATA 0xA321
223 #define MAT_TEX2MASK 0xA340H
224 #define MAT_SXP_TEXT2MASK_DATA 0xA32C
225 #define MAT_OPACMAP 0xA210
226 #define MAT_SXP_OPAC_DATA 0xA322
227 #define MAT_OPACMASK 0xA342
228 #define MAT_SXP_OPACMASK_DATA 0xA32E
229 #define MAT_BUMPMAP 0xA230
230 #define MAT_SXP_BUMP_DATA 0xA324
231 #define MAT_BUMPMASK 0xA344
232 #define MAT_SXP_BUMPMASK_DATA 0xA330
233 #define MAT_SPECMAP 0xA204
234 #define MAT_SXP_SPEC_DATA 0xA325
235 #define MAT_SPECMASK 0xA348
236 #define MAT_SXP_SPECMASK_DATA 0xA332
237 #define MAT_SHINMAP 0xA33C
238 #define MAT_SXP_SHIN_DATA 0xA326
239 #define MAT_SHINMASK 0xA346
240 #define MAT_SXP_SHINMASK_DATA 0xA334
241 #define MAT_SELFIMAP 0xA33D
242 #define MAT_SXP_SELFI_DATA 0xA328
243 #define MAT_SELFIMASK 0xA34A
244 #define MAT_SXP_SELFIMASK_DATA 0xA336
245 #define MAT_REFLMAP 0xA220
246 #define MAT_REFLMASK 0xA34C
247 #define MAT_SXP_REFLMASK_DATA 0xA338
248 #define MAT_ACUBIC 0xA310
249 #define MAT_MAPNAME 0xA300
250 #define MAT_MAP_TILING 0xA351
251 #define MAT_MAT_TEXBLUR 0xA353
252 #define MAT_MAP_USCALE 0xA354
253 #define MAT_MAP_VSCALE 0xA356
254 #define MAT_MAP_UOFFSET 0xA358
255 #define MAT_MAP_VOFFSET 0xA35A
256 #define MAT_MAP_ANG 0xA35C
257 #define MAT_MAP_COL1 0xA360
258 #define MAT_MAP_COL2 0xA362
259 #define MAT_MAP_RCOL 0xA364
260 #define MAT_MAP_GCOL 0xA366
261 #define MAT_MAP_BCOL 0xA368
262
263 // Object Chunks
264 #define NAMED_OBJECT 0x4000
265 #define N_TRI_OBJECT 0x4100
266 #define POINT_ARRAY 0x4110
267 #define POINT_FLAG_ARRAY 0x4111
268 #define FACE_ARRAY 0x4120
269 #define MSH_MAT_GROUP 0x4130
270 #define SMOOTH_GROUP 0x4150
271 #define MSH_BOXMAP 0x4190
272 #define TEX_VERTS 0x4140
273 #define MESH_MATRIX 0x4160
274 #define MESH_COLOR 0x4165
275 #define MESH_TEXTURE_INFO 0x4170
276 #define PROC_NAME 0x4181
277 #define PROC_DATA 0x4182
278 #define N_DIRECT_LIGHT 0x4600
279 #define DL_OFF 0x4620
280 #define DL_OUTER_RANGE 0x465A
281 #define DL_INNER_RANGE 0x4659
282 #define DL_MULTIPLIER 0x465B
283 #define DL_EXCLUDE 0x4654
284 #define DL_ATTENUATE 0x4625
285 #define DL_SPOTLIGHT 0x4610
286 #define DL_SPOT_ROLL 0x4656
287 #define DL_SHADOWED 0x4630
288 #define DL_LOCAL_SHADOW2 0x4641
289 #define DL_SEE_CONE 0x4650
290 #define DL_SPOT_RECTANGULAR 0x4651
291 #define DL_SPOT_ASPECT 0x4657
292 #define DL_SPOT_PROJECTOR 0x4653
293 #define DL_SPOT_OVERSHOOT 0x4652
294 #define DL_RAY_BIAS 0x4658
295 #define DL_RAYSHAD 0x4627
296 #define N_CAMERA 0x4700
297 #define CAM_SEE_CONE 0x4710
298 #define CAM_RANGES 0x4720
299 #define OBJ_HIDDEN 0x4010
300 #define OBJ_VIS_LOFTER 0x4011
301 #define OBJ_DOESNT_CAST 0x4012
302 #define OBJ_DONT_RCVSHADOW 0x4017
303 #define OBJ_MATTE 0x4013
304 #define OBJ_FAST 0x4014
305 #define OBJ_PROCEDURAL 0x4015
306 #define OBJ_FROZEN 0x4016
307
308
309
310
311 struct tagFace;
312 struct tagFaceGroup;
313 struct tagMaterial;
314 struct tagContext;
315
316
317 typedef struct {
318 SbVec3f point;
319 SbVec2f texturePoint;
320 SbList<tagFace*> faceList;
321
322 SbVec3f getNormal(tagContext *con, uint16_t myIndex) const;
323 } Vertex;
324
325 typedef struct tagFace {
326 uint16_t v1,v2,v3;
327 uint16_t flags;
328 tagFaceGroup *faceGroup;
329 uint32_t e12,e23,e31;
330 SbBool isDegenerated;
331
332 SbVec3f getNormal(tagContext *con) const;
333 float getAngle(tagContext *con, uint16_t vertexIndex) const;
334 SbVec3f getWeightedNormal(tagContext *con, uint16_t vertexIndex) const;
335 void init(tagContext *con, uint16_t a, uint16_t b, uint16_t c, uint16_t f);
336 } Face;
337
338 typedef struct tagFaceGroup {
339 tagMaterial *mat;
340
341 SbList<Face*> faceList;
342 uint16_t numDegFaces;
343
344 SbBool hasTexture2(tagContext *con);
345 SoTexture2* getSoTexture2(tagContext *con);
346 SbBool hasTexture2Transform(tagContext *con);
347 SoTexture2Transform* getSoTexture2Transform(tagContext *con);
348 SoMaterial* getSoMaterial(tagContext *con);
349 SoNormal* createSoNormal(tagContext *con);
350
351 SoCoordinate3* createSoCoordinate3_n(tagContext *con);
352 SoTextureCoordinate2* createSoTextureCoordinate2_n(tagContext *con);
353 SoTriangleStripSet* createSoTriStripSet_n(tagContext *con);
354
355 SoIndexedTriangleStripSet* createSoIndexedTriStripSet_i(tagContext *con);
356 } FaceGroup;
357
358 // FIXME mortene: don't use "namespace"
359 namespace DefaultFaceGroup {
360 static tagMaterial* getMaterial(tagContext *con);
361 static SbBool isEmpty(tagContext *con);
362
363 static SoMaterial* getSoMaterial(tagContext *con);
364 static SoNormal* createSoNormal(tagContext *con);
365
366 static SoCoordinate3* createSoCoordinate3_n(tagContext *con);
367 static SoTriangleStripSet* createSoTriStripSet_n(tagContext *con);
368
369 static SoIndexedTriangleStripSet* createSoIndexedTriStripSet_i(tagContext *con);
370 }
371
372 typedef struct {
373 SbList<Face*> faceList;
374 } Edge;
375
376 typedef struct tagMaterial {
377 SbString name;
378 SbColor ambient;
379 SbColor diffuse;
380 SbColor specular;
381 float shininess;
382 float transparency;
383 SbString textureName;
384 float uscale;
385 float vscale;
386 float uoffset;
387 float voffset;
388 SbBool twoSided;
389
390 SoMaterial *matCache;
391 SoTexture2 *texture2Cache;
392 SoTexture2Transform *texture2TransformCache;
393
394 void updateSoMaterial(int index, SoMaterial *m);
395 SoMaterial* getSoMaterial(tagContext *con);
396 SbBool hasTexture2(tagContext *con);
397 SoTexture2* getSoTexture2(tagContext *con);
398 SbBool hasTexture2Transform(tagContext *con);
399 SoTexture2Transform* getSoTexture2Transform(tagContext *con);
400
tagMaterialtagMaterial401 tagMaterial() : matCache(NULL), texture2Cache(NULL),
402 texture2TransformCache(NULL) {}
~tagMaterialtagMaterial403 ~tagMaterial() {
404 if (matCache) matCache->unref();
405 if (texture2Cache) texture2Cache->unref();
406 if (texture2TransformCache) texture2TransformCache->unref();
407 }
408 } Material;
409
410
411
412 typedef struct tagContext {
413 // flags "What to load"
414 int appendNormals;
415 SbBool loadMaterials;
416 SbBool loadTextures;
417 SbBool loadObjNames;
418 SbBool useIndexedTriSet;
419 SbBool centerModel;
420
421 // basic loading stuff
422 SoStream &s;
423 size_t stopPos;
424 SoSeparator *root;
425 SoSeparator *cObj;
426 SbBool minMaxValid;
427 float minX,maxX;
428 float minY,maxY;
429 float minZ,maxZ;
430 char objectName[OBJNAME_LENGTH];
431 int totalVertices;
432 int totalFaces;
433
434 // material stuff
435 SbList<FaceGroup*> faceGroupList;
436 SbList<Material*> matList;
437 Material defaultMat;
438 Material *cMat;
439 SbColor cColor;
440 float cColorFloat;
441 SbBool textureCoordsFound;
442
443 // geometry stuff
444 Vertex *vertexList;
445 uint16_t numVertices;
446 Face *faceList;
447 uint16_t numFaces;
448 uint16_t numDefaultDegFaces;
449 Edge *edgeList;
450 uint32_t numEdges;
451
452 // scene graph generator stuff
453 SoTexture2 *genCurrentTexture;
454 SoMaterial *genCurrentMaterial;
455 SoTexture2Transform *genCurrentTexTransform;
456 int genTwoSided;
457 // multiple-time used nodes
458 SoTexture2 *genEmptyTexture;
459 SoTexture2Transform *genEmptyTexTransform;
460 SoShapeHints *genOneSidedHints;
461 SoShapeHints *genTwoSidedHints;
462
463
464 SoCoordinate3* createSoCoordinate3_i(tagContext *con) const;
465 SoTextureCoordinate2* createSoTextureCoordinate2_i(tagContext *con) const;
466
467 SoTexture2* genGetEmptyTexture();
468 SoTexture2Transform* genGetEmptyTexTransform();
469 SoShapeHints* genGetOneSidedHints();
470 SoShapeHints* genGetTwoSidedHints();
471
tagContexttagContext472 tagContext(SoStream &stream) : s(stream), root(NULL), cObj(NULL),
473 totalVertices(0), totalFaces(0),
474 vertexList(NULL), faceList(NULL),
475 genEmptyTexture(NULL), genEmptyTexTransform(NULL),
476 genOneSidedHints(NULL), genTwoSidedHints(NULL) {}
~tagContexttagContext477 ~tagContext() {
478 for (int i=matList.getLength()-1; i>=1; i--)
479 delete matList[i];
480
481 if (genEmptyTexture) genEmptyTexture->unref();
482 if (genEmptyTexTransform) genEmptyTexTransform->unref();
483 if (genOneSidedHints) genOneSidedHints->unref();
484 if (genTwoSidedHints) genTwoSidedHints->unref();
485
486 assert(!root && !cObj && !vertexList && !faceList &&
487 "You forgot to free some memory.");
488 }
489 } Context;
490
491
492
493 #define CHUNK_DECL(_name_) static void _name_(Context *con)
494
495 CHUNK_DECL(SkipChunk);
496 CHUNK_DECL(LoadNamedObject);
497 CHUNK_DECL(LoadNTriObject);
498 CHUNK_DECL(LoadPointArray);
499 CHUNK_DECL(LoadFaceArray);
500 CHUNK_DECL(LoadMshMatGroup);
501 CHUNK_DECL(LoadTexVerts);
502 CHUNK_DECL(LoadMatEntry);
503 CHUNK_DECL(LoadMatName);
504 CHUNK_DECL(LoadMatAmbient);
505 CHUNK_DECL(LoadMatDiffuse);
506 CHUNK_DECL(LoadMatSpecular);
507 CHUNK_DECL(LoadShininess);
508 CHUNK_DECL(LoadTransparency);
509 CHUNK_DECL(LoadMatTwoSide);
510 CHUNK_DECL(LoadColor24);
511 CHUNK_DECL(LoadLinColor24);
512 CHUNK_DECL(LoadIntPercentage);
513 CHUNK_DECL(LoadFloatPercentage);
514 CHUNK_DECL(LoadM3DMagic);
515 CHUNK_DECL(LoadM3DVersion);
516 CHUNK_DECL(LoadMData);
517 CHUNK_DECL(LoadMeshVersion);
518 CHUNK_DECL(LoadTexMap);
519 CHUNK_DECL(LoadMapName);
520 CHUNK_DECL(LoadMapUScale);
521 CHUNK_DECL(LoadMapVScale);
522 CHUNK_DECL(LoadMapUOffset);
523 CHUNK_DECL(LoadMapVOffset);
524 static int coin_debug_3ds();
525
526 static SbBool
read3dsFile(SoStream * in,SoSeparator * & root,int appendNormals,float creaseAngle,SbBool loadMaterials,SbBool loadTextures,SbBool loadObjNames,SbBool indexedTriSet,SbBool centerModel,float modelSize)527 read3dsFile(SoStream *in, SoSeparator *&root,
528 int appendNormals, float creaseAngle,
529 SbBool loadMaterials, SbBool loadTextures,
530 SbBool loadObjNames, SbBool indexedTriSet,
531 SbBool centerModel, float modelSize)
532 {
533 // read the stream header
534 uint16_t header;
535 *in >> header;
536 if (header != M3DMAGIC) {
537 SoDebugError::post("read3dsFile",
538 "Bad 3ds stream: invalid header.");
539 return FALSE;
540 }
541
542 // prepare Context structure
543 Context con(*in);
544 con.stopPos = 0;
545 con.root = new SoSeparator;
546 con.root->ref();
547 con.minMaxValid = FALSE;
548
549 // customize loader
550 if (appendNormals >= 2) appendNormals = 1; // per-vertex normals are
551 // not currently supported
552 con.appendNormals = appendNormals;
553 con.loadMaterials = loadMaterials;
554 con.loadTextures = loadTextures;
555 con.loadObjNames = loadObjNames;
556 con.useIndexedTriSet = indexedTriSet;
557 con.centerModel = centerModel;
558
559 // initialize materials and prepare default one
560 con.matList.append(&con.defaultMat);
561 // FIXME: the values for the default material are guessed one (maybe completely wrong)
562 con.defaultMat.ambient = SbColor(0.6f, 0.6f, 0.6f);
563 con.defaultMat.diffuse = SbColor(0.8f, 0.8f, 0.8f);
564 con.defaultMat.specular = SbColor(0.f, 0.f, 0.f);
565 con.defaultMat.shininess = 0.f;
566 con.defaultMat.transparency = 0.f;
567 con.defaultMat.twoSided = TRUE; // FIXME: is default material double sided?
568 con.defaultMat.matCache = new SoMaterial;
569 con.defaultMat.matCache->ref();
570 con.defaultMat.updateSoMaterial(0, con.defaultMat.matCache);
571 con.cMat = 0;
572
573 // build base scene graph
574
575 #ifdef DISABLE_BACKFACE_CULLING // put default shape hints into the scene;
576 // Backface culling is set to off and two sided lighting is enabled.
577 SoShapeHints *sh = new SoShapeHints;
578 sh->vertexOrdering = SoShapeHints::COUNTERCLOCKWISE;
579 sh->shapeType = SoShapeHints::UNKNOWN_SHAPE_TYPE;
580
581 // configure creaseAngle on shape hints when normals are computed by shapes
582 if (con.appendNormals == 0) {
583 sh->creaseAngle = creaseAngle;
584 }
585 con.root->addChild(sh);
586 #endif
587
588 // center model and scale it
589 SoMatrixTransform *matrix = NULL;
590 if (con.centerModel || modelSize != 0.f) {
591 matrix = new SoMatrixTransform;
592 con.root->addChild(matrix);
593 }
594
595 if (con.loadMaterials) {
596 // material binding
597 SoMaterialBinding *mb = new SoMaterialBinding;
598 mb->value.setValue(SoMaterialBinding::OVERALL);
599 con.root->addChild(mb);
600 }
601
602 if (con.appendNormals) {
603 // normal binding
604 SoNormalBinding *nb = new SoNormalBinding;
605 if (con.appendNormals == 1)
606 nb->value.setValue(SoNormalBinding::PER_PART); // normal for each strip of the set
607 else
608 nb->value.setValue(SoNormalBinding::PER_VERTEX);
609 con.root->addChild(nb);
610 }
611
612 if (con.loadTextures) {
613 SoTextureCoordinateBinding *tb = new SoTextureCoordinateBinding;
614 if (con.useIndexedTriSet)
615 tb->value.setValue(SoTextureCoordinateBinding::PER_VERTEX_INDEXED);
616 else
617 tb->value.setValue(SoTextureCoordinateBinding::PER_VERTEX);
618 con.root->addChild(tb);
619 }
620
621
622 // read the stream
623 LoadM3DMagic(&con);
624
625 // handle errors
626 if (con.s.isBad()) {
627 con.root->unref();
628 con.root = NULL;
629
630 SoDebugError::post("read3dsFile",
631 "3ds loading failed.");
632 return FALSE;
633 }
634
635 if (con.centerModel || modelSize != 0.f) {
636 SbMatrix m;
637
638 // center model
639 if (con.centerModel)
640 m.setTranslate(SbVec3f(-(con.maxX+con.minX)/2.f, -(con.maxY+con.minY)/2.f,
641 -(con.maxZ+con.minZ)/2.f));
642 else
643 m.makeIdentity();
644
645 // set model size
646 if (modelSize != 0.f) {
647 SbMatrix m2;
648 float max = SbMax(SbMax(con.maxX-con.minX, con.maxY-con.minY), con.maxZ-con.minZ);
649 m2.setScale(modelSize/max);
650 m.multRight(m2);
651 }
652
653 matrix->matrix.setValue(m);
654 }
655
656 // return root
657 con.root->unrefNoDelete();
658 root = con.root;
659 con.root = NULL;
660
661 // debug info
662 if (coin_debug_3ds() >= 2)
663 SoDebugError::postInfo("read3dsFile",
664 "File loading ok. Loaded %i vertices and %i faces.",
665 con.totalVertices, con.totalFaces);
666
667 return TRUE;
668 }
669
670
671
672
673 #define CHUNK(_name_) CHUNK_DECL(_name_)
674
675 #define HEADER \
676 if (con->s.isBad()) \
677 return; \
678 \
679 uint32_t size; \
680 con->s >> size;
681
682 #define FULLHEADER \
683 HEADER \
684 uint32_t cpos = static_cast<uint32_t>(con->s.getPos()); \
685 uint32_t stopPos = cpos + size - 6;
686
687
688
689
690 #define READ_SUBCHUNKS(_subChunkSwitch_) \
691 while (con->s.getPos() < stopPos) { \
692 uint16_t chid; \
693 con->s >> chid; \
694 if (con->s.isBad()) \
695 break; \
696 \
697 switch (chid) { \
698 _subChunkSwitch_; \
699 default: \
700 SkipChunk(con); \
701 }; \
702 }
703
704
705
706
707
CHUNK(SkipChunk)708 CHUNK(SkipChunk)
709 {
710 FULLHEADER;
711
712 // move on the position of the next chunk
713 con->s.setPos(stopPos);
714 }
715
716
717
CHUNK(LoadM3DMagic)718 CHUNK(LoadM3DMagic)
719 {
720 FULLHEADER;
721 con->stopPos = con->s.getPos() + size - 6;
722
723 if (coin_debug_3ds() >= 2)
724 SoDebugError::postInfo("LoadM3DMagic",
725 "Loading 3ds stream (stream size: %i).", size);
726
727 READ_SUBCHUNKS(
728 case M3D_VERSION: LoadM3DVersion(con); break;
729 case MDATA: LoadMData(con); break;
730 case KFDATA: SkipChunk(con); break;
731 )
732 }
733
734
735
CHUNK(LoadM3DVersion)736 CHUNK(LoadM3DVersion)
737 {
738 HEADER;
739
740 int32_t version;
741 con->s >> version;
742
743 if (version != 3 && coin_debug_3ds() >= 1)
744 SoDebugError::postWarning("LoadM3DVersion",
745 "Non-standard 3ds format version: %i.", version);
746 }
747
748
749
CHUNK(LoadMData)750 CHUNK(LoadMData)
751 {
752 FULLHEADER;
753
754 READ_SUBCHUNKS(
755 case MESH_VERSION: LoadMeshVersion(con); break;
756 case MAT_ENTRY: LoadMatEntry(con); break;
757 case NAMED_OBJECT: LoadNamedObject(con); break;
758 )
759 }
760
761
762
CHUNK(LoadMeshVersion)763 CHUNK(LoadMeshVersion)
764 {
765 HEADER;
766
767 int32_t version;
768 con->s >> version;
769
770 if (coin_debug_3ds() >= 3)
771 SoDebugError::postInfo("LoadMeshVersion",
772 "The 3ds file version: %i.", version);
773 }
774
775
776
CHUNK(LoadNamedObject)777 CHUNK(LoadNamedObject)
778 {
779 FULLHEADER;
780
781 assert(!con->cObj && "Forgot to free the current object.");
782
783 // read object name
784 con->s.readZString(con->objectName, OBJNAME_LENGTH);
785
786 if (coin_debug_3ds() >= 3)
787 SoDebugError::postInfo("LoadNamesObject",
788 "Name: %s.", con->objectName);
789
790 READ_SUBCHUNKS(
791 case N_TRI_OBJECT: LoadNTriObject(con); break;
792 )
793
794 if (con->cObj) {
795 // set object name
796 if (con->loadObjNames && strlen(con->objectName) > 0)
797 con->cObj->setName(con->objectName);
798
799 // add cObj to the main scene graph
800 if (con->cObj->getNumChildren() > 0)
801 con->root->addChild(con->cObj);
802 con->cObj->unref();
803 con->cObj = NULL;
804 }
805 }
806
807
808
CHUNK(LoadNTriObject)809 CHUNK(LoadNTriObject)
810 {
811 FULLHEADER;
812
813 assert(con->faceGroupList.getLength() == 0);
814 con->numVertices = 0;
815 con->numFaces = 0;
816 con->numDefaultDegFaces = 0;
817 con->textureCoordsFound = FALSE;
818
819 if (coin_debug_3ds() >= 3)
820 SoDebugError::postInfo("LoadNTriObject",
821 "About to load");
822
823 READ_SUBCHUNKS(
824 case POINT_ARRAY: LoadPointArray(con); break;
825 case POINT_FLAG_ARRAY: SkipChunk(con); break;
826 case FACE_ARRAY: LoadFaceArray(con); break;
827 case MSH_MAT_GROUP: LoadMshMatGroup(con); break;
828 case TEX_VERTS: LoadTexVerts(con); break;
829 case MESH_MATRIX: SkipChunk(con); break;
830 case MESH_COLOR: SkipChunk(con); break;
831 case MESH_TEXTURE_INFO: SkipChunk(con); break;
832 case PROC_NAME: SkipChunk(con); break;
833 case PROC_DATA: SkipChunk(con); break;
834 )
835
836 // debug info
837 if (coin_debug_3ds() >= 3)
838 SoDebugError::postInfo("LoadNTriObject",
839 "Object %s parsed - vertices: %i, faces %i.", &con->objectName, con->numVertices, con->numFaces);
840 con->totalVertices += con->numVertices;
841 con->totalFaces += con->numFaces;
842
843 // create object separator
844 con->cObj = new SoSeparator;
845 con->cObj->ref();
846
847 con->genCurrentTexture = NULL;
848 con->genCurrentTexTransform = NULL;
849 con->genCurrentMaterial = NULL;
850 con->genTwoSided = -1;
851
852 // create coordinates (in indexed mode)
853 if (con->useIndexedTriSet) {
854 // coordinates
855 con->cObj->addChild(con->createSoCoordinate3_i(con));
856 // texture coordinates
857 if (con->textureCoordsFound && con->loadTextures)
858 con->cObj->addChild(con->createSoTextureCoordinate2_i(con));
859 }
860
861 // create "default material" scene
862 if (!DefaultFaceGroup::isEmpty(con)) {
863
864 // default material has not a texture => switch it off
865 #if 0 // non-optimized version
866 if (con->loadTextures)
867 con->cObj->addChild(new SoTexture2);
868 #else
869 if (con->loadTextures) {
870 SoTexture2 *t = con->genGetEmptyTexture();
871 if (t != con->genCurrentTexture) {
872 con->genCurrentTexture = t;
873 con->cObj->addChild(t);
874 }
875 SoTexture2Transform *tt = con->genGetEmptyTexTransform();
876 if (tt != con->genCurrentTexTransform) {
877 con->genCurrentTexTransform = tt;
878 con->cObj->addChild(tt);
879 }
880 }
881 #endif
882
883 // materials
884 #if 0 // non-optimized version
885 if (con->loadMaterials)
886 con->cObj->addChild(DefaultFaceGroup::getSoMaterial(con));
887 #else
888 if (con->loadMaterials) {
889 SoMaterial *m = DefaultFaceGroup::getSoMaterial(con);
890 if (m != con->genCurrentMaterial) {
891 con->genCurrentMaterial = m;
892 con->cObj->addChild(con->genCurrentMaterial);
893 }
894 }
895 #endif
896
897 // normals
898 if (con->appendNormals)
899 con->cObj->addChild(DefaultFaceGroup::createSoNormal(con));
900
901 #ifndef DISABLE_BACKFACE_CULLING
902 // single x double faces
903 SbBool matTwoSided = DefaultFaceGroup::getMaterial(con)->twoSided;
904 if (con->genTwoSided == -1 || (matTwoSided && (con->genTwoSided == 0)) ||
905 (!matTwoSided && (con->genTwoSided == 1))) {
906 con->genTwoSided = (DefaultFaceGroup::getMaterial(con)->twoSided ? 1 : 0);
907 con->cObj->addChild((con->genTwoSided == 1) ?
908 con->genGetTwoSidedHints() : con->genGetOneSidedHints());
909 }
910 #endif
911
912 // load default material geometry
913 if (con->useIndexedTriSet) {
914 // indexed triStripSet
915 con->cObj->addChild(DefaultFaceGroup::createSoIndexedTriStripSet_i(con));
916 } else {
917 // coordinates
918 con->cObj->addChild(DefaultFaceGroup::createSoCoordinate3_n(con));
919 // triStripSet
920 con->cObj->addChild(DefaultFaceGroup::createSoTriStripSet_n(con));
921 }
922 }
923
924 // create non-default materials scene
925 for (int i=0; i<con->faceGroupList.getLength(); i++) {
926 FaceGroup *fg = con->faceGroupList[i];
927
928 // materials
929 #if 0 // non-optimized version
930 if (con->loadMaterials)
931 con->cObj->addChild(fg->getSoMaterial(con));
932 #else
933 if (con->loadMaterials) {
934 SoMaterial *m = fg->getSoMaterial(con);
935 if (m != con->genCurrentMaterial) {
936 con->genCurrentMaterial = m;
937 con->cObj->addChild(m);
938 }
939 }
940 #endif
941
942 // normals
943 if (con->appendNormals)
944 con->cObj->addChild(fg->createSoNormal(con));
945
946 // textures - optimized code
947 if (con->loadTextures) {
948 if (fg->hasTexture2(con)) {
949 SoTexture2 *t = fg->getSoTexture2(con);
950 if (t != con->genCurrentTexture) {
951 con->genCurrentTexture = t;
952 con->cObj->addChild(t);
953 }
954 } else {
955 SoTexture2 *t = con->genGetEmptyTexture();
956 if (t != con->genCurrentTexture) {
957 con->genCurrentTexture = t;
958 con->cObj->addChild(t);
959 }
960 }
961 // texture transform - optimized code
962 if (fg->hasTexture2Transform(con)) {
963 SoTexture2Transform *tt = fg->getSoTexture2Transform(con);
964 if (tt != con->genCurrentTexTransform) {
965 con->genCurrentTexTransform = tt;
966 con->cObj->addChild(tt);
967 }
968 } else {
969 SoTexture2Transform *tt = con->genGetEmptyTexTransform();
970 if (tt != con->genCurrentTexTransform) {
971 con->genCurrentTexTransform = tt;
972 con->cObj->addChild(tt);
973 }
974 }
975 }
976
977 #ifndef DISABLE_BACKFACE_CULLING
978 // single x double faces
979 if (con->genTwoSided == -1 || (fg->mat->twoSided && (con->genTwoSided == 0)) ||
980 (!fg->mat->twoSided && (con->genTwoSided == 1))) {
981 con->genTwoSided = (fg->mat->twoSided ? 1 : 0);
982 con->cObj->addChild((con->genTwoSided == 1) ?
983 con->genGetTwoSidedHints() : con->genGetOneSidedHints());
984 }
985 #endif
986
987 if (con->useIndexedTriSet) {
988 // indexed triStripSet
989 con->cObj->addChild(fg->createSoIndexedTriStripSet_i(con));
990 } else {
991 // coordinates
992 con->cObj->addChild(fg->createSoCoordinate3_n(con));
993 // textures
994 if (con->loadTextures && fg->hasTexture2(con))
995 con->cObj->addChild(fg->createSoTextureCoordinate2_n(con));
996 // triStripSet
997 con->cObj->addChild(fg->createSoTriStripSet_n(con));
998 }
999 }
1000
1001 // clean up memory
1002 delete[] con->vertexList;
1003 con->vertexList = NULL;
1004 delete[] con->faceList;
1005 con->faceList = NULL;
1006 for (int j=con->faceGroupList.getLength()-1; j>=0; j--) {
1007 delete con->faceGroupList[j];
1008 con->faceGroupList.removeFast(j);
1009 }
1010 }
1011
1012
1013
CHUNK(LoadPointArray)1014 CHUNK(LoadPointArray)
1015 {
1016 HEADER;
1017
1018 if (coin_debug_3ds() >= 3)
1019 SoDebugError::postInfo("LoadPointArray",
1020 "Begin");
1021
1022
1023 // number of vertices
1024 uint16_t num;
1025 con->s >> num;
1026
1027 // alloc memory for Vertices
1028 assert(con->vertexList == NULL && "Forgot to free memory.");
1029 con->vertexList = new Vertex[num];
1030 con->numVertices = num;
1031
1032 // read points
1033 float x,y,z;
1034 for (int i=0; i<num; i++) {
1035 con->s >> x;
1036 con->s >> y;
1037 con->s >> z;
1038 con->vertexList[i].point = SbVec3f(x,z,-y); // 3ds has different
1039 //coordinate system. Z is up, and Y goes into the scene.
1040 }
1041 }
1042
1043
1044
CHUNK(LoadFaceArray)1045 CHUNK(LoadFaceArray)
1046 {
1047 FULLHEADER;
1048
1049 if (coin_debug_3ds() >= 3)
1050 SoDebugError::postInfo("LoadFaceArray",
1051 "Begin");
1052
1053 // number of faces
1054 uint16_t num;
1055 con->s >> num;
1056
1057 // alloc memory for Faces
1058 assert(con->faceList == NULL && "Forgot to free memory.");
1059 con->faceList = new Face[num];
1060 con->numFaces = num;
1061
1062 // alloc memory for edges
1063 if (con->appendNormals == 2) {
1064 con->numEdges = 0;
1065 con->edgeList = new Edge[num*3];
1066 }
1067
1068 // make sure vertices are present yet
1069 if (num > 0) {
1070 if (con->vertexList == NULL) {
1071 assert(FALSE && "Vertex list not present.");
1072 con->s.setBadBit();
1073 return;
1074 }
1075 }
1076
1077 // read Faces
1078 uint16_t a,b,c;
1079 uint16_t flags;
1080 for (int i=0; i<num; i++) {
1081 con->s >> a;
1082 con->s >> b;
1083 con->s >> c;
1084 con->s >> flags; // STUB: decode flags (edge visibility and texture
1085 // wrapping, but first get idea what's the flags meaning)
1086 if (flags != 7 && coin_debug_3ds() >= 2)
1087 SoDebugError::postWarning("LoadFaceArray",
1088 "Non-standard face flags: %x, investigate it.\n", flags);
1089 con->faceList[i].init(con, a,b,c,flags); // vertex ordering is counter-clockwise.
1090
1091 if (!con->minMaxValid) {
1092 con->minMaxValid = TRUE;
1093 con->minX = con->maxX = con->vertexList[a].point[0];
1094 con->minY = con->maxY = con->vertexList[a].point[1];
1095 con->minZ = con->maxZ = con->vertexList[a].point[2];
1096 }
1097 #define PROCESS_VERTEX(_abc_, _xyz_, _index_) \
1098 if (con->min##_xyz_ > con->vertexList[_abc_].point[_index_]) \
1099 con->min##_xyz_ = con->vertexList[_abc_].point[_index_]; \
1100 else \
1101 if (con->max##_xyz_ < con->vertexList[_abc_].point[_index_]) \
1102 con->max##_xyz_ = con->vertexList[_abc_].point[_index_]
1103
1104 PROCESS_VERTEX(a, X, 0);
1105 PROCESS_VERTEX(a, Y, 1);
1106 PROCESS_VERTEX(a, Z, 2);
1107 PROCESS_VERTEX(b, X, 0);
1108 PROCESS_VERTEX(b, Y, 1);
1109 PROCESS_VERTEX(b, Z, 2);
1110 PROCESS_VERTEX(c, X, 0);
1111 PROCESS_VERTEX(c, Y, 1);
1112 PROCESS_VERTEX(c, Z, 2);
1113 #undef PROCESS_VERTEX
1114 }
1115
1116 // report degenerated faces
1117 if (con->numDefaultDegFaces > 0 && coin_debug_3ds() >= 1)
1118 SoDebugError::postWarning("LoadFaceArray",
1119 "There are %i degenerated faces in the object named \"%s\" - removing them.",
1120 con->numDefaultDegFaces, &con->objectName);
1121
1122 READ_SUBCHUNKS(
1123 case MSH_MAT_GROUP: LoadMshMatGroup(con); break;
1124 case SMOOTH_GROUP: SkipChunk(con); break;
1125 case MSH_BOXMAP: SkipChunk(con); break;
1126 )
1127 }
1128
1129
1130
CHUNK(LoadMshMatGroup)1131 CHUNK(LoadMshMatGroup)
1132 {
1133 FULLHEADER;
1134
1135 if (coin_debug_3ds() >= 4)
1136 SoDebugError::postInfo("LoadMatGroup",
1137 "Begin");
1138
1139 if (!con->loadMaterials && !con->loadTextures) {
1140 // move on the position of the next chunk
1141 con->s.setPos(stopPos);
1142 return;
1143 }
1144
1145 // material name
1146 char materialName[MATNAME_LENGTH];
1147 con->s.readZString(materialName, MATNAME_LENGTH);
1148 int matIndex;
1149 for (matIndex=1; matIndex<con->matList.getLength(); matIndex++) {
1150 if (strcmp(con->matList[matIndex]->name.getString(), materialName) == 0)
1151 break;
1152 }
1153 if (matIndex == con->matList.getLength()) {
1154 assert(FALSE && "Wrong material name in the file.");
1155 con->s.setBadBit();
1156 return;
1157 }
1158
1159 // create FaceGroup
1160 FaceGroup *mm = new FaceGroup;
1161 mm->mat = con->matList[matIndex];
1162 con->faceGroupList.append(mm);
1163 mm->numDegFaces = 0;
1164
1165 // number of faces
1166 uint16_t num;
1167 con->s >> num;
1168
1169 // make sure faces are present yet
1170 if (num > 0) {
1171 if (con->faceList == NULL) {
1172 assert(FALSE && "Face list not present.");
1173 con->s.setBadBit();
1174 return;
1175 }
1176 }
1177
1178 // face indexes
1179 uint16_t faceMatIndex;
1180 for (int i=0; i<num; i++) {
1181 con->s >> faceMatIndex;
1182 if (faceMatIndex < con->numFaces) {
1183 assert(con->faceList[faceMatIndex].faceGroup == NULL &&
1184 "3ds file error: Two materials on one face.");
1185 con->faceList[faceMatIndex].faceGroup = mm;
1186 mm->faceList.append(&con->faceList[faceMatIndex]);
1187 if (con->faceList[faceMatIndex].isDegenerated) {
1188 mm->numDegFaces++;
1189 con->numDefaultDegFaces--;
1190 }
1191 } else {
1192 assert(FALSE && "Wrong face material index.");
1193 con->s.setBadBit();
1194 return;
1195 }
1196 }
1197 }
1198
1199
1200
CHUNK(LoadTexVerts)1201 CHUNK(LoadTexVerts)
1202 {
1203 HEADER;
1204
1205 if (coin_debug_3ds() >= 4)
1206 SoDebugError::postInfo("LoadTexVerts",
1207 "Begin");
1208
1209 con->textureCoordsFound = TRUE;
1210
1211 // number of faces
1212 uint16_t num;
1213 con->s >> num;
1214
1215 // make sure vertices are present yet
1216 if (num > 0) {
1217 if (con->vertexList == NULL) {
1218 assert(FALSE && "Vertex list not present.");
1219 con->s.setBadBit();
1220 return;
1221 }
1222 }
1223
1224 // texture coordinates
1225 float u;
1226 float v;
1227 for (int i=0; i<num; i++) {
1228 con->s >> u;
1229 con->s >> v;
1230 con->vertexList[i].texturePoint = SbVec2f(u,v);
1231 }
1232 }
1233
1234
1235
CHUNK(LoadMatEntry)1236 CHUNK(LoadMatEntry)
1237 {
1238 FULLHEADER;
1239
1240 if (coin_debug_3ds() >= 4)
1241 SoDebugError::postInfo("LoadMatEntry",
1242 "Begin");
1243
1244 if (!con->loadMaterials && !con->loadTextures) {
1245 // move on the position of the next chunk
1246 con->s.setPos(stopPos);
1247 return;
1248 }
1249
1250 assert(con->cMat == NULL);
1251 con->cMat = new Material;
1252 con->matList.append(con->cMat);
1253
1254 // default values
1255 con->cMat->name = "";
1256 con->cMat->ambient = SbColor(0.f, 0.f, 0.f);
1257 con->cMat->diffuse = SbColor(0.f, 0.f, 0.f);
1258 con->cMat->specular = SbColor(0.f, 0.f, 0.f);
1259 con->cMat->shininess = 0.f;
1260 con->cMat->transparency = 0.f;
1261 con->cMat->twoSided = FALSE;
1262
1263 READ_SUBCHUNKS(
1264 case MAT_NAME: LoadMatName(con); break;
1265 case MAT_AMBIENT: LoadMatAmbient(con); break;
1266 case MAT_DIFFUSE: LoadMatDiffuse(con); break;
1267 case MAT_SPECULAR: LoadMatSpecular(con); break;
1268 case MAT_SHININESS: LoadShininess(con); break;
1269 case MAT_TRANSPARENCY: LoadTransparency(con); break;
1270 case MAT_TWO_SIDE: LoadMatTwoSide(con); break;
1271 case MAT_TEXMAP: LoadTexMap(con); break;
1272 )
1273
1274 // create new SoMaterial
1275 con->cMat->matCache = new SoMaterial;
1276 con->cMat->matCache->ref();
1277 con->cMat->updateSoMaterial(0, con->cMat->matCache);
1278
1279 con->cMat = NULL;
1280 }
1281
1282
1283
CHUNK(LoadMatName)1284 CHUNK(LoadMatName)
1285 {
1286 HEADER;
1287
1288 if (coin_debug_3ds() >= 4)
1289 SoDebugError::postInfo("LoadMatName",
1290 "Begin");
1291
1292 char materialName[MATNAME_LENGTH];
1293 con->s.readZString(materialName, MATNAME_LENGTH);
1294
1295 con->cMat->name = materialName;
1296 }
1297
1298
1299
CHUNK(LoadMatAmbient)1300 CHUNK(LoadMatAmbient)
1301 {
1302 FULLHEADER;
1303
1304 if (coin_debug_3ds() >= 4)
1305 SoDebugError::postInfo("LoadMatAmbient",
1306 "Begin");
1307
1308 READ_SUBCHUNKS(
1309 case COLOR_24: LoadColor24(con); break;
1310 case LIN_COLOR_24: LoadLinColor24(con); break;
1311 )
1312 con->cMat->ambient = con->cColor;
1313 }
1314
1315
1316
CHUNK(LoadMatDiffuse)1317 CHUNK(LoadMatDiffuse)
1318 {
1319 FULLHEADER;
1320
1321 if (coin_debug_3ds() >= 4)
1322 SoDebugError::postInfo("LoadMatDiffuse",
1323 "Begin");
1324
1325 READ_SUBCHUNKS(
1326 case COLOR_24: LoadColor24(con); break;
1327 case LIN_COLOR_24: LoadLinColor24(con); break;
1328 )
1329 con->cMat->diffuse = con->cColor;
1330 }
1331
1332
1333
CHUNK(LoadMatSpecular)1334 CHUNK(LoadMatSpecular)
1335 {
1336 FULLHEADER;
1337
1338 if (coin_debug_3ds() >= 4)
1339 SoDebugError::postInfo("LoadMatSpecular",
1340 "Begin");
1341
1342 READ_SUBCHUNKS(
1343 case COLOR_24: LoadColor24(con); break;
1344 case LIN_COLOR_24: LoadLinColor24(con); break;
1345 )
1346 con->cMat->specular = con->cColor;
1347 }
1348
1349
1350
CHUNK(LoadShininess)1351 CHUNK(LoadShininess)
1352 {
1353 FULLHEADER;
1354
1355 if (coin_debug_3ds() >= 4)
1356 SoDebugError::postInfo("LoadMatShininesst",
1357 "Begin");
1358
1359 con->cColorFloat = 0.f;
1360
1361 READ_SUBCHUNKS(
1362 case INT_PERCENTAGE: LoadIntPercentage(con); break;
1363 case FLOAT_PERCENTAGE: LoadFloatPercentage(con); break;
1364 )
1365 con->cMat->shininess = con->cColorFloat;
1366 }
1367
1368
1369
CHUNK(LoadMatTwoSide)1370 CHUNK(LoadMatTwoSide)
1371 {
1372 HEADER;
1373
1374 if (coin_debug_3ds() >= 4)
1375 SoDebugError::postInfo("LoadMatTwoSide",
1376 "Begin");
1377
1378 con->cMat->twoSided = TRUE;
1379 }
1380
1381
1382
CHUNK(LoadTransparency)1383 CHUNK(LoadTransparency)
1384 {
1385 FULLHEADER;
1386
1387 if (coin_debug_3ds() >= 4)
1388 SoDebugError::postInfo("LoadTransparency",
1389 "Begin");
1390
1391 con->cColorFloat = 0.f;
1392
1393 READ_SUBCHUNKS(
1394 case INT_PERCENTAGE: LoadIntPercentage(con); break;
1395 case FLOAT_PERCENTAGE: LoadFloatPercentage(con); break;
1396 )
1397 con->cMat->transparency = con->cColorFloat;
1398 }
1399
1400
1401
CHUNK(LoadTexMap)1402 CHUNK(LoadTexMap)
1403 {
1404 FULLHEADER;
1405
1406 if (coin_debug_3ds() >= 4)
1407 SoDebugError::postInfo("LoadTexMap",
1408 "Begin");
1409
1410 if (!con->loadTextures) {
1411 // move on the position of the next chunk
1412 con->s.setPos(stopPos);
1413 return;
1414 }
1415
1416 con->cMat->uscale = con->cMat->vscale = 1.f;
1417 con->cMat->uoffset = con->cMat->voffset = 0.f;
1418
1419 READ_SUBCHUNKS(
1420 case INT_PERCENTAGE: LoadIntPercentage(con); break;
1421 case FLOAT_PERCENTAGE: LoadFloatPercentage(con); break;
1422 case MAT_MAPNAME: LoadMapName(con); break;
1423 case MAT_MAP_USCALE: LoadMapUScale(con); break;
1424 case MAT_MAP_VSCALE: LoadMapVScale(con); break;
1425 case MAT_MAP_UOFFSET: LoadMapUOffset(con); break;
1426 case MAT_MAP_VOFFSET: LoadMapVOffset(con); break;
1427 )
1428
1429 if (con->cMat->textureName.getLength() > 0) {
1430 SoTexture2 *t = new SoTexture2;
1431 t->ref();
1432 t->filename.setValue(con->cMat->textureName);
1433 t->model.setValue(SoTexture2::DECAL);
1434 con->cMat->texture2Cache = t;
1435 }
1436
1437 if (con->cMat->uscale != 1.f || con->cMat->vscale != 1.f ||
1438 con->cMat->uoffset != 0.f || con->cMat->voffset != 0.f) {
1439 SoTexture2Transform *tt = new SoTexture2Transform;
1440 tt->ref();
1441 tt->scaleFactor.setValue(SbVec2f(con->cMat->uscale, con->cMat->vscale));
1442 tt->translation.setValue(SbVec2f(con->cMat->uoffset, con->cMat->voffset));
1443 con->cMat->texture2TransformCache = tt;
1444 }
1445 }
1446
1447
1448
CHUNK(LoadMapName)1449 CHUNK(LoadMapName)
1450 {
1451 HEADER;
1452
1453 if (coin_debug_3ds() >= 4)
1454 SoDebugError::postInfo("LoadMapName",
1455 "Begin");
1456
1457 char textureName[13];
1458 con->s.readZString(textureName, 13);
1459
1460 con->cMat->textureName = textureName;
1461 }
1462
1463
1464
CHUNK(LoadMapUScale)1465 CHUNK(LoadMapUScale)
1466 {
1467 HEADER;
1468
1469 if (coin_debug_3ds() >= 4)
1470 SoDebugError::postInfo("LoadMatUScale",
1471 "Begin");
1472
1473 con->s >> con->cMat->uscale;
1474 }
1475
1476
1477
CHUNK(LoadMapVScale)1478 CHUNK(LoadMapVScale)
1479 {
1480 HEADER;
1481
1482 if (coin_debug_3ds() >= 4)
1483 SoDebugError::postInfo("LoadMapVScale",
1484 "Begin");
1485
1486 con->s >> con->cMat->vscale;
1487 }
1488
1489
1490
CHUNK(LoadMapUOffset)1491 CHUNK(LoadMapUOffset)
1492 {
1493 HEADER;
1494
1495 if (coin_debug_3ds() >= 4)
1496 SoDebugError::postInfo("LoadMapUOffset",
1497 "Begin");
1498
1499 con->s >> con->cMat->uoffset;
1500 }
1501
1502
1503
CHUNK(LoadMapVOffset)1504 CHUNK(LoadMapVOffset)
1505 {
1506 HEADER;
1507 if (coin_debug_3ds() >= 4)
1508 SoDebugError::postInfo("LoadMapVOffset",
1509 "Begin");
1510
1511 con->s >> con->cMat->voffset;
1512 }
1513
1514
1515
CHUNK(LoadColor24)1516 CHUNK(LoadColor24)
1517 {
1518 HEADER;
1519
1520 if (coin_debug_3ds() >= 4)
1521 SoDebugError::postInfo("LoadColor24",
1522 "Begin");
1523
1524 uint8_t r,g,b;
1525 con->s >> r;
1526 con->s >> g;
1527 con->s >> b;
1528
1529 con->cColor = SbColor(float(r)/255.f, float(g)/255.f, float(b)/255.f);
1530 }
1531
1532
1533
CHUNK(LoadLinColor24)1534 CHUNK(LoadLinColor24)
1535 {
1536 HEADER;
1537
1538 if (coin_debug_3ds() >= 4)
1539 SoDebugError::postInfo("LoadLinColor24",
1540 "Begin");
1541
1542 uint8_t r,g,b;
1543 con->s >> r;
1544 con->s >> g;
1545 con->s >> b;
1546
1547 con->cColor = SbColor(float(r)/255.f, float(g)/255.f, float(b)/255.f);
1548 }
1549
1550
1551
CHUNK(LoadIntPercentage)1552 CHUNK(LoadIntPercentage)
1553 {
1554 HEADER;
1555
1556 if (coin_debug_3ds() >= 4)
1557 SoDebugError::postInfo("LoadIntPerscentage",
1558 "Begin");
1559
1560 int16_t i;
1561 con->s >> i;
1562
1563 con->cColorFloat = float(i)/100.f;
1564 }
1565
1566
1567
CHUNK(LoadFloatPercentage)1568 CHUNK(LoadFloatPercentage)
1569 {
1570 HEADER;
1571
1572 if (coin_debug_3ds() >= 4)
1573 SoDebugError::postInfo("LoadFloatPersentage",
1574 "Begin");
1575
1576 con->s >> (con->cColorFloat);
1577 }
1578
1579
1580
1581
1582
getNormal(tagContext * con,uint16_t myIndex) const1583 SbVec3f Vertex::getNormal(tagContext *con, uint16_t myIndex) const
1584 {
1585 int c = this->faceList.getLength();
1586 SbVec3f normal(0.f,0.f,0.f);
1587 for (int i=0; i<c; i++)
1588 normal += this->faceList[i]->getWeightedNormal(con, myIndex);
1589 // ok to have a null vector here, it probably just means that we
1590 // have an empty triangle.
1591 (void) normal.normalize();
1592 return normal;
1593 }
1594
1595
1596
getNormal(tagContext * con) const1597 SbVec3f Face::getNormal(tagContext *con) const
1598 {
1599 SbPlane plane(con->vertexList[v1].point, con->vertexList[v2].point,
1600 con->vertexList[v3].point);
1601 return plane.getNormal();
1602 }
1603
1604
1605
getAngle(tagContext * con,uint16_t vertexIndex) const1606 float Face::getAngle(tagContext *con, uint16_t vertexIndex) const
1607 {
1608 int i1, i2;
1609 if (v1 == vertexIndex) {
1610 i1 = v2; i2 = v3;
1611 } else {
1612 i1 = v1;
1613 if (v2 == vertexIndex) i2 = v3;
1614 else {
1615 assert(v3 == vertexIndex);
1616 i2 = v2;
1617 }
1618 }
1619
1620 SbVec3f vec1(con->vertexList[i1].point - con->vertexList[vertexIndex].point);
1621 SbVec3f vec2(con->vertexList[i2].point - con->vertexList[vertexIndex].point);
1622
1623 SbRotation rot(vec1, vec2);
1624 float value;
1625 rot.getValue(vec1, value);
1626 return value;
1627 }
1628
1629
1630
getWeightedNormal(tagContext * con,uint16_t vertexIndex) const1631 SbVec3f Face::getWeightedNormal(tagContext *con, uint16_t vertexIndex) const
1632 {
1633 return getNormal(con) * getAngle(con, vertexIndex);
1634 }
1635
1636
1637
init(tagContext * con,uint16_t a,uint16_t b,uint16_t c,uint16_t f)1638 void Face::init(tagContext *con, uint16_t a, uint16_t b, uint16_t c, uint16_t f)
1639 {
1640 v1=a; v2=b; v3=c; flags=f;
1641 faceGroup = NULL;
1642
1643 isDegenerated = (con->vertexList[v2].point-con->vertexList[v1].point).cross(
1644 con->vertexList[v3].point - con->vertexList[v1].point).sqrLength() == 0.f;
1645 if (isDegenerated) con->numDefaultDegFaces++;
1646
1647 int n,i;
1648 Face *face;
1649 if (con->appendNormals == 2) {
1650 e12 = e23 = e31 = 0xffffffff;
1651
1652 #define VERT_CODE(_nc_, _ns1_, _ns2_) \
1653 n = con->vertexList[v##_nc_].faceList.getLength(); \
1654 for (i=0; i<n; i++) { \
1655 face = con->vertexList[v##_nc_].faceList[i]; \
1656 if (v##_ns1_ == face->v##_ns1_) { \
1657 e##_nc_##_ns1_ = face->e##_nc_##_ns1_; \
1658 con->edgeList[face->e##_nc_##_ns1_].faceList.append(this); \
1659 } \
1660 if (v##_ns2_ == face->v##_ns1_) { \
1661 e##_ns2_##_nc_ = face->e##_nc_##_ns1_; \
1662 con->edgeList[face->e##_nc_##_ns1_].faceList.append(this); \
1663 } \
1664 if (v##_ns1_ == face->v##_ns2_) { \
1665 e##_nc_##_ns1_ = face->e##_ns2_##_nc_; \
1666 con->edgeList[face->e##_ns2_##_nc_].faceList.append(this); \
1667 } \
1668 if (v##_ns2_ == face->v##_ns2_) { \
1669 e##_ns2_##_nc_ = face->e##_ns2_##_nc_; \
1670 con->edgeList[face->e##_ns2_##_nc_].faceList.append(this); \
1671 } \
1672 } \
1673 con->vertexList[v##_nc_].faceList.append(this);
1674
1675 VERT_CODE(1,2,3);
1676 VERT_CODE(2,3,1);
1677 VERT_CODE(3,1,2);
1678
1679 #undef VERT_CODE
1680
1681 if (e12 == 0xffffffff)
1682 e12 = con->numEdges++;
1683 if (e23 == 0xffffffff)
1684 e23 = con->numEdges++;
1685 if (e31 == 0xffffffff)
1686 e31 = con->numEdges++;
1687 }
1688 }
1689
1690
1691
hasTexture2(tagContext * con)1692 SbBool FaceGroup::hasTexture2(tagContext *con)
1693 { return mat->hasTexture2(con); }
1694
getSoTexture2(tagContext * con)1695 SoTexture2* FaceGroup::getSoTexture2(tagContext *con)
1696 { return mat->getSoTexture2(con); }
1697
hasTexture2Transform(tagContext * con)1698 SbBool FaceGroup::hasTexture2Transform(tagContext *con)
1699 { return mat->hasTexture2Transform(con); }
1700
getSoTexture2Transform(tagContext * con)1701 SoTexture2Transform* FaceGroup::getSoTexture2Transform(tagContext *con)
1702 { return mat->getSoTexture2Transform(con); }
1703
getSoMaterial(tagContext * con)1704 SoMaterial* FaceGroup::getSoMaterial(tagContext *con)
1705 { return mat->getSoMaterial(con); }
1706
1707
1708
createSoNormal(tagContext * con)1709 SoNormal* FaceGroup::createSoNormal(tagContext *con)
1710 {
1711 SoNormal *normals = new SoNormal;
1712 int num = faceList.getLength();
1713 if (con->appendNormals == 1) {
1714 normals->vector.setNum(num-numDegFaces);
1715 SbVec3f *v = normals->vector.startEditing();
1716 for (int i=0; i<num; i++) {
1717 Face *f = faceList[i];
1718 if (!f->isDegenerated)
1719 *(v++) = f->getNormal(con);
1720 }
1721 normals->vector.finishEditing();
1722 } else {
1723 normals->vector.setNum(0);
1724 /* FIXME: This is incomplete implementation of per-vertex normal generator.
1725
1726 normals->vector.setNum(num*3);
1727 SbVec3f *v = normals->vector.startEditing();
1728 SbPlane p1, p2;
1729 for (int i=0; i<num; i++) {
1730 Face *f = faceList[i];
1731 Edge *e = &con->edgeList[f->e12];
1732 int fnum = e->faceList.getLength();
1733 int j;
1734 for (j=0; i<fnum; j++) {
1735 if (currface != facenum) { // check all but this face
1736 const SbVec3f &normal = facenormals[currface];
1737 if ((normal.dot(*facenormal)) > threshold) {
1738 // smooth towards this face
1739 vertnormal += normal;
1740 }
1741 }
1742 }
1743 *(v++) = con->vertexList[f->v1].getNormal(con, f->v1);
1744 *(v++) = con->vertexList[f->v2].getNormal(con, f->v2);
1745 *(v++) = con->vertexList[f->v3].getNormal(con, f->v3);
1746 }
1747 normals->vector.finishEditing();*/
1748 }
1749 return normals;
1750 }
1751
1752
1753
createSoCoordinate3_n(tagContext * con)1754 SoCoordinate3* FaceGroup::createSoCoordinate3_n(tagContext *con)
1755 {
1756 assert(!con->useIndexedTriSet && "Improper use.");
1757
1758 SoCoordinate3 *coords = new SoCoordinate3;
1759 int num = faceList.getLength();
1760 coords->point.setNum((num-numDegFaces)*3);
1761 SbVec3f *c = coords->point.startEditing();
1762 for (int i=0; i<num; i++) {
1763 Face *f = faceList[i];
1764 if (!f->isDegenerated) {
1765 *(c++) = con->vertexList[f->v1].point;
1766 *(c++) = con->vertexList[f->v2].point;
1767 *(c++) = con->vertexList[f->v3].point;
1768 }
1769 }
1770 coords->point.finishEditing();
1771 return coords;
1772 }
1773
1774
1775
createSoTextureCoordinate2_n(tagContext * con)1776 SoTextureCoordinate2* FaceGroup::createSoTextureCoordinate2_n(tagContext *con)
1777 {
1778 assert(!con->useIndexedTriSet && "Improper use.");
1779
1780 SoTextureCoordinate2 *tCoords = new SoTextureCoordinate2;
1781 int num = faceList.getLength();
1782 tCoords->point.setNum((num-numDegFaces)*3);
1783 SbVec2f *c = tCoords->point.startEditing();
1784 for (int i=0; i<num; i++) {
1785 Face *f = faceList[i];
1786 if (!f->isDegenerated) {
1787 *(c++) = con->vertexList[f->v1].texturePoint;
1788 *(c++) = con->vertexList[f->v2].texturePoint;
1789 *(c++) = con->vertexList[f->v3].texturePoint;
1790 }
1791 }
1792 tCoords->point.finishEditing();
1793 return tCoords;
1794 }
1795
1796
1797
createSoTriStripSet_n(tagContext * con)1798 SoTriangleStripSet* FaceGroup::createSoTriStripSet_n(tagContext *con)
1799 {
1800 assert(!con->useIndexedTriSet && "Improper use.");
1801
1802 SoTriangleStripSet *triSet = new SoTriangleStripSet;
1803 int num = faceList.getLength() - numDegFaces;
1804 triSet->numVertices.setNum(num);
1805 int32_t *n = triSet->numVertices.startEditing();
1806 for (int i=0; i<num; i++) {
1807 *(n++) = 3;
1808 }
1809 triSet->numVertices.finishEditing();
1810 return triSet;
1811 }
1812
1813
1814
createSoIndexedTriStripSet_i(tagContext * con)1815 SoIndexedTriangleStripSet* FaceGroup::createSoIndexedTriStripSet_i(tagContext *con)
1816 {
1817 assert(con->useIndexedTriSet && "Improper use.");
1818
1819 SoIndexedTriangleStripSet *triSet = new SoIndexedTriangleStripSet;
1820 int num = faceList.getLength();
1821 int i;
1822
1823 // coords
1824 triSet->coordIndex.setNum((num-numDegFaces)*4);
1825 int32_t *c = triSet->coordIndex.startEditing();
1826 for (i=0; i<num; i++) {
1827 Face *f = faceList[i];
1828 if (!f->isDegenerated) {
1829 *(c++) = f->v1;
1830 *(c++) = f->v2;
1831 *(c++) = f->v3;
1832 *(c++) = SO_END_STRIP_INDEX;
1833 }
1834 }
1835 triSet->coordIndex.finishEditing();
1836
1837 // texture
1838 if (mat->hasTexture2(con) && con->loadTextures) {
1839 triSet->textureCoordIndex.setNum((num-numDegFaces)*4);
1840 int32_t *tc = triSet->textureCoordIndex.startEditing();
1841 for (i=0; i<num; i++) {
1842 Face *f = faceList[i];
1843 if (!f->isDegenerated) {
1844 *(tc++) = f->v1;
1845 *(tc++) = f->v2;
1846 *(tc++) = f->v3;
1847 *(tc++) = SO_END_STRIP_INDEX;
1848 }
1849 }
1850 triSet->textureCoordIndex.finishEditing();
1851 }
1852
1853 return triSet;
1854 }
1855
1856
1857
getMaterial(tagContext * con)1858 Material* DefaultFaceGroup::getMaterial(tagContext *con)
1859 { return &con->defaultMat; }
1860
1861
1862
isEmpty(Context * con)1863 SbBool DefaultFaceGroup::isEmpty(Context *con)
1864 {
1865 int num = con->numFaces;
1866 for (int i=0; i<num; i++)
1867 if (con->faceList[i].faceGroup == NULL) return FALSE;
1868 return TRUE;
1869 }
1870
1871
1872
getSoMaterial(tagContext * con)1873 SoMaterial* DefaultFaceGroup::getSoMaterial(tagContext *con)
1874 {
1875 return getMaterial(con)->getSoMaterial(con);
1876 }
1877
1878
1879
createSoNormal(tagContext * con)1880 SoNormal* DefaultFaceGroup::createSoNormal(tagContext *con)
1881 {
1882 SoNormal *normals = new SoNormal;
1883 int num = con->numFaces;
1884 int j = 0;
1885 if (con->appendNormals == 1) {
1886 normals->vector.setNum(num - con->numDefaultDegFaces);
1887 SbVec3f *v = normals->vector.startEditing();
1888 for (int i=0; i<num; i++) {
1889 Face *f = &con->faceList[i];
1890 if (f->faceGroup == NULL && !f->isDegenerated) {
1891 *(v++) = f->getNormal(con);
1892 j++;
1893 }
1894 }
1895 normals->vector.finishEditing();
1896 normals->vector.setNum(j);
1897 } else {
1898 assert(FALSE);
1899 }
1900 return normals;
1901 }
1902
1903
1904
createSoCoordinate3_n(tagContext * con)1905 SoCoordinate3* DefaultFaceGroup::createSoCoordinate3_n(tagContext *con)
1906 {
1907 assert(!con->useIndexedTriSet && "Improper use.");
1908
1909 SoCoordinate3 *coords = new SoCoordinate3;
1910 int num = con->numFaces;
1911 coords->point.setNum((num - con->numDefaultDegFaces) * 3);
1912 SbVec3f *c = coords->point.startEditing();
1913 int j = 0;
1914 for (int i=0; i<num; i++) {
1915 Face *f = &con->faceList[i];
1916 if (f->faceGroup == NULL && !f->isDegenerated) {
1917 *(c++) = con->vertexList[f->v1].point;
1918 *(c++) = con->vertexList[f->v2].point;
1919 *(c++) = con->vertexList[f->v3].point;
1920 j += 3;
1921 }
1922 }
1923 coords->point.finishEditing();
1924 coords->point.setNum(j);
1925 return coords;
1926 }
1927
1928
1929
createSoTriStripSet_n(tagContext * con)1930 SoTriangleStripSet* DefaultFaceGroup::createSoTriStripSet_n(tagContext *con)
1931 {
1932 assert(!con->useIndexedTriSet && "Improper use.");
1933
1934 SoTriangleStripSet *triSet = new SoTriangleStripSet;
1935 int num = con->numFaces - con->numDefaultDegFaces;
1936 int i;
1937 int j = 0;
1938 for (i=0; i<num; i++) {
1939 Face *f = &con->faceList[i];
1940 if (f->faceGroup == NULL) j++;
1941 }
1942 j -= con->numDefaultDegFaces;
1943
1944 triSet->numVertices.setNum(j);
1945 int32_t *n = triSet->numVertices.startEditing();
1946 for (i=0; i<j; i++) {
1947 *(n++) = 3;
1948 }
1949 triSet->numVertices.finishEditing();
1950
1951 return triSet;
1952 }
1953
1954
1955
createSoIndexedTriStripSet_i(tagContext * con)1956 SoIndexedTriangleStripSet* DefaultFaceGroup::createSoIndexedTriStripSet_i(tagContext *con)
1957 {
1958 assert(con->useIndexedTriSet && "Improper use.");
1959
1960 SoIndexedTriangleStripSet *triSet = new SoIndexedTriangleStripSet;
1961 int num = con->numFaces;
1962 int i;
1963 int j = 0;
1964 for (i=0; i<num; i++) {
1965 Face *f = &con->faceList[i];
1966 if (f->faceGroup == NULL) j++;
1967 }
1968 j -= con->numDefaultDegFaces;
1969
1970 // coords
1971 triSet->coordIndex.setNum(j*4);
1972 int32_t *c = triSet->coordIndex.startEditing();
1973 for (i=0; i<num; i++) {
1974 Face *f = &con->faceList[i];
1975 if (f->faceGroup == NULL && !f->isDegenerated) {
1976 *(c++) = f->v1;
1977 *(c++) = f->v2;
1978 *(c++) = f->v3;
1979 *(c++) = SO_END_STRIP_INDEX;
1980 }
1981 }
1982 triSet->coordIndex.finishEditing();
1983
1984 return triSet;
1985 }
1986
1987
1988
updateSoMaterial(int index,SoMaterial * m)1989 void Material::updateSoMaterial(int index, SoMaterial *m)
1990 {
1991 m->ambientColor.set1Value(index, ambient);
1992 m->diffuseColor.set1Value(index, diffuse);
1993 m->specularColor.set1Value(index, specular);
1994 m->emissiveColor.set1Value(index, SbColor(0.f,0.f,0.f));
1995 m->shininess.set1Value(index, shininess);
1996 m->transparency.set1Value(index, transparency);
1997 }
1998
1999
2000
getSoMaterial(Context COIN_UNUSED_ARG (* con))2001 SoMaterial* Material::getSoMaterial(Context COIN_UNUSED_ARG(*con))
2002 { return matCache; }
2003
2004
2005
hasTexture2(tagContext COIN_UNUSED_ARG (* con))2006 SbBool Material::hasTexture2(tagContext COIN_UNUSED_ARG(*con))
2007 { return (texture2Cache != NULL); }
2008
2009
2010
getSoTexture2(tagContext COIN_UNUSED_ARG (* con))2011 SoTexture2* Material::getSoTexture2(tagContext COIN_UNUSED_ARG(*con))
2012 { return texture2Cache; }
2013
2014
2015
hasTexture2Transform(tagContext COIN_UNUSED_ARG (* con))2016 SbBool Material::hasTexture2Transform(tagContext COIN_UNUSED_ARG(*con))
2017 { return (texture2TransformCache != NULL); }
2018
2019
2020
getSoTexture2Transform(tagContext COIN_UNUSED_ARG (* con))2021 SoTexture2Transform* Material::getSoTexture2Transform(tagContext COIN_UNUSED_ARG(*con))
2022 { return texture2TransformCache; }
2023
2024
2025
createSoCoordinate3_i(Context * con) const2026 SoCoordinate3* Context::createSoCoordinate3_i(Context *con) const
2027 {
2028 assert(con->useIndexedTriSet && "Improper use.");
2029
2030 SoCoordinate3 *coords = new SoCoordinate3;
2031 coords->point.setNum(con->numVertices);
2032 SbVec3f *c = coords->point.startEditing();
2033 for (int i=0; i<con->numVertices; i++)
2034 c[i] = con->vertexList[i].point;
2035 coords->point.finishEditing();
2036 return coords;
2037 }
2038
2039
2040
createSoTextureCoordinate2_i(tagContext * con) const2041 SoTextureCoordinate2* Context::createSoTextureCoordinate2_i(tagContext *con) const
2042 {
2043 assert(con->useIndexedTriSet && "Improper use.");
2044
2045 SoTextureCoordinate2 *tCoords = new SoTextureCoordinate2;
2046 tCoords->point.setNum(con->numVertices);
2047 SbVec2f *c = tCoords->point.startEditing();
2048 for (int i=0; i<con->numVertices; i++)
2049 c[i] = con->vertexList[i].texturePoint;
2050 tCoords->point.finishEditing();
2051 return tCoords;
2052 }
2053
2054
2055
genGetEmptyTexture()2056 SoTexture2* Context::genGetEmptyTexture()
2057 {
2058 if (!genEmptyTexture) {
2059 genEmptyTexture = new SoTexture2;
2060 genEmptyTexture->ref();
2061 }
2062 return genEmptyTexture;
2063 }
2064
2065
2066
genGetEmptyTexTransform()2067 SoTexture2Transform* Context::genGetEmptyTexTransform()
2068 {
2069 if (!genEmptyTexTransform) {
2070 genEmptyTexTransform = new SoTexture2Transform;
2071 genEmptyTexTransform->ref();
2072 }
2073 return genEmptyTexTransform;
2074 }
2075
2076
2077
genGetOneSidedHints()2078 SoShapeHints* Context::genGetOneSidedHints()
2079 {
2080 if (!genOneSidedHints) {
2081 genOneSidedHints = new SoShapeHints;
2082 genOneSidedHints->ref();
2083 // backface culling on, one-sided lighting
2084 genOneSidedHints->vertexOrdering = SoShapeHints::COUNTERCLOCKWISE;
2085 genOneSidedHints->shapeType = SoShapeHints::SOLID;
2086 }
2087 return genOneSidedHints;
2088 }
2089
2090
2091
genGetTwoSidedHints()2092 SoShapeHints* Context::genGetTwoSidedHints()
2093 {
2094 if (!genTwoSidedHints) {
2095 genTwoSidedHints = new SoShapeHints;
2096 genTwoSidedHints->ref();
2097 // backface culling off, two-sided lighting
2098 genTwoSidedHints->vertexOrdering = SoShapeHints::COUNTERCLOCKWISE;
2099 genTwoSidedHints->shapeType = SoShapeHints::UNKNOWN_SHAPE_TYPE;
2100 }
2101 return genTwoSidedHints;
2102 }
2103
2104
2105
2106 /* Return value of COIN_DEBUG_3DS environment variable. */
coin_debug_3ds()2107 static int coin_debug_3ds()
2108 {
2109 static int d = -1;
2110 if (d == -1) {
2111 const char * val = coin_getenv("COIN_DEBUG_3DS");
2112 d = val ? atoi(val) : 0;
2113 }
2114 return d;
2115 }
2116
2117 // *************************************************************************
2118
2119 // This is the only interface exposed to code outside this file.
2120
2121 SbBool
coin_3ds_read_file(SoInput * in,SoSeparator * & root,int appendNormals,float creaseAngle,SbBool loadMaterials,SbBool loadTextures,SbBool loadObjNames,SbBool indexedTriSet,SbBool centerModel,float modelSize)2122 coin_3ds_read_file(SoInput *in, SoSeparator *&root,
2123 int appendNormals, float creaseAngle,
2124 SbBool loadMaterials, SbBool loadTextures,
2125 SbBool loadObjNames, SbBool indexedTriSet,
2126 SbBool centerModel, float modelSize)
2127 {
2128 SoStream s;
2129 s.setBinary(TRUE);
2130 s.setEndianOrdering(SoStream::LITTLE_ENDIAN_STREAM);
2131 s.wrapSoInput(in);
2132
2133 return read3dsFile(&s, root, appendNormals, creaseAngle, loadMaterials,
2134 loadTextures, loadObjNames, indexedTriSet,
2135 centerModel, modelSize);
2136 }
2137
2138 // *************************************************************************
2139