ES-DE/external/CImg/plugins/vrml.h

895 lines
40 KiB
C
Raw Permalink Normal View History

/*
#
# File : vrml.h
# ( C++ header file - CImg plug-in )
#
# Description : CImg plugin that provide functions to load/save VRML files.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : Greg Rami
# ( greg.rami36 (at) gmail.com )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
/*-----------------------------------------------------------------------------------
IMPORTANT NOTE :
You *need* to include the following lines in your own code to use this plugin :
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>
------------------------------------------------------------------------------------*/
#ifndef cimg_plugin_vrml
#define cimg_plugin_vrml
//! Load a 3d object from a .VRML file.
template<typename tf, typename tc>
CImg<T>& load_vrml(const char *const filename, CImgList<tf>& primitives, CImgList<tc>& colors) {
return _load_vrml(0,filename,primitives,colors);
}
//! Load a 3d object from a .VRML file.
template<typename tf, typename tc>
static CImg<T> get_load_vrml(const char *const filename, CImgList<tf>& primitives, CImgList<tc>& colors) {
return CImg<T>().load_vrml(filename,primitives,colors);
}
//! Load a 3d object from a .VRML file.
template<typename tf, typename tc>
CImg<T>& load_vrml(std::FILE *const file, CImgList<tf>& primitives, CImgList<tc>& colors) {
return _load_vrml(file,0,primitives,colors);
}
//! Load a 3d object from a .VRML file.
template<typename tf, typename tc>
static CImg<T> get_load_vrml(std::FILE *const file, CImgList<tf>& primitives, CImgList<tc>& colors) {
return CImg<T>().load_vrml(file,primitives,colors);
}
//! Load a 3d object from a .VRML file (internal).
template<typename tf, typename tc>
CImg<T>& _load_vrml(std::FILE *const file, const char *const filename,CImgList<tf>& primitives, CImgList<tc>& colors) {
if (!file && !filename)
throw CImgArgumentException(_cimg_instance
"load_vrml() : Specified filename is (null).",
cimg_instance);
std::FILE *const nfile = file?file:cimg::fopen(filename,"r");
char line[1024] = { 0 };
int err;
// Skip comments, and read the first node.
do { err = std::fscanf(nfile,"%65535[^\n] ",line); } while (!err || (err==1 && *line=='#'));
// Check for a first valid vrml valid node.
if (cimg::strncasecmp(line,"Shape",5) &&
cimg::strncasecmp(line,"Transform",9) &&
cimg::strncasecmp(line,"NavigationInfo",14) &&
cimg::strncasecmp(line,"Billboard",9)) {
if (!file) cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : VRML nodes not found in file '%s'.",
cimg_instance,filename?filename:"(FILE*)");
}
// Look for the Shape node (as we do not manage the treatment for the other nodes yet).
if (cimg::strncasecmp(line,"Shape",5)) {
while (cimg::strncasecmp(line,"Shape",5) && !std::feof(nfile)) err = std::fscanf(nfile,"%1023[^\n] ",line);
if (std::feof(nfile)) {
if (!file) cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : Shape node not found in file '%s'.",
cimg_instance,filename?filename:"(FILE*)");
}
}
// Look for either geometry or appearance node.
while (cimg::strncasecmp(line,"geometry",8) && cimg::strncasecmp(line,"appearance",10) && !std::feof(nfile))
err = std::fscanf(nfile,"%1023[^\n] ",line);
if (std::feof(nfile)) { // If none of these nodes are defined.
if (!file) cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : Geometry and appearance nodes not found in file '%s'.",
cimg_instance,filename?filename:"(FILE*)");
}
std::vector<T> listePoints; // Intermediate list containing the points of the whole object.
primitives.assign();
colors.assign();
// Count the number of points of the whole object and the number of primitives.
int nbPointsTotal = 0, nbPrimitives = 0;
float r = 0.78f, g = 0.78f, b = 0.78f; // RGB level of the object, the object is gray by default.
// Boolean used to know if a color is defined for an object,
// if this object has multiple colors or if the object has a texture
bool colorDefined = true, multipleColors = false, textureTest = false;
char textureFile[1024] = { 0 }; // Variable containing the name of the image used as a texture
while (!std::feof(nfile)) {
char type[1024] = { 0 }, textureFileTemp[1024] = { 0 };
colorDefined = true;
if (!cimg::strncasecmp(line,"geometry",8)) { // We are at the geometry node
std::sscanf(line,"geometry %s",type); // We are looking for the type of geometry to draw
const CImg<float> coords = CImg<float>::empty(); // CImg used for the texturization of an object
CImgList<tc> colorsTextured; // CImgList used for the texturization of the color of an object
CImgList<tf> primitivesTemp; // Intermediate CImgList used to update the primitives of the whole object
if (!cimg::strncasecmp(type,"Box",3)) { // If the object to draw is a box
while (cimg::strncasecmp(line,"size",4) && !std::feof(nfile)) // We are looking for the size of the box
err = std::fscanf(nfile,"%1023[^\n] ",line);
if (std::feof(nfile)) { // If no size is specified
if (!file) cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : size of box not defined in file '%s'.",
cimg_instance, filename?filename:"(FILE*)");
}
float X = 0, Y = 0, Z = 0; // The width, height and depth of the box
if ((err = std::sscanf(line,"size %f %f %f[^\n] ",&X,&Y,&Z))!=3 &&
(err = std::sscanf(line,"size %f,%f,%f[^\n] ",&X,&Y,&Z))!=3) {
if (!file) cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : Failed to read box size in file '%s'.",
cimg_instance,filename?filename:"(FILE*)");
}
// We generate the primitives and the points of the box
const CImg<T> pointsTemp = CImg<T>::box3d(primitivesTemp,(T)X,(T)Y,(T)Z);
nbPrimitives = primitivesTemp.size(); // We save the number of primitives of the object
if (textureTest) { // If the object has a texture
// We put the image used as a texture into a CImg object
const CImg<float> texture(textureFile);
// We initialize the colorsTextured list
colorsTextured.insert(primitivesTemp.size(),CImg<unsigned char>::vector(0,50,250));
// We texturize the object
pointsTemp.texturize_object3d(primitivesTemp,colorsTextured,texture,coords);
nbPrimitives = 0;
}
if(nbPointsTotal) { // If there are already some objects in the scene
for (int j=0;j<(int)primitivesTemp.size();j++) {
for(int i=0;i<4;i++)
// We shift the indices in the primitives to designate the right points
primitivesTemp(j).at(i) += (tf)nbPointsTotal;
}
}
primitives.push_back(primitivesTemp); // We add the primitives of the box to the general primitives variable
for(int i=0;i<(int)pointsTemp.size()/3;++i) { // We add the points into the temporary list in the right order
listePoints.push_back((T)pointsTemp.at(i));
listePoints.push_back((T)pointsTemp.at(i + 8));
listePoints.push_back((T)pointsTemp.at(i + 16));
}
nbPointsTotal += pointsTemp.size()/3; // We increase the number of points of the whole object
}
else if(!cimg::strncasecmp(type,"Sphere",6)) { // If the object to draw is a sphere
while(cimg::strncasecmp(line,"radius",6) && !std::feof(nfile))
err = std::fscanf(nfile,"%1023[^\n] ",line);
if(std::feof(nfile)) {
if (!file)
cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : radius of sphere not defined in file '%s'.",
cimg_instance, filename?filename:"(FILE*)");
}
float R = 0;
if ((err = std::sscanf(line,"radius %f[^\n] ",&R))!=1) { // We get the radius of the sphere
if (!file)
cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : Failed to read sphere radius in file '%s'.",
cimg_instance,filename?filename:"(FILE*)");
}
// Compute the necessary points and primitives for a sphere of radius R
const CImg<T> pointsTemp = CImg<T>::sphere3d(primitivesTemp,(T)R);
// We get the number of primitives to used on the attribution of a color, in case no specific color is defined
nbPrimitives = primitivesTemp.size();
if(textureTest) { // If the object has a texture
// We put the image used as a texture into a CImg object
const CImg<float> texture(textureFile);
// We initialize the colorsTextured list
colorsTextured.insert(primitivesTemp.size(),CImg<unsigned char>::vector(0,50,250));
pointsTemp.texturize_object3d(primitivesTemp,colorsTextured,texture,coords); // We texturize the object
nbPrimitives = 0; // We set to 0 because there is no color to use
}
if(nbPointsTotal) { // If there are already some objects in the scene
for (int j=0;j<(int)primitivesTemp.size();j++) {
for(int i=0;i<3;i++)
primitivesTemp(j).at(i) += (tf)nbPointsTotal;
}
}
primitives.push_back(primitivesTemp);
for(int i=0;i<(int)pointsTemp.size()/3;++i) {
listePoints.push_back((T)pointsTemp.at(i));
listePoints.push_back((T)pointsTemp.at(i + pointsTemp.size()/3));
listePoints.push_back((T)pointsTemp.at(i + 2*pointsTemp.size()/3));
}
nbPointsTotal += pointsTemp.size()/3;
}
else if(!cimg::strncasecmp(type,"Cone",4)) { // If the object to draw is a cone
while(cimg::strncasecmp(line,"bottomRadius",12) && !std::feof(nfile) && cimg::strncasecmp(line,"height",6))
err = std::fscanf(nfile,"%1023[^\n] ",line);
float R = 0, H = 0;
if(std::feof(nfile)) {
if (!file)
cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : bottom radius and height of cone not defined in file '%s'.",
cimg_instance, filename?filename:"(FILE*)");
}
else if(!cimg::strncasecmp(line,"bottomRadius",12)) { // We find the bottom radius of the cone first
if ((err = std::sscanf(line,"bottomRadius %f[^\n] ",&R))!=1) { // We get the radius into the variable R
if (!file)
cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : Failed to read cone bottomRadius in file '%s'.",
cimg_instance,filename?filename:"(FILE*)");
}
while(!std::feof(nfile) && cimg::strncasecmp(line,"height",6)) // We look for the height of the cone
err = std::fscanf(nfile,"%1023[^\n] ",line);
if(std::feof(nfile)) {
if (!file)
cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : height of cone not defined in file '%s'.",
cimg_instance, filename?filename:"(FILE*)");
}
if ((err = std::sscanf(line,"height %f[^\n] ",&H))!=1) { // We get the height into the variable H
if (!file)
cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : Failed to read cone height in file '%s'.",
cimg_instance,filename?filename:"(FILE*)");
}
}
else { // We find the height of the cone first
if ((err = std::sscanf(line,"height %f[^\n] ",&H))!=1) {
if (!file)
cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : Failed to read cone height in file '%s'.",
cimg_instance,filename?filename:"(FILE*)");
}
while(!std::feof(nfile) && cimg::strncasecmp(line,"bottomRadius",12))
err = std::fscanf(nfile,"%1023[^\n] ",line);
if(std::feof(nfile)) {
if (!file)
cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : bottom radius of cone not defined in file '%s'.",
cimg_instance, filename?filename:"(FILE*)");
}
if ((err = std::sscanf(line,"bottomRadius %f[^\n] ",&R))!=1) {
if (!file)
cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : Failed to read cone bottom radius in file '%s'.",
cimg_instance,filename?filename:"(FILE*)");
}
}
// Compute the necessary points and primitives for a cone of radius R and height H
const CImg<T> pointsTemp = CImg<T>::cone3d(primitivesTemp,(T)R,(T)H);
nbPrimitives = primitivesTemp.size();
if(textureTest) { // If the object has a texture
// We put the image used as a texture into a CImg object
const CImg<float> texture(textureFile);
// We initialize the colorsTextured list
colorsTextured.insert(primitivesTemp.size(),CImg<unsigned char>::vector(0,50,250));
pointsTemp.texturize_object3d(primitivesTemp,colorsTextured,texture,coords); // We texturize the object
nbPrimitives = 0;
}
if(nbPointsTotal) {
for (int j=0;j<(int)primitivesTemp.size();j++) {
for(int i=0;i<3;i++)
primitivesTemp(j).at(i) += (tf)nbPointsTotal;
}
}
primitives.push_back(primitivesTemp);
for(int i=0;i<(int)pointsTemp.size()/3;++i) {
listePoints.push_back((T)pointsTemp.at(i));
listePoints.push_back((T)pointsTemp.at(i + pointsTemp.size()/3));
listePoints.push_back((T)pointsTemp.at(i + 2*pointsTemp.size()/3));
}
nbPointsTotal += pointsTemp.size()/3;
}
else if(!cimg::strncasecmp(type,"Cylinder",8)) { // If the object to draw is a cylinder
while(cimg::strncasecmp(line,"radius",6) && !std::feof(nfile) && cimg::strncasecmp(line,"height",6))
err = std::fscanf(nfile,"%1023[^\n] ",line);
float R = 0, H = 0;
if(std::feof(nfile)) {
if (!file)
cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : radius or height of cylinder not defined in file '%s'.",
cimg_instance, filename?filename:"(FILE*)");
}
else if(!cimg::strncasecmp(line,"radius",6)) { // If we find the radius first
if ((err = std::sscanf(line,"radius %f[^\n] ",&R))!=1) {
if (!file)
cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : Failed to read cylinder radius in file '%s'.",
cimg_instance,filename?filename:"(FILE*)");
}
while(!std::feof(nfile) && cimg::strncasecmp(line,"height",6)) // We now look for the height of the cylinder
err = std::fscanf(nfile,"%1023[^\n] ",line);
if(std::feof(nfile)) {
if (!file)
cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : height of cylinder not defined in file '%s'.",
cimg_instance, filename?filename:"(FILE*)");
}
if ((err = std::sscanf(line,"height %f[^\n] ",&H))!=1) {
if (!file)
cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : Failed to read cylinder height in file '%s'.",
cimg_instance,filename?filename:"(FILE*)");
}
}
else { // If we find the height first
if ((err = std::sscanf(line,"height %f[^\n] ",&H))!=1) {
if (!file)
cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : Failed to read cylinder height in file '%s'.",
cimg_instance,filename?filename:"(FILE*)");
}
while(!std::feof(nfile) && cimg::strncasecmp(line,"radius",6))// We now look for the radius of the cylinder
err = std::fscanf(nfile,"%1023[^\n] ",line);
if(std::feof(nfile)) {
if (!file)
cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : radius of cylinder not defined in file '%s'.",
cimg_instance, filename?filename:"(FILE*)");
}
if ((err = std::sscanf(line,"radius %f[^\n] ",&R))!=1) {
if (!file)
cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : Failed to read cylinder radius in file '%s'.",
cimg_instance,filename?filename:"(FILE*)");
}
}
// Compute the necessary points and primitives for a cylinder of radius R and height H
const CImg<T> pointsTemp = CImg<T>::cylinder3d(primitivesTemp,(T)R,(T)H);
if(textureTest) { // If the object has a texture
// We put the image used as a texture into a CImg object
const CImg<float> texture(textureFile);
// We initialize the colorsTextured list
colorsTextured.insert(primitivesTemp.size(),CImg<unsigned char>::vector(0,50,250));
pointsTemp.texturize_object3d(primitivesTemp,colorsTextured,texture,coords); // We texturize the object
nbPrimitives = 0;
}
nbPrimitives = primitivesTemp.size();
if(nbPointsTotal) {
for (int j=0;j<(int)primitivesTemp.size();j++) {
for(int i=0;i<3;i++)
primitivesTemp(j).at(i) += (tf)nbPointsTotal;
}
}
primitives.push_back(primitivesTemp);
for(int i=0;i<(int)pointsTemp.size()/3;++i) {
listePoints.push_back((T)pointsTemp.at(i));
listePoints.push_back((T)pointsTemp.at(i + pointsTemp.size()/3));
listePoints.push_back((T)pointsTemp.at(i + 2*pointsTemp.size()/3));
}
nbPointsTotal += pointsTemp.size()/3;
}
else if(!cimg::strncasecmp(type,"PointSet",8)) { // If the object to draw is a set of points
while(cimg::strncasecmp(line,"point [",7) && !std::feof(nfile))
err = std::fscanf(nfile,"%1023[^\n] ",line);
if(std::feof(nfile)) {
if (!file)
cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : points of pointSet node not defined in file '%s'.",
cimg_instance, filename?filename:"(FILE*)");
}
err = std::fscanf(nfile,"%1023[^\n] ",line);
int nbPoints = 0;
while(cimg::strncasecmp(line,"]",1) && !std::feof(nfile)) {
// while we did not get all the points and while we are not at the end of the file
float X = 0, Y = 0, Z = 0;
if ((err = std::sscanf(line,"%f %f %f,[^\n] ",&X,&Y,&Z))==3 ||
(err = std::sscanf(line,"%f,%f,%f,[^\n] ",&X,&Y,&Z))==3) {
// We get the coordinates of all the points and store them into a list of points
listePoints.push_back((T)X);
listePoints.push_back((T)Y);
listePoints.push_back((T)Z);
++nbPoints;
}
err = std::fscanf(nfile,"%1023[^\n] ",line);
}
if(std::feof(nfile)) {
if (!file)
cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : bad structure of pointSet node in file '%s'.",
cimg_instance, filename?filename:"(FILE*)");
}
primitivesTemp.assign();
for(int i=0;i<nbPoints;++i) { // The primitive is only composed of the indice of the point itself
CImg<tf> temp(1,1,1,1,(tf)i);
primitivesTemp.push_back(temp);
}
if(nbPointsTotal) {
for (int j=0;j<(int)primitivesTemp.size();j++) {
for(int i=0;i<(int)primitivesTemp(j).size();i++)
primitivesTemp(j).at(i) += (tf)nbPointsTotal;
}
}
nbPrimitives = primitivesTemp.size();
primitives.push_back(primitivesTemp);
nbPointsTotal += nbPoints;
}
else if(!cimg::strncasecmp(type,"IndexedLineSet",14) ||
!cimg::strncasecmp(type,"IndexedFaceSet",14)) {
// If the object to draw is a set of lines or a set of faces
while(cimg::strncasecmp(line,"point [",7) && !std::feof(nfile))
err = std::fscanf(nfile,"%1023[^\n] ",line);
if(std::feof(nfile)) {
if (!file)
cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : points of IndexedSet node not defined in file '%s'.",
cimg_instance, filename?filename:"(FILE*)");
}
err = std::fscanf(nfile,"%1023[^\n] ",line);
int nbPoints = 0;
while(cimg::strncasecmp(line,"]",1) && !std::feof(nfile)) {
// As long as there are points defined we add them to the list
float X=0,Y=0,Z=0;
if ((err = std::sscanf(line,"%f %f %f,[^\n] ",&X,&Y,&Z))==3 ||
(err = std::sscanf(line,"%f,%f,%f,[^\n] ",&X,&Y,&Z))==3) {
// We get the coordinates of the points into a list of points
listePoints.push_back((T)X);
listePoints.push_back((T)Y);
listePoints.push_back((T)Z);
++nbPoints;
}
err = std::fscanf(nfile,"%1023[^\n] ",line);
}
if(std::feof(nfile)) {
if (!file)
cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : bad structure of point vector node in file '%s'.",
cimg_instance, filename?filename:"(FILE*)");
}
primitivesTemp.assign();
while(cimg::strncasecmp(line,"coordIndex [",12) && !std::feof(nfile))
// We are looking for the index of the points
err = std::fscanf(nfile,"%1023[^\n] ",line);
if(std::feof(nfile)) {
if (!file)
cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : coordIndex not furnished for IndexedSet node in file '%s'.",
cimg_instance, filename?filename:"(FILE*)");
}
err = std::fscanf(nfile,"%1023[^\n] ",line);
while(cimg::strncasecmp(line,"]",1) && !std::feof(nfile)) { // As long as there are indices
if(*line!='#') {
std::vector<tf> primitiveComponents;
char * pch;
pch = std::strtok (line,",");
while (pch != NULL && std::atof(pch)!=-1) { // We extract the list of indices and store them into a vector
if(!(int)count(primitiveComponents.begin(),primitiveComponents.end(),(tf)std::atof(pch)))
primitiveComponents.push_back((tf)std::atof(pch));
pch = std::strtok (NULL, ",");
}
CImg<tf> temp(1,primitiveComponents.size(),1,1);
for(int i=0;i<(int)primitiveComponents.size();++i)
temp(0,i) = primitiveComponents.at(i);
primitivesTemp.push_back(temp);
}
err = std::fscanf(nfile,"%1023[^\n] ",line);
}
if(std::feof(nfile)) {
if (!file)
cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : bad structure of coordIndex in file '%s'.",
cimg_instance, filename?filename:"(FILE*)");
}
if(nbPointsTotal) {
for (int j=0;j<(int)primitivesTemp.size();j++) {
for(int i=0;i<(int)primitivesTemp(j).size();i++)
primitivesTemp(j).at(i) += (tf)nbPointsTotal;
}
}
nbPrimitives = primitivesTemp.size();
primitives.push_back(primitivesTemp);
nbPointsTotal += nbPoints;
while(cimg::strncasecmp(line,"color [",7) && cimg::strncasecmp(line,"}",1) && !std::feof(nfile))
err = std::fscanf(nfile,"%1023[^\n] ",line);
if(std::feof(nfile)) {
if (!file)
cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : bad structure of coordIndex in file '%s'.",
cimg_instance, filename?filename:"(FILE*)");
}
else if(!cimg::strncasecmp(line,"color [",7)) { // If there are different colors defined for each faces
multipleColors = true;
std::vector<CImg<tc> > listColors;
err = std::fscanf(nfile,"%1023[^\n] ",line);
while(cimg::strncasecmp(line,"]",1) && !std::feof(nfile)) {
// We add the list of all colors defined into the vector listColors
if(*line!='#') {
if ((err = std::sscanf(line,"%f %f %f[^\n] ",&r,&g,&b))!=3) {
if (!file)
cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : wrong number of color furnished in file '%s'.",
cimg_instance,filename?filename:"(FILE*)");
}
CImg<tc> img(3,1,1,1,(tc)(r*255),(tc)(g*255),(tc)(b*255));
listColors.push_back(img);
}
err = std::fscanf(nfile,"%1023[^\n] ",line);
}
if(std::feof(nfile)) {
if (!file)
cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : bad structure of color in file '%s'.",
cimg_instance, filename?filename:"(FILE*)");
}
else {
while(cimg::strncasecmp(line,"colorIndex [",12) && !std::feof(nfile))
err = std::fscanf(nfile,"%1023[^\n] ",line);
if(std::feof(nfile)) {
if (!file)
cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : colorIndex not furnished for Color node in file '%s'.",
cimg_instance, filename?filename:"(FILE*)");
}
err = std::fscanf(nfile,"%1023[^\n] ",line);
while(cimg::strncasecmp(line,"]",1) && !std::feof(nfile)) {
// We add the colors at the right index into the vector colors
if(*line!='#') {
char * pch;
pch = std::strtok (line," ");
while (pch != NULL) {
int indice = std::atoi(pch);
colors.insert(CImg<tc>::vector((tc)(listColors[indice])[0],
(tc)(listColors[indice])[1],
(tc)(listColors[indice])[2]));
pch = std::strtok (NULL, " ");
}
}
err = std::fscanf(nfile,"%1023[^\n] ",line);
}
}
}
}
else // If none of the known type of shape is defined
cimg::warn(_cimg_instance
"load_vrml() : Failed to read type of geometry to draw from file '%s'.",
cimg_instance,filename?filename:"(FILE*)");
if(textureTest) { // If the object considered is texturized
colors.push_back(colorsTextured);
*textureFile = 0;
}
while(cimg::strncasecmp(line,"appearance",10) &&
cimg::strncasecmp(line,"Shape",5) && !std::feof(nfile))
// We look for the node appearance or for another shape
err = std::fscanf(nfile,"%1023[^\n] ",line);
}
if(!cimg::strncasecmp(line,"appearance",10)) { // We are at the appearance node
while(cimg::strncasecmp(line,"texture ImageTexture",20) &&
cimg::strncasecmp(line,"diffuseColor",12) && !std::feof(nfile))
// We are looking for a valid appearance node
err = std::fscanf(nfile,"%1023[^\n] ",line);
if(!cimg::strncasecmp(line,"diffuseColor",12)) { // If the object as a unique diffuse color
if ((err = std::sscanf(line,"diffuseColor %f,%f,%f[^\n] ",&r,&g,&b))!=3 &&
(err = std::sscanf(line,"diffuseColor %f %f %f[^\n] ",&r,&g,&b))!=3) {
if (!file)
cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : wrong number of color furnished in file '%s'.",
cimg_instance,filename?filename:"(FILE*)");
}
}
else if(!cimg::strncasecmp(line,"texture ImageTexture",20)) { // If there is a texture defined in the VRML file
textureTest = true;
colorDefined = false;
while(cimg::strncasecmp(line,"url",3) && !std::feof(nfile))
err = std::fscanf(nfile,"%1023[^\n] ",line);
if(std::feof(nfile)) {
if (!file)
cimg::fclose(nfile);
throw CImgIOException(_cimg_instance
"load_vrml() : texture not defined in file '%s'.",
cimg_instance, filename?filename:"(FILE*)");
}
// We temporary put the name of the texture image into textureFileTemp
std::sscanf(line,"url [%s][^\n] ",textureFileTemp);
char * pch;
pch = std::strtok (textureFileTemp,"\"");
strcpy(textureFile,pch); // We put the url of the texture image into textureFile
}
}
else if(!cimg::strncasecmp(line,"Shape",5)) // We have another shape node
textureTest = false; // We reinitialize the texture boolean
if(nbPrimitives && colorDefined && !multipleColors && !textureTest) {
// If there is only one color defined we add it to the colors CImgList or if no color
// is defined for an object, we add the default color
CImgList<tc> colorsTemp;
colorsTemp.insert(nbPrimitives,CImg<tc>::vector((tc)(r*255),(tc)(g*255),(tc)(b*255)));
colors.push_back(colorsTemp);
nbPrimitives = 0;
r = 0.7f;
g = 0.7f;
b = 0.7f;
}
err = std::fscanf(nfile,"%1023[^\n] ",line);
}
assign(listePoints.size()/3,3);
cimg_forX(*this,l) { // We add the points coordinates to the calling object
(*this)(l,0) = (T)(listePoints.at(l*3));
(*this)(l,1) = (T)(listePoints.at(l*3 + 1));
(*this)(l,2) = (T)(listePoints.at(l*3 + 2));
}
if (!file)
cimg::fclose(nfile);
return *this;
}
//! Save VRML files.
template<typename tf, typename tc>
const CImg<T>& save_vrml(const char *const filename,const CImgList<tf>& primitives,
const CImgList<tc>& colors, const char *const texturefile = 0) const {
return _save_vrml(0,filename,primitives,colors,texturefile);
}
//! Save VRML files.
template<typename tf, typename tc>
const CImg<T>& save_vrml(std::FILE *const file,const CImgList<tf>& primitives,
const CImgList<tc>& colors, const char *const texturefile = 0) const {
return _save_vrml(file,0,primitives,colors,texturefile);
}
// Save VRML files (internal).
template<typename tf, typename tc>
const CImg<T>& _save_vrml(std::FILE *const file, const char *const filename, const CImgList<tf>& primitives,
const CImgList<tc>& colors, const char *const texturefile) const {
// Check that the user furnished a file to save the object and that the object is not empty.
if (!file && !filename)
throw CImgArgumentException(_cimg_instance
"save_vrml() : Specified filename is (null).",
cimg_instance);
if (is_empty())
throw CImgInstanceException(_cimg_instance
"save_vrml() : Empty instance, for file '%s'.",
cimg_instance,filename?filename:"(FILE*)");
// Check that the object we want to save is a 3D object.
CImgList<T> opacities;
char error_message[1024] = {0};
if (!is_object3d(primitives,colors,opacities,true,error_message))
throw CImgInstanceException(_cimg_instance
"save_vrml() : Invalid specified 3d object, for file '%s' (%s).",
cimg_instance,filename?filename:"(FILE*)",error_message);
const CImg<tc> default_color(1,3,1,1,200);
// We open the file in which we will save the 3D object.
std::FILE * nfile;
if(file) nfile = file;
else nfile = cimg::fopen(filename,"w");
// We use the version 2.0 of VRML to represent the object in UTF8
std::fprintf(nfile,"#VRML V2.0 utf8\n");
// We copy the coordinates of all the points
std::fprintf(nfile,"Shape {\n\tgeometry IndexedFaceSet {\n\t\tcoord Coordinate {\n\t\t\tpoint [\n");
cimg_forX(*this,i)
std::fprintf(nfile,"\t\t\t\t%f %f %f,\n",(float)((*this)(i,0)),(float)((*this)(i,1)),(float)((*this)(i,2)));
std::fprintf(nfile,"\t\t\t]\n\t\t}\n\t\tcoordIndex [\n");
bool sameColor = true;
float r = colors[0][0]/255.0f;
float g = colors[0][1]/255.0f;
float b = colors[0][2]/255.0f;
std::vector<std::string> listColor;
std::string listColorPerFace("");
for(int i=0;i<(int)colors.size();++i) {// Test if the object is composed of only one color
float valR = (colors[i][0])/255.0f;
float valG = (colors[i][1])/255.0f;
float valB = (colors[i][2])/255.0f;
if (r!=valR || g!=valG || b!=valB) { // If the object has different colors
sameColor = false;
i = colors.size();
}
}
cimglist_for(primitives,l) { // For each primitive
const CImg<tc>& color = l<colors.width()?colors[l]:default_color;
const unsigned int psiz = primitives[l].size(), csiz = color.size();
float r = color[0]/255.0f;
float g, b;
if (csiz > 1) g = color[1]/255.0f;
else g = r/255.0f;
if (csiz > 2) b = color[2]/255.0f;
else b = g/255.0f;
switch (psiz) {
case 1 :
std::fprintf(nfile,"\t\t\t%u,-1\n",(unsigned int)primitives(l,0));
break;
case 2 :
std::fprintf(nfile,"\t\t\t%u,%u,-1\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,1));
break;
case 3 :
std::fprintf(nfile,"\t\t\t%u,%u,%u,-1\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,2),
(unsigned int)primitives(l,1));
break;
case 4 :
std::fprintf(nfile,"\t\t\t%u,%u,%u,%u,-1\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,3),
(unsigned int)primitives(l,2),(unsigned int)primitives(l,1));
break;
case 6 : {
const unsigned int xt = (unsigned int)primitives(l,2), yt = (unsigned int)primitives(l,3);
r = color.atXY(xt,yt,0)/255.0f;
g = (csiz>1?color.atXY(xt,yt,1):r)/255.0f;
b = (csiz>2?color.atXY(xt,yt,2):g)/255.0f;
std::fprintf(nfile,"\t\t\t%u,%u,-1\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,1));
} break;
case 9 : {
const unsigned int xt = (unsigned int)primitives(l,3), yt = (unsigned int)primitives(l,4);
r = color.atXY(xt,yt,0)/255.0f;
g = (csiz>1?color.atXY(xt,yt,1):r)/255.0f;
b = (csiz>2?color.atXY(xt,yt,2):g)/255.0f;
std::fprintf(nfile,"\t\t\t%u,%u,%u,-1\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,2),
(unsigned int)primitives(l,1));
} break;
case 12 : {
const unsigned int xt = (unsigned int)primitives(l,4), yt = (unsigned int)primitives(l,5);
r = color.atXY(xt,yt,0)/255.0f;
g = (csiz>1?color.atXY(xt,yt,1):r)/255.0f;
b = (csiz>2?color.atXY(xt,yt,2):g)/255.0f;
std::fprintf(nfile,"\t\t\t%u,%u,%u,%u,-1\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,3),
(unsigned int)primitives(l,2),(unsigned int)primitives(l,1));
} break;
}
if (!sameColor) { // If there are different colors we store on every loop the RGB values into the vector listColor
std::ostringstream oss;
oss << r << " " << g << " " << b << "\n";
if (listColor.size() == 0) {
listColor.push_back(oss.str());
listColorPerFace += "0"; // We store the indice of the color
}
else {
std::vector<std::string>::iterator it;
it = find (listColor.begin(), listColor.end(), oss.str());
std::ostringstream oss2;
if(it==listColor.end()) {
oss2 << " " << listColor.size();
listColorPerFace += oss2.str();
listColor.push_back(oss.str());
}
else {
int n = 0;
for (std::vector<std::string>::iterator iter = listColor.begin(); iter != it; iter++) ++n;
oss2 << " " << n;
listColorPerFace += oss2.str();
}
}
}
}
std::fprintf(nfile,"\t\t]\n");
if (texturefile) // If we have a texture instead of a color
std::fprintf(nfile,"\n\t}\n\tappearance DEF theTexture Appearance "
"{\n\t\ttexture ImageTexture {\n\t\t\turl [\"%s\"]\n\t\t}\n\t}\n}",
texturefile);
else {
if(!sameColor) { // If there are different colors we add all of them
std::fprintf(nfile,"\tcolorPerVertex FALSE\n\tcolor Color {\n\t\tcolor [\n");
while(!listColor.empty()) {
std::fprintf(nfile,"\t\t\t%s",(listColor.back()).c_str());
listColor.pop_back();
}
std::fprintf(nfile,"\t\t]\n\t}\n\tcolorIndex [\n\t\t");
std::fprintf(nfile,"%s",listColorPerFace.c_str());
std::fprintf(nfile,"\n\t]\n\t}\n}");
}
else { // If there is only one color we add it with the Material node
std::fprintf(nfile,"\t}\n\tappearance Appearance "
"{\n\t\tmaterial Material {\n\t\t\tdiffuseColor %f,%f,%f\n\t\t}\n\t}\n}",
colors[0][0]/255.0f,colors[0][1]/255.0f,colors[0][2]/255.0f);
}
}
if (!file) cimg::fclose(nfile);
return *this;
}
#endif /* cimg_plugin_vrml */