cimg.cxx 3.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/plugins/vrml.h ADDED
@@ -0,0 +1,894 @@
1
+ /*
2
+ #
3
+ # File : vrml.h
4
+ # ( C++ header file - CImg plug-in )
5
+ #
6
+ # Description : CImg plugin that provide functions to load/save VRML files.
7
+ # This file is a part of the CImg Library project.
8
+ # ( http://cimg.eu )
9
+ #
10
+ # Copyright : Greg Rami
11
+ # ( greg.rami36 (at) gmail.com )
12
+ #
13
+ # License : CeCILL v2.0
14
+ # ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
15
+ #
16
+ # This software is governed by the CeCILL license under French law and
17
+ # abiding by the rules of distribution of free software. You can use,
18
+ # modify and/ or redistribute the software under the terms of the CeCILL
19
+ # license as circulated by CEA, CNRS and INRIA at the following URL
20
+ # "http://www.cecill.info".
21
+ #
22
+ # As a counterpart to the access to the source code and rights to copy,
23
+ # modify and redistribute granted by the license, users are provided only
24
+ # with a limited warranty and the software's author, the holder of the
25
+ # economic rights, and the successive licensors have only limited
26
+ # liability.
27
+ #
28
+ # In this respect, the user's attention is drawn to the risks associated
29
+ # with loading, using, modifying and/or developing or reproducing the
30
+ # software by the user in light of its specific status of free software,
31
+ # that may mean that it is complicated to manipulate, and that also
32
+ # therefore means that it is reserved for developers and experienced
33
+ # professionals having in-depth computer knowledge. Users are therefore
34
+ # encouraged to load and test the software's suitability as regards their
35
+ # requirements in conditions enabling the security of their systems and/or
36
+ # data to be ensured and, more generally, to use and operate it in the
37
+ # same conditions as regards security.
38
+ #
39
+ # The fact that you are presently reading this means that you have had
40
+ # knowledge of the CeCILL license and that you accept its terms.
41
+ #
42
+ */
43
+
44
+ /*-----------------------------------------------------------------------------------
45
+
46
+ IMPORTANT NOTE :
47
+
48
+ You *need* to include the following lines in your own code to use this plugin :
49
+
50
+ #include <vector>
51
+ #include <string>
52
+ #include <sstream>
53
+ #include <algorithm>
54
+
55
+ ------------------------------------------------------------------------------------*/
56
+
57
+ #ifndef cimg_plugin_vrml
58
+ #define cimg_plugin_vrml
59
+
60
+ //! Load a 3d object from a .VRML file.
61
+ template<typename tf, typename tc>
62
+ CImg<T>& load_vrml(const char *const filename, CImgList<tf>& primitives, CImgList<tc>& colors) {
63
+ return _load_vrml(0,filename,primitives,colors);
64
+ }
65
+
66
+ //! Load a 3d object from a .VRML file.
67
+ template<typename tf, typename tc>
68
+ static CImg<T> get_load_vrml(const char *const filename, CImgList<tf>& primitives, CImgList<tc>& colors) {
69
+ return CImg<T>().load_vrml(filename,primitives,colors);
70
+ }
71
+
72
+ //! Load a 3d object from a .VRML file.
73
+ template<typename tf, typename tc>
74
+ CImg<T>& load_vrml(std::FILE *const file, CImgList<tf>& primitives, CImgList<tc>& colors) {
75
+ return _load_vrml(file,0,primitives,colors);
76
+ }
77
+
78
+ //! Load a 3d object from a .VRML file.
79
+ template<typename tf, typename tc>
80
+ static CImg<T> get_load_vrml(std::FILE *const file, CImgList<tf>& primitives, CImgList<tc>& colors) {
81
+ return CImg<T>().load_vrml(file,primitives,colors);
82
+ }
83
+
84
+ //! Load a 3d object from a .VRML file (internal).
85
+ template<typename tf, typename tc>
86
+ CImg<T>& _load_vrml(std::FILE *const file, const char *const filename,CImgList<tf>& primitives, CImgList<tc>& colors) {
87
+ if (!file && !filename)
88
+ throw CImgArgumentException(_cimg_instance
89
+ "load_vrml() : Specified filename is (null).",
90
+ cimg_instance);
91
+ std::FILE *const nfile = file?file:cimg::fopen(filename,"r");
92
+
93
+ char line[1024] = { 0 };
94
+ int err;
95
+
96
+ // Skip comments, and read the first node.
97
+ do { err = std::fscanf(nfile,"%65535[^\n] ",line); } while (!err || (err==1 && *line=='#'));
98
+
99
+ // Check for a first valid vrml valid node.
100
+ if (cimg::strncasecmp(line,"Shape",5) &&
101
+ cimg::strncasecmp(line,"Transform",9) &&
102
+ cimg::strncasecmp(line,"NavigationInfo",14) &&
103
+ cimg::strncasecmp(line,"Billboard",9)) {
104
+ if (!file) cimg::fclose(nfile);
105
+ throw CImgIOException(_cimg_instance
106
+ "load_vrml() : VRML nodes not found in file '%s'.",
107
+ cimg_instance,filename?filename:"(FILE*)");
108
+ }
109
+
110
+ // Look for the Shape node (as we do not manage the treatment for the other nodes yet).
111
+ if (cimg::strncasecmp(line,"Shape",5)) {
112
+ while (cimg::strncasecmp(line,"Shape",5) && !std::feof(nfile)) err = std::fscanf(nfile,"%1023[^\n] ",line);
113
+ if (std::feof(nfile)) {
114
+ if (!file) cimg::fclose(nfile);
115
+ throw CImgIOException(_cimg_instance
116
+ "load_vrml() : Shape node not found in file '%s'.",
117
+ cimg_instance,filename?filename:"(FILE*)");
118
+ }
119
+ }
120
+
121
+ // Look for either geometry or appearance node.
122
+ while (cimg::strncasecmp(line,"geometry",8) && cimg::strncasecmp(line,"appearance",10) && !std::feof(nfile))
123
+ err = std::fscanf(nfile,"%1023[^\n] ",line);
124
+ if (std::feof(nfile)) { // If none of these nodes are defined.
125
+ if (!file) cimg::fclose(nfile);
126
+ throw CImgIOException(_cimg_instance
127
+ "load_vrml() : Geometry and appearance nodes not found in file '%s'.",
128
+ cimg_instance,filename?filename:"(FILE*)");
129
+ }
130
+
131
+ std::vector<T> listePoints; // Intermediate list containing the points of the whole object.
132
+ primitives.assign();
133
+ colors.assign();
134
+ // Count the number of points of the whole object and the number of primitives.
135
+ int nbPointsTotal = 0, nbPrimitives = 0;
136
+ float r = 0.78f, g = 0.78f, b = 0.78f; // RGB level of the object, the object is gray by default.
137
+ // Boolean used to know if a color is defined for an object,
138
+ // if this object has multiple colors or if the object has a texture
139
+ bool colorDefined = true, multipleColors = false, textureTest = false;
140
+ char textureFile[1024] = { 0 }; // Variable containing the name of the image used as a texture
141
+
142
+ while (!std::feof(nfile)) {
143
+ char type[1024] = { 0 }, textureFileTemp[1024] = { 0 };
144
+ colorDefined = true;
145
+ if (!cimg::strncasecmp(line,"geometry",8)) { // We are at the geometry node
146
+ std::sscanf(line,"geometry %s",type); // We are looking for the type of geometry to draw
147
+ const CImg<float> coords = CImg<float>::empty(); // CImg used for the texturization of an object
148
+ CImgList<tc> colorsTextured; // CImgList used for the texturization of the color of an object
149
+ CImgList<tf> primitivesTemp; // Intermediate CImgList used to update the primitives of the whole object
150
+
151
+ if (!cimg::strncasecmp(type,"Box",3)) { // If the object to draw is a box
152
+ while (cimg::strncasecmp(line,"size",4) && !std::feof(nfile)) // We are looking for the size of the box
153
+ err = std::fscanf(nfile,"%1023[^\n] ",line);
154
+
155
+ if (std::feof(nfile)) { // If no size is specified
156
+ if (!file) cimg::fclose(nfile);
157
+ throw CImgIOException(_cimg_instance
158
+ "load_vrml() : size of box not defined in file '%s'.",
159
+ cimg_instance, filename?filename:"(FILE*)");
160
+ }
161
+
162
+ float X = 0, Y = 0, Z = 0; // The width, height and depth of the box
163
+ if ((err = std::sscanf(line,"size %f %f %f[^\n] ",&X,&Y,&Z))!=3 &&
164
+ (err = std::sscanf(line,"size %f,%f,%f[^\n] ",&X,&Y,&Z))!=3) {
165
+ if (!file) cimg::fclose(nfile);
166
+ throw CImgIOException(_cimg_instance
167
+ "load_vrml() : Failed to read box size in file '%s'.",
168
+ cimg_instance,filename?filename:"(FILE*)");
169
+ }
170
+ // We generate the primitives and the points of the box
171
+ const CImg<T> pointsTemp = CImg<T>::box3d(primitivesTemp,(T)X,(T)Y,(T)Z);
172
+
173
+ nbPrimitives = primitivesTemp.size(); // We save the number of primitives of the object
174
+
175
+ if (textureTest) { // If the object has a texture
176
+ // We put the image used as a texture into a CImg object
177
+ const CImg<float> texture(textureFile);
178
+ // We initialize the colorsTextured list
179
+ colorsTextured.insert(primitivesTemp.size(),CImg<unsigned char>::vector(0,50,250));
180
+ // We texturize the object
181
+ pointsTemp.texturize_object3d(primitivesTemp,colorsTextured,texture,coords);
182
+ nbPrimitives = 0;
183
+ }
184
+
185
+ if(nbPointsTotal) { // If there are already some objects in the scene
186
+ for (int j=0;j<(int)primitivesTemp.size();j++) {
187
+ for(int i=0;i<4;i++)
188
+ // We shift the indices in the primitives to designate the right points
189
+ primitivesTemp(j).at(i) += (tf)nbPointsTotal;
190
+ }
191
+ }
192
+ primitives.push_back(primitivesTemp); // We add the primitives of the box to the general primitives variable
193
+ for(int i=0;i<(int)pointsTemp.size()/3;++i) { // We add the points into the temporary list in the right order
194
+ listePoints.push_back((T)pointsTemp.at(i));
195
+ listePoints.push_back((T)pointsTemp.at(i + 8));
196
+ listePoints.push_back((T)pointsTemp.at(i + 16));
197
+ }
198
+ nbPointsTotal += pointsTemp.size()/3; // We increase the number of points of the whole object
199
+ }
200
+ else if(!cimg::strncasecmp(type,"Sphere",6)) { // If the object to draw is a sphere
201
+ while(cimg::strncasecmp(line,"radius",6) && !std::feof(nfile))
202
+ err = std::fscanf(nfile,"%1023[^\n] ",line);
203
+
204
+ if(std::feof(nfile)) {
205
+ if (!file)
206
+ cimg::fclose(nfile);
207
+ throw CImgIOException(_cimg_instance
208
+ "load_vrml() : radius of sphere not defined in file '%s'.",
209
+ cimg_instance, filename?filename:"(FILE*)");
210
+ }
211
+
212
+ float R = 0;
213
+ if ((err = std::sscanf(line,"radius %f[^\n] ",&R))!=1) { // We get the radius of the sphere
214
+ if (!file)
215
+ cimg::fclose(nfile);
216
+ throw CImgIOException(_cimg_instance
217
+ "load_vrml() : Failed to read sphere radius in file '%s'.",
218
+ cimg_instance,filename?filename:"(FILE*)");
219
+ }
220
+ // Compute the necessary points and primitives for a sphere of radius R
221
+ const CImg<T> pointsTemp = CImg<T>::sphere3d(primitivesTemp,(T)R);
222
+ // We get the number of primitives to used on the attribution of a color, in case no specific color is defined
223
+ nbPrimitives = primitivesTemp.size();
224
+
225
+ if(textureTest) { // If the object has a texture
226
+ // We put the image used as a texture into a CImg object
227
+ const CImg<float> texture(textureFile);
228
+ // We initialize the colorsTextured list
229
+ colorsTextured.insert(primitivesTemp.size(),CImg<unsigned char>::vector(0,50,250));
230
+ pointsTemp.texturize_object3d(primitivesTemp,colorsTextured,texture,coords); // We texturize the object
231
+ nbPrimitives = 0; // We set to 0 because there is no color to use
232
+ }
233
+
234
+ if(nbPointsTotal) { // If there are already some objects in the scene
235
+ for (int j=0;j<(int)primitivesTemp.size();j++) {
236
+ for(int i=0;i<3;i++)
237
+ primitivesTemp(j).at(i) += (tf)nbPointsTotal;
238
+ }
239
+ }
240
+
241
+ primitives.push_back(primitivesTemp);
242
+ for(int i=0;i<(int)pointsTemp.size()/3;++i) {
243
+ listePoints.push_back((T)pointsTemp.at(i));
244
+ listePoints.push_back((T)pointsTemp.at(i + pointsTemp.size()/3));
245
+ listePoints.push_back((T)pointsTemp.at(i + 2*pointsTemp.size()/3));
246
+ }
247
+ nbPointsTotal += pointsTemp.size()/3;
248
+ }
249
+ else if(!cimg::strncasecmp(type,"Cone",4)) { // If the object to draw is a cone
250
+ while(cimg::strncasecmp(line,"bottomRadius",12) && !std::feof(nfile) && cimg::strncasecmp(line,"height",6))
251
+ err = std::fscanf(nfile,"%1023[^\n] ",line);
252
+ float R = 0, H = 0;
253
+ if(std::feof(nfile)) {
254
+ if (!file)
255
+ cimg::fclose(nfile);
256
+ throw CImgIOException(_cimg_instance
257
+ "load_vrml() : bottom radius and height of cone not defined in file '%s'.",
258
+ cimg_instance, filename?filename:"(FILE*)");
259
+ }
260
+ else if(!cimg::strncasecmp(line,"bottomRadius",12)) { // We find the bottom radius of the cone first
261
+ if ((err = std::sscanf(line,"bottomRadius %f[^\n] ",&R))!=1) { // We get the radius into the variable R
262
+ if (!file)
263
+ cimg::fclose(nfile);
264
+ throw CImgIOException(_cimg_instance
265
+ "load_vrml() : Failed to read cone bottomRadius in file '%s'.",
266
+ cimg_instance,filename?filename:"(FILE*)");
267
+ }
268
+ while(!std::feof(nfile) && cimg::strncasecmp(line,"height",6)) // We look for the height of the cone
269
+ err = std::fscanf(nfile,"%1023[^\n] ",line);
270
+
271
+ if(std::feof(nfile)) {
272
+ if (!file)
273
+ cimg::fclose(nfile);
274
+ throw CImgIOException(_cimg_instance
275
+ "load_vrml() : height of cone not defined in file '%s'.",
276
+ cimg_instance, filename?filename:"(FILE*)");
277
+ }
278
+
279
+ if ((err = std::sscanf(line,"height %f[^\n] ",&H))!=1) { // We get the height into the variable H
280
+ if (!file)
281
+ cimg::fclose(nfile);
282
+ throw CImgIOException(_cimg_instance
283
+ "load_vrml() : Failed to read cone height in file '%s'.",
284
+ cimg_instance,filename?filename:"(FILE*)");
285
+ }
286
+ }
287
+ else { // We find the height of the cone first
288
+ if ((err = std::sscanf(line,"height %f[^\n] ",&H))!=1) {
289
+ if (!file)
290
+ cimg::fclose(nfile);
291
+ throw CImgIOException(_cimg_instance
292
+ "load_vrml() : Failed to read cone height in file '%s'.",
293
+ cimg_instance,filename?filename:"(FILE*)");
294
+ }
295
+ while(!std::feof(nfile) && cimg::strncasecmp(line,"bottomRadius",12))
296
+ err = std::fscanf(nfile,"%1023[^\n] ",line);
297
+
298
+ if(std::feof(nfile)) {
299
+ if (!file)
300
+ cimg::fclose(nfile);
301
+ throw CImgIOException(_cimg_instance
302
+ "load_vrml() : bottom radius of cone not defined in file '%s'.",
303
+ cimg_instance, filename?filename:"(FILE*)");
304
+ }
305
+
306
+ if ((err = std::sscanf(line,"bottomRadius %f[^\n] ",&R))!=1) {
307
+ if (!file)
308
+ cimg::fclose(nfile);
309
+ throw CImgIOException(_cimg_instance
310
+ "load_vrml() : Failed to read cone bottom radius in file '%s'.",
311
+ cimg_instance,filename?filename:"(FILE*)");
312
+ }
313
+ }
314
+ // Compute the necessary points and primitives for a cone of radius R and height H
315
+ const CImg<T> pointsTemp = CImg<T>::cone3d(primitivesTemp,(T)R,(T)H);
316
+
317
+ nbPrimitives = primitivesTemp.size();
318
+
319
+ if(textureTest) { // If the object has a texture
320
+ // We put the image used as a texture into a CImg object
321
+ const CImg<float> texture(textureFile);
322
+ // We initialize the colorsTextured list
323
+ colorsTextured.insert(primitivesTemp.size(),CImg<unsigned char>::vector(0,50,250));
324
+ pointsTemp.texturize_object3d(primitivesTemp,colorsTextured,texture,coords); // We texturize the object
325
+ nbPrimitives = 0;
326
+ }
327
+
328
+ if(nbPointsTotal) {
329
+ for (int j=0;j<(int)primitivesTemp.size();j++) {
330
+ for(int i=0;i<3;i++)
331
+ primitivesTemp(j).at(i) += (tf)nbPointsTotal;
332
+ }
333
+ }
334
+
335
+ primitives.push_back(primitivesTemp);
336
+ for(int i=0;i<(int)pointsTemp.size()/3;++i) {
337
+ listePoints.push_back((T)pointsTemp.at(i));
338
+ listePoints.push_back((T)pointsTemp.at(i + pointsTemp.size()/3));
339
+ listePoints.push_back((T)pointsTemp.at(i + 2*pointsTemp.size()/3));
340
+ }
341
+ nbPointsTotal += pointsTemp.size()/3;
342
+ }
343
+ else if(!cimg::strncasecmp(type,"Cylinder",8)) { // If the object to draw is a cylinder
344
+ while(cimg::strncasecmp(line,"radius",6) && !std::feof(nfile) && cimg::strncasecmp(line,"height",6))
345
+ err = std::fscanf(nfile,"%1023[^\n] ",line);
346
+ float R = 0, H = 0;
347
+ if(std::feof(nfile)) {
348
+ if (!file)
349
+ cimg::fclose(nfile);
350
+ throw CImgIOException(_cimg_instance
351
+ "load_vrml() : radius or height of cylinder not defined in file '%s'.",
352
+ cimg_instance, filename?filename:"(FILE*)");
353
+ }
354
+ else if(!cimg::strncasecmp(line,"radius",6)) { // If we find the radius first
355
+ if ((err = std::sscanf(line,"radius %f[^\n] ",&R))!=1) {
356
+ if (!file)
357
+ cimg::fclose(nfile);
358
+ throw CImgIOException(_cimg_instance
359
+ "load_vrml() : Failed to read cylinder radius in file '%s'.",
360
+ cimg_instance,filename?filename:"(FILE*)");
361
+ }
362
+ while(!std::feof(nfile) && cimg::strncasecmp(line,"height",6)) // We now look for the height of the cylinder
363
+ err = std::fscanf(nfile,"%1023[^\n] ",line);
364
+
365
+ if(std::feof(nfile)) {
366
+ if (!file)
367
+ cimg::fclose(nfile);
368
+ throw CImgIOException(_cimg_instance
369
+ "load_vrml() : height of cylinder not defined in file '%s'.",
370
+ cimg_instance, filename?filename:"(FILE*)");
371
+ }
372
+
373
+ if ((err = std::sscanf(line,"height %f[^\n] ",&H))!=1) {
374
+ if (!file)
375
+ cimg::fclose(nfile);
376
+ throw CImgIOException(_cimg_instance
377
+ "load_vrml() : Failed to read cylinder height in file '%s'.",
378
+ cimg_instance,filename?filename:"(FILE*)");
379
+ }
380
+ }
381
+ else { // If we find the height first
382
+ if ((err = std::sscanf(line,"height %f[^\n] ",&H))!=1) {
383
+ if (!file)
384
+ cimg::fclose(nfile);
385
+ throw CImgIOException(_cimg_instance
386
+ "load_vrml() : Failed to read cylinder height in file '%s'.",
387
+ cimg_instance,filename?filename:"(FILE*)");
388
+ }
389
+ while(!std::feof(nfile) && cimg::strncasecmp(line,"radius",6))// We now look for the radius of the cylinder
390
+ err = std::fscanf(nfile,"%1023[^\n] ",line);
391
+
392
+ if(std::feof(nfile)) {
393
+ if (!file)
394
+ cimg::fclose(nfile);
395
+ throw CImgIOException(_cimg_instance
396
+ "load_vrml() : radius of cylinder not defined in file '%s'.",
397
+ cimg_instance, filename?filename:"(FILE*)");
398
+ }
399
+
400
+ if ((err = std::sscanf(line,"radius %f[^\n] ",&R))!=1) {
401
+ if (!file)
402
+ cimg::fclose(nfile);
403
+ throw CImgIOException(_cimg_instance
404
+ "load_vrml() : Failed to read cylinder radius in file '%s'.",
405
+ cimg_instance,filename?filename:"(FILE*)");
406
+ }
407
+ }
408
+ // Compute the necessary points and primitives for a cylinder of radius R and height H
409
+ const CImg<T> pointsTemp = CImg<T>::cylinder3d(primitivesTemp,(T)R,(T)H);
410
+
411
+ if(textureTest) { // If the object has a texture
412
+ // We put the image used as a texture into a CImg object
413
+ const CImg<float> texture(textureFile);
414
+ // We initialize the colorsTextured list
415
+ colorsTextured.insert(primitivesTemp.size(),CImg<unsigned char>::vector(0,50,250));
416
+ pointsTemp.texturize_object3d(primitivesTemp,colorsTextured,texture,coords); // We texturize the object
417
+ nbPrimitives = 0;
418
+ }
419
+
420
+ nbPrimitives = primitivesTemp.size();
421
+
422
+ if(nbPointsTotal) {
423
+ for (int j=0;j<(int)primitivesTemp.size();j++) {
424
+ for(int i=0;i<3;i++)
425
+ primitivesTemp(j).at(i) += (tf)nbPointsTotal;
426
+ }
427
+ }
428
+
429
+ primitives.push_back(primitivesTemp);
430
+ for(int i=0;i<(int)pointsTemp.size()/3;++i) {
431
+ listePoints.push_back((T)pointsTemp.at(i));
432
+ listePoints.push_back((T)pointsTemp.at(i + pointsTemp.size()/3));
433
+ listePoints.push_back((T)pointsTemp.at(i + 2*pointsTemp.size()/3));
434
+ }
435
+ nbPointsTotal += pointsTemp.size()/3;
436
+ }
437
+ else if(!cimg::strncasecmp(type,"PointSet",8)) { // If the object to draw is a set of points
438
+ while(cimg::strncasecmp(line,"point [",7) && !std::feof(nfile))
439
+ err = std::fscanf(nfile,"%1023[^\n] ",line);
440
+
441
+ if(std::feof(nfile)) {
442
+ if (!file)
443
+ cimg::fclose(nfile);
444
+ throw CImgIOException(_cimg_instance
445
+ "load_vrml() : points of pointSet node not defined in file '%s'.",
446
+ cimg_instance, filename?filename:"(FILE*)");
447
+ }
448
+
449
+ err = std::fscanf(nfile,"%1023[^\n] ",line);
450
+ int nbPoints = 0;
451
+
452
+ while(cimg::strncasecmp(line,"]",1) && !std::feof(nfile)) {
453
+ // while we did not get all the points and while we are not at the end of the file
454
+ float X = 0, Y = 0, Z = 0;
455
+ if ((err = std::sscanf(line,"%f %f %f,[^\n] ",&X,&Y,&Z))==3 ||
456
+ (err = std::sscanf(line,"%f,%f,%f,[^\n] ",&X,&Y,&Z))==3) {
457
+ // We get the coordinates of all the points and store them into a list of points
458
+ listePoints.push_back((T)X);
459
+ listePoints.push_back((T)Y);
460
+ listePoints.push_back((T)Z);
461
+ ++nbPoints;
462
+ }
463
+ err = std::fscanf(nfile,"%1023[^\n] ",line);
464
+ }
465
+ if(std::feof(nfile)) {
466
+ if (!file)
467
+ cimg::fclose(nfile);
468
+ throw CImgIOException(_cimg_instance
469
+ "load_vrml() : bad structure of pointSet node in file '%s'.",
470
+ cimg_instance, filename?filename:"(FILE*)");
471
+ }
472
+ primitivesTemp.assign();
473
+
474
+ for(int i=0;i<nbPoints;++i) { // The primitive is only composed of the indice of the point itself
475
+ CImg<tf> temp(1,1,1,1,(tf)i);
476
+ primitivesTemp.push_back(temp);
477
+ }
478
+
479
+ if(nbPointsTotal) {
480
+ for (int j=0;j<(int)primitivesTemp.size();j++) {
481
+ for(int i=0;i<(int)primitivesTemp(j).size();i++)
482
+ primitivesTemp(j).at(i) += (tf)nbPointsTotal;
483
+ }
484
+ }
485
+ nbPrimitives = primitivesTemp.size();
486
+
487
+ primitives.push_back(primitivesTemp);
488
+
489
+ nbPointsTotal += nbPoints;
490
+ }
491
+ else if(!cimg::strncasecmp(type,"IndexedLineSet",14) ||
492
+ !cimg::strncasecmp(type,"IndexedFaceSet",14)) {
493
+ // If the object to draw is a set of lines or a set of faces
494
+ while(cimg::strncasecmp(line,"point [",7) && !std::feof(nfile))
495
+ err = std::fscanf(nfile,"%1023[^\n] ",line);
496
+ if(std::feof(nfile)) {
497
+ if (!file)
498
+ cimg::fclose(nfile);
499
+ throw CImgIOException(_cimg_instance
500
+ "load_vrml() : points of IndexedSet node not defined in file '%s'.",
501
+ cimg_instance, filename?filename:"(FILE*)");
502
+ }
503
+
504
+ err = std::fscanf(nfile,"%1023[^\n] ",line);
505
+ int nbPoints = 0;
506
+ while(cimg::strncasecmp(line,"]",1) && !std::feof(nfile)) {
507
+ // As long as there are points defined we add them to the list
508
+ float X=0,Y=0,Z=0;
509
+ if ((err = std::sscanf(line,"%f %f %f,[^\n] ",&X,&Y,&Z))==3 ||
510
+ (err = std::sscanf(line,"%f,%f,%f,[^\n] ",&X,&Y,&Z))==3) {
511
+ // We get the coordinates of the points into a list of points
512
+ listePoints.push_back((T)X);
513
+ listePoints.push_back((T)Y);
514
+ listePoints.push_back((T)Z);
515
+ ++nbPoints;
516
+ }
517
+ err = std::fscanf(nfile,"%1023[^\n] ",line);
518
+ }
519
+ if(std::feof(nfile)) {
520
+ if (!file)
521
+ cimg::fclose(nfile);
522
+ throw CImgIOException(_cimg_instance
523
+ "load_vrml() : bad structure of point vector node in file '%s'.",
524
+ cimg_instance, filename?filename:"(FILE*)");
525
+ }
526
+
527
+ primitivesTemp.assign();
528
+
529
+ while(cimg::strncasecmp(line,"coordIndex [",12) && !std::feof(nfile))
530
+ // We are looking for the index of the points
531
+ err = std::fscanf(nfile,"%1023[^\n] ",line);
532
+ if(std::feof(nfile)) {
533
+ if (!file)
534
+ cimg::fclose(nfile);
535
+ throw CImgIOException(_cimg_instance
536
+ "load_vrml() : coordIndex not furnished for IndexedSet node in file '%s'.",
537
+ cimg_instance, filename?filename:"(FILE*)");
538
+ }
539
+
540
+ err = std::fscanf(nfile,"%1023[^\n] ",line);
541
+
542
+ while(cimg::strncasecmp(line,"]",1) && !std::feof(nfile)) { // As long as there are indices
543
+ if(*line!='#') {
544
+ std::vector<tf> primitiveComponents;
545
+ char * pch;
546
+ pch = std::strtok (line,",");
547
+
548
+ while (pch != NULL && std::atof(pch)!=-1) { // We extract the list of indices and store them into a vector
549
+ if(!(int)count(primitiveComponents.begin(),primitiveComponents.end(),(tf)std::atof(pch)))
550
+ primitiveComponents.push_back((tf)std::atof(pch));
551
+ pch = std::strtok (NULL, ",");
552
+ }
553
+ CImg<tf> temp(1,primitiveComponents.size(),1,1);
554
+
555
+ for(int i=0;i<(int)primitiveComponents.size();++i)
556
+ temp(0,i) = primitiveComponents.at(i);
557
+ primitivesTemp.push_back(temp);
558
+ }
559
+ err = std::fscanf(nfile,"%1023[^\n] ",line);
560
+ }
561
+
562
+ if(std::feof(nfile)) {
563
+ if (!file)
564
+ cimg::fclose(nfile);
565
+ throw CImgIOException(_cimg_instance
566
+ "load_vrml() : bad structure of coordIndex in file '%s'.",
567
+ cimg_instance, filename?filename:"(FILE*)");
568
+ }
569
+
570
+ if(nbPointsTotal) {
571
+ for (int j=0;j<(int)primitivesTemp.size();j++) {
572
+ for(int i=0;i<(int)primitivesTemp(j).size();i++)
573
+ primitivesTemp(j).at(i) += (tf)nbPointsTotal;
574
+ }
575
+ }
576
+
577
+ nbPrimitives = primitivesTemp.size();
578
+ primitives.push_back(primitivesTemp);
579
+ nbPointsTotal += nbPoints;
580
+
581
+ while(cimg::strncasecmp(line,"color [",7) && cimg::strncasecmp(line,"}",1) && !std::feof(nfile))
582
+ err = std::fscanf(nfile,"%1023[^\n] ",line);
583
+ if(std::feof(nfile)) {
584
+ if (!file)
585
+ cimg::fclose(nfile);
586
+ throw CImgIOException(_cimg_instance
587
+ "load_vrml() : bad structure of coordIndex in file '%s'.",
588
+ cimg_instance, filename?filename:"(FILE*)");
589
+ }
590
+ else if(!cimg::strncasecmp(line,"color [",7)) { // If there are different colors defined for each faces
591
+ multipleColors = true;
592
+ std::vector<CImg<tc> > listColors;
593
+ err = std::fscanf(nfile,"%1023[^\n] ",line);
594
+ while(cimg::strncasecmp(line,"]",1) && !std::feof(nfile)) {
595
+ // We add the list of all colors defined into the vector listColors
596
+ if(*line!='#') {
597
+ if ((err = std::sscanf(line,"%f %f %f[^\n] ",&r,&g,&b))!=3) {
598
+ if (!file)
599
+ cimg::fclose(nfile);
600
+ throw CImgIOException(_cimg_instance
601
+ "load_vrml() : wrong number of color furnished in file '%s'.",
602
+ cimg_instance,filename?filename:"(FILE*)");
603
+ }
604
+ CImg<tc> img(3,1,1,1,(tc)(r*255),(tc)(g*255),(tc)(b*255));
605
+ listColors.push_back(img);
606
+ }
607
+ err = std::fscanf(nfile,"%1023[^\n] ",line);
608
+ }
609
+ if(std::feof(nfile)) {
610
+ if (!file)
611
+ cimg::fclose(nfile);
612
+ throw CImgIOException(_cimg_instance
613
+ "load_vrml() : bad structure of color in file '%s'.",
614
+ cimg_instance, filename?filename:"(FILE*)");
615
+ }
616
+ else {
617
+ while(cimg::strncasecmp(line,"colorIndex [",12) && !std::feof(nfile))
618
+ err = std::fscanf(nfile,"%1023[^\n] ",line);
619
+ if(std::feof(nfile)) {
620
+ if (!file)
621
+ cimg::fclose(nfile);
622
+ throw CImgIOException(_cimg_instance
623
+ "load_vrml() : colorIndex not furnished for Color node in file '%s'.",
624
+ cimg_instance, filename?filename:"(FILE*)");
625
+ }
626
+ err = std::fscanf(nfile,"%1023[^\n] ",line);
627
+ while(cimg::strncasecmp(line,"]",1) && !std::feof(nfile)) {
628
+ // We add the colors at the right index into the vector colors
629
+ if(*line!='#') {
630
+ char * pch;
631
+ pch = std::strtok (line," ");
632
+ while (pch != NULL) {
633
+ int indice = std::atoi(pch);
634
+ colors.insert(CImg<tc>::vector((tc)(listColors[indice])[0],
635
+ (tc)(listColors[indice])[1],
636
+ (tc)(listColors[indice])[2]));
637
+ pch = std::strtok (NULL, " ");
638
+ }
639
+ }
640
+ err = std::fscanf(nfile,"%1023[^\n] ",line);
641
+ }
642
+ }
643
+ }
644
+ }
645
+ else // If none of the known type of shape is defined
646
+ cimg::warn(_cimg_instance
647
+ "load_vrml() : Failed to read type of geometry to draw from file '%s'.",
648
+ cimg_instance,filename?filename:"(FILE*)");
649
+
650
+ if(textureTest) { // If the object considered is texturized
651
+ colors.push_back(colorsTextured);
652
+ *textureFile = 0;
653
+ }
654
+ while(cimg::strncasecmp(line,"appearance",10) &&
655
+ cimg::strncasecmp(line,"Shape",5) && !std::feof(nfile))
656
+ // We look for the node appearance or for another shape
657
+ err = std::fscanf(nfile,"%1023[^\n] ",line);
658
+ }
659
+ if(!cimg::strncasecmp(line,"appearance",10)) { // We are at the appearance node
660
+ while(cimg::strncasecmp(line,"texture ImageTexture",20) &&
661
+ cimg::strncasecmp(line,"diffuseColor",12) && !std::feof(nfile))
662
+ // We are looking for a valid appearance node
663
+ err = std::fscanf(nfile,"%1023[^\n] ",line);
664
+ if(!cimg::strncasecmp(line,"diffuseColor",12)) { // If the object as a unique diffuse color
665
+ if ((err = std::sscanf(line,"diffuseColor %f,%f,%f[^\n] ",&r,&g,&b))!=3 &&
666
+ (err = std::sscanf(line,"diffuseColor %f %f %f[^\n] ",&r,&g,&b))!=3) {
667
+ if (!file)
668
+ cimg::fclose(nfile);
669
+ throw CImgIOException(_cimg_instance
670
+ "load_vrml() : wrong number of color furnished in file '%s'.",
671
+ cimg_instance,filename?filename:"(FILE*)");
672
+ }
673
+ }
674
+ else if(!cimg::strncasecmp(line,"texture ImageTexture",20)) { // If there is a texture defined in the VRML file
675
+ textureTest = true;
676
+ colorDefined = false;
677
+ while(cimg::strncasecmp(line,"url",3) && !std::feof(nfile))
678
+ err = std::fscanf(nfile,"%1023[^\n] ",line);
679
+ if(std::feof(nfile)) {
680
+ if (!file)
681
+ cimg::fclose(nfile);
682
+ throw CImgIOException(_cimg_instance
683
+ "load_vrml() : texture not defined in file '%s'.",
684
+ cimg_instance, filename?filename:"(FILE*)");
685
+ }
686
+ // We temporary put the name of the texture image into textureFileTemp
687
+ std::sscanf(line,"url [%s][^\n] ",textureFileTemp);
688
+ char * pch;
689
+ pch = std::strtok (textureFileTemp,"\"");
690
+ strcpy(textureFile,pch); // We put the url of the texture image into textureFile
691
+ }
692
+ }
693
+ else if(!cimg::strncasecmp(line,"Shape",5)) // We have another shape node
694
+ textureTest = false; // We reinitialize the texture boolean
695
+
696
+ if(nbPrimitives && colorDefined && !multipleColors && !textureTest) {
697
+ // If there is only one color defined we add it to the colors CImgList or if no color
698
+ // is defined for an object, we add the default color
699
+ CImgList<tc> colorsTemp;
700
+ colorsTemp.insert(nbPrimitives,CImg<tc>::vector((tc)(r*255),(tc)(g*255),(tc)(b*255)));
701
+ colors.push_back(colorsTemp);
702
+ nbPrimitives = 0;
703
+ r = 0.7f;
704
+ g = 0.7f;
705
+ b = 0.7f;
706
+ }
707
+ err = std::fscanf(nfile,"%1023[^\n] ",line);
708
+ }
709
+
710
+ assign(listePoints.size()/3,3);
711
+ cimg_forX(*this,l) { // We add the points coordinates to the calling object
712
+ (*this)(l,0) = (T)(listePoints.at(l*3));
713
+ (*this)(l,1) = (T)(listePoints.at(l*3 + 1));
714
+ (*this)(l,2) = (T)(listePoints.at(l*3 + 2));
715
+ }
716
+
717
+ if (!file)
718
+ cimg::fclose(nfile);
719
+
720
+ return *this;
721
+ }
722
+
723
+ //! Save VRML files.
724
+ template<typename tf, typename tc>
725
+ const CImg<T>& save_vrml(const char *const filename,const CImgList<tf>& primitives,
726
+ const CImgList<tc>& colors, const char *const texturefile = 0) const {
727
+ return _save_vrml(0,filename,primitives,colors,texturefile);
728
+ }
729
+
730
+ //! Save VRML files.
731
+ template<typename tf, typename tc>
732
+ const CImg<T>& save_vrml(std::FILE *const file,const CImgList<tf>& primitives,
733
+ const CImgList<tc>& colors, const char *const texturefile = 0) const {
734
+ return _save_vrml(file,0,primitives,colors,texturefile);
735
+ }
736
+
737
+ // Save VRML files (internal).
738
+ template<typename tf, typename tc>
739
+ const CImg<T>& _save_vrml(std::FILE *const file, const char *const filename, const CImgList<tf>& primitives,
740
+ const CImgList<tc>& colors, const char *const texturefile) const {
741
+
742
+ // Check that the user furnished a file to save the object and that the object is not empty.
743
+ if (!file && !filename)
744
+ throw CImgArgumentException(_cimg_instance
745
+ "save_vrml() : Specified filename is (null).",
746
+ cimg_instance);
747
+ if (is_empty())
748
+ throw CImgInstanceException(_cimg_instance
749
+ "save_vrml() : Empty instance, for file '%s'.",
750
+ cimg_instance,filename?filename:"(FILE*)");
751
+
752
+ // Check that the object we want to save is a 3D object.
753
+ CImgList<T> opacities;
754
+ char error_message[1024] = {0};
755
+ if (!is_object3d(primitives,colors,opacities,true,error_message))
756
+ throw CImgInstanceException(_cimg_instance
757
+ "save_vrml() : Invalid specified 3d object, for file '%s' (%s).",
758
+ cimg_instance,filename?filename:"(FILE*)",error_message);
759
+ const CImg<tc> default_color(1,3,1,1,200);
760
+
761
+ // We open the file in which we will save the 3D object.
762
+ std::FILE * nfile;
763
+ if(file) nfile = file;
764
+ else nfile = cimg::fopen(filename,"w");
765
+
766
+ // We use the version 2.0 of VRML to represent the object in UTF8
767
+ std::fprintf(nfile,"#VRML V2.0 utf8\n");
768
+
769
+ // We copy the coordinates of all the points
770
+ std::fprintf(nfile,"Shape {\n\tgeometry IndexedFaceSet {\n\t\tcoord Coordinate {\n\t\t\tpoint [\n");
771
+ cimg_forX(*this,i)
772
+ std::fprintf(nfile,"\t\t\t\t%f %f %f,\n",(float)((*this)(i,0)),(float)((*this)(i,1)),(float)((*this)(i,2)));
773
+ std::fprintf(nfile,"\t\t\t]\n\t\t}\n\t\tcoordIndex [\n");
774
+ bool sameColor = true;
775
+
776
+ float r = colors[0][0]/255.0f;
777
+ float g = colors[0][1]/255.0f;
778
+ float b = colors[0][2]/255.0f;
779
+
780
+ std::vector<std::string> listColor;
781
+ std::string listColorPerFace("");
782
+ for(int i=0;i<(int)colors.size();++i) {// Test if the object is composed of only one color
783
+ float valR = (colors[i][0])/255.0f;
784
+ float valG = (colors[i][1])/255.0f;
785
+ float valB = (colors[i][2])/255.0f;
786
+
787
+ if (r!=valR || g!=valG || b!=valB) { // If the object has different colors
788
+ sameColor = false;
789
+ i = colors.size();
790
+ }
791
+ }
792
+
793
+ cimglist_for(primitives,l) { // For each primitive
794
+ const CImg<tc>& color = l<colors.width()?colors[l]:default_color;
795
+ const unsigned int psiz = primitives[l].size(), csiz = color.size();
796
+ float r = color[0]/255.0f;
797
+ float g, b;
798
+ if (csiz > 1) g = color[1]/255.0f;
799
+ else g = r/255.0f;
800
+ if (csiz > 2) b = color[2]/255.0f;
801
+ else b = g/255.0f;
802
+
803
+ switch (psiz) {
804
+ case 1 :
805
+ std::fprintf(nfile,"\t\t\t%u,-1\n",(unsigned int)primitives(l,0));
806
+ break;
807
+ case 2 :
808
+ std::fprintf(nfile,"\t\t\t%u,%u,-1\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,1));
809
+ break;
810
+ case 3 :
811
+ std::fprintf(nfile,"\t\t\t%u,%u,%u,-1\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,2),
812
+ (unsigned int)primitives(l,1));
813
+ break;
814
+ case 4 :
815
+ std::fprintf(nfile,"\t\t\t%u,%u,%u,%u,-1\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,3),
816
+ (unsigned int)primitives(l,2),(unsigned int)primitives(l,1));
817
+ break;
818
+ case 6 : {
819
+ const unsigned int xt = (unsigned int)primitives(l,2), yt = (unsigned int)primitives(l,3);
820
+ r = color.atXY(xt,yt,0)/255.0f;
821
+ g = (csiz>1?color.atXY(xt,yt,1):r)/255.0f;
822
+ b = (csiz>2?color.atXY(xt,yt,2):g)/255.0f;
823
+ std::fprintf(nfile,"\t\t\t%u,%u,-1\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,1));
824
+ } break;
825
+ case 9 : {
826
+ const unsigned int xt = (unsigned int)primitives(l,3), yt = (unsigned int)primitives(l,4);
827
+ r = color.atXY(xt,yt,0)/255.0f;
828
+ g = (csiz>1?color.atXY(xt,yt,1):r)/255.0f;
829
+ b = (csiz>2?color.atXY(xt,yt,2):g)/255.0f;
830
+ std::fprintf(nfile,"\t\t\t%u,%u,%u,-1\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,2),
831
+ (unsigned int)primitives(l,1));
832
+ } break;
833
+ case 12 : {
834
+ const unsigned int xt = (unsigned int)primitives(l,4), yt = (unsigned int)primitives(l,5);
835
+ r = color.atXY(xt,yt,0)/255.0f;
836
+ g = (csiz>1?color.atXY(xt,yt,1):r)/255.0f;
837
+ b = (csiz>2?color.atXY(xt,yt,2):g)/255.0f;
838
+ std::fprintf(nfile,"\t\t\t%u,%u,%u,%u,-1\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,3),
839
+ (unsigned int)primitives(l,2),(unsigned int)primitives(l,1));
840
+ } break;
841
+ }
842
+ if (!sameColor) { // If there are different colors we store on every loop the RGB values into the vector listColor
843
+ std::ostringstream oss;
844
+ oss << r << " " << g << " " << b << "\n";
845
+ if (listColor.size() == 0) {
846
+ listColor.push_back(oss.str());
847
+ listColorPerFace += "0"; // We store the indice of the color
848
+ }
849
+ else {
850
+ std::vector<std::string>::iterator it;
851
+ it = find (listColor.begin(), listColor.end(), oss.str());
852
+ std::ostringstream oss2;
853
+ if(it==listColor.end()) {
854
+ oss2 << " " << listColor.size();
855
+ listColorPerFace += oss2.str();
856
+ listColor.push_back(oss.str());
857
+ }
858
+ else {
859
+ int n = 0;
860
+ for (std::vector<std::string>::iterator iter = listColor.begin(); iter != it; iter++) ++n;
861
+ oss2 << " " << n;
862
+ listColorPerFace += oss2.str();
863
+ }
864
+ }
865
+ }
866
+ }
867
+ std::fprintf(nfile,"\t\t]\n");
868
+
869
+ if (texturefile) // If we have a texture instead of a color
870
+ std::fprintf(nfile,"\n\t}\n\tappearance DEF theTexture Appearance "
871
+ "{\n\t\ttexture ImageTexture {\n\t\t\turl [\"%s\"]\n\t\t}\n\t}\n}",
872
+ texturefile);
873
+ else {
874
+ if(!sameColor) { // If there are different colors we add all of them
875
+ std::fprintf(nfile,"\tcolorPerVertex FALSE\n\tcolor Color {\n\t\tcolor [\n");
876
+ while(!listColor.empty()) {
877
+ std::fprintf(nfile,"\t\t\t%s",(listColor.back()).c_str());
878
+ listColor.pop_back();
879
+ }
880
+ std::fprintf(nfile,"\t\t]\n\t}\n\tcolorIndex [\n\t\t");
881
+ std::fprintf(nfile,"%s",listColorPerFace.c_str());
882
+ std::fprintf(nfile,"\n\t]\n\t}\n}");
883
+ }
884
+ else { // If there is only one color we add it with the Material node
885
+ std::fprintf(nfile,"\t}\n\tappearance Appearance "
886
+ "{\n\t\tmaterial Material {\n\t\t\tdiffuseColor %f,%f,%f\n\t\t}\n\t}\n}",
887
+ colors[0][0]/255.0f,colors[0][1]/255.0f,colors[0][2]/255.0f);
888
+ }
889
+ }
890
+ if (!file) cimg::fclose(nfile);
891
+ return *this;
892
+ }
893
+
894
+ #endif /* cimg_plugin_vrml */