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