From 2cbd4b7964b06f25086b7f987ace108d0930978d Mon Sep 17 00:00:00 2001 From: cignoni Date: Tue, 27 Nov 2012 07:05:38 +0000 Subject: [PATCH] Added support for the color support in STL files (both the SolidView and the Magics 'standard'). --- vcg/space/color4.h | 57 +++++++++++++++++++++- wrap/io_trimesh/export_stl.h | 28 +++++++---- wrap/io_trimesh/import_stl.h | 92 ++++++++++++++++++++++++++++-------- 3 files changed, 148 insertions(+), 29 deletions(-) diff --git a/vcg/space/color4.h b/vcg/space/color4.h index a2b424de..a26703aa 100644 --- a/vcg/space/color4.h +++ b/vcg/space/color4.h @@ -226,7 +226,20 @@ inline static Color4 ColorRamp(const float &minf,const float &maxf ,float v ) rc.SetColorRamp(minf,maxf,v); return rc; } -}; + +inline static unsigned short ToUnsignedB5G5R5(Color4 &) { return 0;} +inline static unsigned short ToUnsignedR5G5B5(Color4 &) { return 0;} + +inline static Color4 FromUnsignedB5G5R5(unsigned short) +{ + return Color4(Color4::White); +} +inline static Color4 FromUnsignedR5G5B5(unsigned short) +{ + return Color4(Color4::White); +} + +}; /// END CLASS /////////////////// template <> template <> inline void Color4::Import(const Color4 &b) @@ -312,6 +325,48 @@ typedef Color4 Color4b; typedef Color4 Color4f; typedef Color4 Color4d; + +template<> +inline unsigned short Color4::ToUnsignedB5G5R5(Color4 &cc) +{ + unsigned short r = cc[0]/8; + unsigned short g = cc[1]/8; + unsigned short b = cc[2]/8; + unsigned short res = b + g*32 + r*1024; + return res; +} + +template<> +inline unsigned short Color4::ToUnsignedR5G5B5(Color4 &cc) +{ + unsigned short r = cc[0]/8; + unsigned short g = cc[1]/8; + unsigned short b = cc[2]/8; + unsigned short res = r + g*32 + b*1024; + return res; +} + + +template<> +inline Color4 Color4::FromUnsignedR5G5B5(unsigned short val) +{ + unsigned short r = val % 32 *8; + unsigned short g = ((val/32)%32)*8; + unsigned short b = ((val/1024)%32)*8; + Color4b cc((unsigned char)r,(unsigned char)g,(unsigned char)b,(unsigned char)255); + return cc; +} + +template<> +inline Color4 Color4::FromUnsignedB5G5R5(unsigned short val) +{ + unsigned short b = val % 32 *8; + unsigned short g = ((val/32)%32)*8; + unsigned short r = ((val/1024)%32)*8; + Color4b cc((unsigned char)r,(unsigned char)g,(unsigned char)b,(unsigned char)255); + return cc; +} + /*@}*/ diff --git a/wrap/io_trimesh/export_stl.h b/wrap/io_trimesh/export_stl.h index 63084528..31d2f059 100644 --- a/wrap/io_trimesh/export_stl.h +++ b/wrap/io_trimesh/export_stl.h @@ -75,12 +75,12 @@ public: typedef typename SaveMeshType::FaceType FaceType; typedef unsigned short CallBackSTLFaceAttribute(const SaveMeshType &m, const FaceType &f); -static int Save(SaveMeshType &m, const char * filename, const int &/*mask*/, CallBackPos *) +static int Save(SaveMeshType &m, const char * filename, const int &mask, CallBackPos *) { - return Save(m,filename,true); + return Save(m,filename,true,mask); } -static int Save(SaveMeshType &m, const char * filename , bool binary =true, const char *objectname=0, CallBackSTLFaceAttribute *faceAttributeCallback = NULL) +static int Save(SaveMeshType &m, const char * filename , bool binary =true, int mask=0, const char *objectname=0, bool magicsMode=0) { typedef typename SaveMeshType::FaceIterator FaceIterator; FILE *fp; @@ -94,14 +94,23 @@ static int Save(SaveMeshType &m, const char * filename , bool binary =true, cons // Write Header char header[128]="VCG "; if(objectname) strncpy(header,objectname,80); + if(magicsMode) + { + strncpy(header,"COLOR=XXX MATERIAL=AAA BBB CCC ",80); + for(int i=0;i<3;++i) + { + header[0x06+i]=0x7f; + header[0x13+i]=0x7f; + header[0x17+i]=0x7f; + header[0x1b+i]=0x7f; + } + } fwrite(header,80,1,fp); // write number of facets fwrite(&m.fn,1,sizeof(int),fp); Point3f p; unsigned short attributes=0; - - FaceIterator fi; - for(fi=m.face.begin(); fi!=m.face.end(); ++fi) if( !(*fi).IsD() ) + for(FaceIterator fi=m.face.begin(); fi!=m.face.end(); ++fi) if( !(*fi).IsD() ) { // For each triangle write the normal, the three coords and a short set to zero p.Import(vcg::NormalizedNormal(*fi)); @@ -111,8 +120,10 @@ static int Save(SaveMeshType &m, const char * filename , bool binary =true, cons p.Import((*fi).V(k)->P()); fwrite(p.V(),3,sizeof(float),fp); } - if (faceAttributeCallback != NULL) { - attributes = (*faceAttributeCallback)(m, *fi); + if ((mask & Mask::IOM_FACECOLOR) && tri::HasPerFaceColor(m)) + { + if(magicsMode) attributes = 32768 | vcg::Color4b::ToUnsignedR5G5B5(fi->C()); + else attributes = 32768 | vcg::Color4b::ToUnsignedB5G5R5(fi->C()); } fwrite(&attributes,1,sizeof(short),fp); } @@ -164,6 +175,7 @@ static int GetExportMaskCapability() int capability = 0; capability |= vcg::tri::io::Mask::IOM_VERTCOORD; capability |= vcg::tri::io::Mask::IOM_FACEINDEX; + capability |= vcg::tri::io::Mask::IOM_FACECOLOR; return capability; } diff --git a/wrap/io_trimesh/import_stl.h b/wrap/io_trimesh/import_stl.h index c25f8942..f82cd4da 100644 --- a/wrap/io_trimesh/import_stl.h +++ b/wrap/io_trimesh/import_stl.h @@ -25,6 +25,7 @@ #define __VCGLIB_IMPORT_STL #include #include +#include namespace vcg { namespace tri { @@ -79,28 +80,59 @@ static const char *ErrorMsg(int error) else return stl_error_msg[error]; }; -static bool LoadMask(const char * /*filename*/, int &mask) +static bool LoadMask(const char * filename, int &mask) { + bool magicMode; mask = Mask::IOM_VERTCOORD | Mask::IOM_FACEINDEX; + if(IsSTLColored(filename,magicMode)) + mask |= Mask::IOM_FACECOLOR; return true; } -static int Open(OpenMeshType &mesh, const char *filename, int &loadmask, CallBackPos *cb=0) +/* Try to guess if a stl has color + * + * rules: + * - It has to be binary + * - The per face attribute should be not zero + * + */ +static bool IsSTLColored(const char * filename, bool &magicsMode) { - loadmask = Mask::IOM_VERTCOORD | Mask::IOM_FACEINDEX; - return Open(mesh,filename,cb); + if(IsSTLBinary(filename)==false) return false; + FILE *fp = fopen(filename, "r"); + char buf[STL_LABEL_SIZE+1]; + fread(buf,sizeof(char),STL_LABEL_SIZE,fp); + std::string strInput(buf); + size_t cInd = strInput.rfind("COLOR="); + size_t mInd = strInput.rfind("MATERIAL="); + if(cInd!=std::string::npos && mInd!=std::string::npos) + magicsMode = true; + else + magicsMode = false; + int facenum; + fread(&facenum, sizeof(int), 1, fp); + + for(int i=0;i 127) - { - binary=true; - break; - } + { + binary=true; + break; + } } // Now we know if the stl file is ascii or binary. fclose(fp); - if(binary) return OpenBinary(m,filename,cb); + return binary; +} + +static int Open( OpenMeshType &m, const char * filename, int &loadMask, CallBackPos *cb=0) +{ + FILE *fp = fopen(filename, "r"); + if(fp == NULL) + return E_CANTOPEN; + fclose(fp); + loadMask |= Mask::IOM_VERTCOORD | Mask::IOM_FACEINDEX; + + if(IsSTLBinary(filename)) return OpenBinary(m,filename,loadMask,cb); else return OpenAscii(m,filename,cb); } -static int OpenBinary( OpenMeshType &m, const char * filename, CallBackPos *cb=0) +static int OpenBinary( OpenMeshType &m, const char * filename, int &loadMask, CallBackPos *cb=0) { FILE *fp; fp = fopen(filename, "rb"); @@ -135,6 +178,10 @@ static int OpenBinary( OpenMeshType &m, const char * filename, CallBackPos *cb=0 return E_CANTOPEN; } + bool magicsMode; + if(!IsSTLColored(filename,magicsMode)) + loadMask = loadMask & (~Mask::IOM_FACECOLOR); + int facenum; fseek(fp, STL_LABEL_SIZE, SEEK_SET); fread(&facenum, sizeof(int), 1, fp); @@ -145,12 +192,17 @@ static int OpenBinary( OpenMeshType &m, const char * filename, CallBackPos *cb=0 // For each triangle read the normal, the three coords and a short set to zero for(int i=0;i