00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <sofa/component/visualmodel/VisualModelImpl.h>
00026
00027 #include <sofa/component/topology/TriangleSetTopologyModifier.h>
00028 #include <sofa/component/topology/QuadSetTopologyModifier.h>
00029 #include <sofa/component/topology/TetrahedronSetTopologyModifier.h>
00030 #include <sofa/component/topology/HexahedronSetTopologyModifier.h>
00031
00032 #include <sofa/component/topology/PointSetTopologyChange.h>
00033 #include <sofa/component/topology/TriangleSetTopologyChange.h>
00034 #include <sofa/component/topology/QuadSetTopologyChange.h>
00035 #include <sofa/component/topology/TetrahedronSetTopologyChange.h>
00036 #include <sofa/component/topology/HexahedronSetTopologyChange.h>
00037
00038 #include <sofa/component/topology/SparseGridTopology.h>
00039
00040 #include <sofa/helper/system/FileRepository.h>
00041 #include <sofa/helper/gl/RAII.h>
00042 #include <sofa/helper/vector.h>
00043 #include <sofa/defaulttype/Quat.h>
00044 #include <sofa/core/ObjectFactory.h>
00045 #include <sofa/helper/io/Mesh.h>
00046 #include <sofa/helper/rmath.h>
00047 #include <sstream>
00048
00049 #include <map>
00050
00051 namespace sofa
00052 {
00053
00054 namespace component
00055 {
00056
00057 namespace visualmodel
00058 {
00059
00060 using namespace sofa::defaulttype;
00061 using namespace sofa::core::componentmodel::topology;
00062
00063 void VisualModelImpl::parse(core::objectmodel::BaseObjectDescription* arg)
00064 {
00065 this->core::VisualModel::parse(arg);
00066 VisualModelImpl* obj = this;
00067
00068 if (arg->getAttribute("normals")!=NULL)
00069 obj->setUseNormals(atoi(arg->getAttribute("normals"))!=0);
00070
00071 if (arg->getAttribute("castshadow")!=NULL)
00072 obj->setCastShadow(atoi(arg->getAttribute("castshadow"))!=0);
00073
00074 std::string loader = arg->getAttribute("loader","");
00075
00076 std::string file;
00077 file=(arg->getAttribute("texturename",""));
00078 if (!file.empty())
00079 {
00080 texturename.setValue( sofa::helper::system::DataRepository.getFile ( file ));
00081 }
00082
00083 file=(arg->getAttribute("filename",""));
00085
00086
00087 filename.setValue( sofa::helper::system::DataRepository.getFile ( file ));
00088
00089
00090
00091 if (arg->getAttribute("flip")!=NULL) {
00092 obj->flipFaces();
00093 }
00094 if (arg->getAttribute("color")) {
00095 obj->setColor(arg->getAttribute("color"));
00096 }
00097 scaleTex= 1.0f;
00098 if (arg->getAttribute("scaleTex")!=NULL) {
00099
00100 scaleTex=(float)(atof(arg->getAttribute("scaleTex","1.0")));
00101 obj->applyUVScale(scaleTex, scaleTex);
00102 }
00103 if (arg->getAttribute("du")!=NULL || arg->getAttribute("dv")!=NULL) {
00104 obj->applyUVTranslation(atof(arg->getAttribute("du","0.0")), atof(arg->getAttribute("dv","0.0")));
00105 }
00106
00107
00108
00109
00110
00111 if (arg->getAttribute("rx")!=NULL || arg->getAttribute("ry")!=NULL || arg->getAttribute("rz")!=NULL) {
00112 rotation.setValue(Vector3((SReal)(atof(arg->getAttribute("rx","0.0"))),(SReal)(atof(arg->getAttribute("ry","0.0"))),(SReal)(atof(arg->getAttribute("rz","0.0")))));
00113 }
00114
00115 if (arg->getAttribute("dx")!=NULL || arg->getAttribute("dy")!=NULL || arg->getAttribute("dz")!=NULL) {
00116 translation.setValue(Vector3((SReal)atof(arg->getAttribute("dx","0.0")), (SReal)atof(arg->getAttribute("dy","0.0")), (SReal)atof(arg->getAttribute("dz","0.0"))));
00117 }
00118 }
00119
00120 SOFA_DECL_CLASS(VisualModelImpl)
00121
00122 int VisualModelImplClass = core::RegisterObject("Generic visual model. If a viewer is active it will replace the VisualModel alias, otherwise nothing will be displayed.")
00123 .add< VisualModelImpl >()
00124 .addAlias("VisualModel")
00125 ;
00126
00127 VisualModelImpl::VisualModelImpl()
00128 : useTopology(false), lastMeshRev(-1), useNormals(true), castShadow(true),
00129
00130 field_vertices (initDataPtr(&field_vertices,&vertices, "position", "vertices of the model") ),
00131 field_vnormals (initDataPtr(&field_vnormals, &vnormals, "normals", "normals of the model") ),
00132 field_vtexcoords (initDataPtr(&field_vtexcoords, &vtexcoords, "texcoords", "coordinates of the texture") ),
00133 field_triangles (initDataPtr(&field_triangles, &triangles,"triangles" , "triangles of the model") ),
00134 field_quads (initDataPtr(&field_quads, &quads, "quads", "quads of the model") ),
00135 filename (initData (&filename, "filename","Path to the model", false)),
00136 texturename (initData (&texturename, "texturename","Name of the Texture")),
00137 translation (initData (&translation, Vector3(), "translation", "Initial Translation of the object")),
00138 rotation (initData (&rotation, Vector3(), "rotation", "Initial Rotation of the object")),
00139 scale (initData (&scale, (SReal)(1.0), "scale", "Initial Scale of the object")),
00140 material(initData(&material,"material","Material"))
00141 {
00142 inputVertices = &vertices;
00143 }
00144
00145 VisualModelImpl::~VisualModelImpl()
00146 {
00147 if (inputVertices != &vertices) delete inputVertices;
00148 }
00149
00150 bool VisualModelImpl::isTransparent()
00151 {
00152 return (material.getValue().useDiffuse && material.getValue().diffuse[3] < 1.0);
00153 }
00154
00155 void VisualModelImpl::drawVisual()
00156 {
00157 if (!isTransparent())
00158 internalDraw();
00159 }
00160
00161 void VisualModelImpl::drawTransparent()
00162 {
00163 if (isTransparent())
00164 internalDraw();
00165 }
00166
00167 void VisualModelImpl::drawShadow()
00168 {
00169 if (!isTransparent() && getCastShadow())
00170 {
00171
00172 internalDraw();
00173 }
00174 }
00175
00176 void VisualModelImpl::setMesh(helper::io::Mesh &objLoader, bool tex)
00177 {
00178 const vector< vector< vector<int> > > &facetsImport = objLoader.getFacets();
00179 const vector<Vector3> &verticesImport = objLoader.getVertices();
00180 const vector<Vector3> &normalsImport = objLoader.getNormals();
00181 const vector<Vector3> &texCoordsImport = objLoader.getTexCoords();
00182
00183 const helper::io::Mesh::Material &materialImport = objLoader.getMaterial();
00184
00185 if (!material.isSet() && materialImport.activated)
00186 {
00187 helper::io::Mesh::Material M;
00188 M = materialImport;
00189 material.setValue(M);
00190 }
00191
00192
00193
00194 int nbVIn = verticesImport.size();
00195
00196
00197 vector< std::map< std::pair<int,int>, int > > vertTexNormMap;
00198 vertTexNormMap.resize(nbVIn);
00199 for (unsigned int i = 0; i < facetsImport.size(); i++)
00200 {
00201 const vector<vector <int> >& vertNormTexIndex = facetsImport[i];
00202 if (vertNormTexIndex[0].size() < 3) continue;
00203 const vector<int>& verts = vertNormTexIndex[0];
00204 const vector<int>& texs = vertNormTexIndex[1];
00205 const vector<int>& norms = vertNormTexIndex[2];
00206 for (unsigned int j = 0; j < verts.size(); j++)
00207 {
00208 vertTexNormMap[verts[j]][std::make_pair((tex?texs[j]:-1), (useNormals?norms[j]:0))] = 0;
00209 }
00210 }
00211
00212
00213 int nbVOut = 0;
00214 bool vsplit = false;
00215 for (int i = 0; i < nbVIn; i++)
00216 {
00217 int s = vertTexNormMap[i].size();
00218 nbVOut += s;
00219 if (s!=1)
00220 vsplit = true;
00221 }
00222
00223
00224
00225 vertices.resize(nbVOut);
00226 vnormals.resize(nbVOut);
00227
00228 if (tex)
00229 vtexcoords.resize(nbVOut);
00230
00231 if (vsplit)
00232 {
00233 inputVertices = new ResizableExtVector<Coord>;
00234 inputVertices->resize(nbVIn);
00235 vertPosIdx.resize(nbVOut);
00236 vertNormIdx.resize(nbVOut);
00237 }
00238 else
00239 inputVertices = &vertices;
00240
00241 int nbNOut = 0;
00242 for (int i = 0, j = 0; i < nbVIn; i++)
00243 {
00244 if (vsplit)
00245 (*inputVertices)[i] = verticesImport[i];
00246 std::map<int, int> normMap;
00247 for (std::map<std::pair<int, int>, int>::iterator it = vertTexNormMap[i].begin();
00248 it != vertTexNormMap[i].end(); ++it)
00249 {
00250 vertices[j] = verticesImport[i];
00251 int t = it->first.first;
00252 int n = it->first.second;
00253 if ((unsigned)n < normalsImport.size())
00254 vnormals[j] = normalsImport[n];
00255 if ((unsigned)t < texCoordsImport.size())
00256 vtexcoords[j] = texCoordsImport[t];
00257
00258 if (vsplit)
00259 {
00260 vertPosIdx[j] = i;
00261 if (normMap.count(n))
00262 vertNormIdx[j] = normMap[n];
00263 else
00264 vertNormIdx[j] = normMap[n] = nbNOut++;
00265 }
00266 it->second = j++;
00267 }
00268 }
00269 if (!vsplit) nbNOut = nbVOut;
00270 else if (nbNOut == nbVOut) vertNormIdx.resize(0);
00271
00272
00273
00274
00275
00276
00277
00278 for (unsigned int i = 0; i < facetsImport.size(); i++)
00279 {
00280 const vector<vector <int> >& vertNormTexIndex = facetsImport[i];
00281 if (vertNormTexIndex[0].size() < 3) continue;
00282 const vector<int>& verts = vertNormTexIndex[0];
00283 const vector<int>& texs = vertNormTexIndex[1];
00284 const vector<int>& norms = vertNormTexIndex[2];
00285 vector<int> idxs;
00286 idxs.resize(verts.size());
00287 for (unsigned int j = 0; j < verts.size(); j++)
00288 {
00289 idxs[j] = vertTexNormMap[verts[j]][std::make_pair((tex?texs[j]:-1), (useNormals?norms[j]:0))];
00290 if ((unsigned)idxs[j] >= (unsigned)nbVOut)
00291 {
00292 std::cerr << "ERROR(VisualModelImpl): index "<<idxs[j]<<" out of range\n";
00293 idxs[j] = 0;
00294 }
00295 }
00296
00297 if (verts.size() == 4)
00298 {
00299 quads.push_back(helper::make_array(idxs[0],idxs[1],idxs[2],idxs[3]));
00300 }
00301 else
00302 {
00303 for (unsigned int j = 2; j < verts.size(); j++)
00304 {
00305 triangles.push_back(helper::make_array(idxs[0],idxs[j-1],idxs[j]));
00306 }
00307 }
00308 }
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320 computeNormals();
00321 computeBBox();
00322 }
00323
00324 bool VisualModelImpl::load(const std::string& filename, const std::string& loader, const std::string& textureName)
00325 {
00326 bool tex = !textureName.empty();
00327 if (!textureName.empty() )
00328 {
00329 std::string textureFilename(textureName);
00330 if (sofa::helper::system::DataRepository.findFile (textureFilename))
00331 tex = loadTexture(textureName);
00332 else
00333 logWarning(std::string("Texture \"") + textureName +std::string("\" not found"));
00334 }
00335 tex = !textureName.empty();
00336
00337 if (!filename.empty() && vertices.size() == 0)
00338 {
00339 std::string meshFilename(filename);
00340 if (sofa::helper::system::DataRepository.findFile (meshFilename))
00341 {
00342
00343 helper::io::Mesh *objLoader;
00344 if (loader.empty())
00345 objLoader = helper::io::Mesh::Create(filename);
00346 else
00347 objLoader = helper::io::Mesh::FactoryMesh::CreateObject(loader, filename);
00348
00349 if (!objLoader)
00350 {
00351 return false;
00352 }
00353 else
00354 {
00355 setMesh(*objLoader,tex);
00356
00357 }
00358 }
00359 else
00360 logWarning(std::string("Mesh \"") + filename +std::string("\" not found"));
00361 }
00362 else
00363 {
00364 if (vertices.size() == 0)
00365 {
00366 std::cout << "VisualModel: will use Topology."<<std::endl;
00367 useTopology = true;
00368 }
00369 else computeBBox();
00370 modified = true;
00371 }
00372
00373 if (!xformsModified)
00374 {
00375
00376 xforms.resize(1);
00377 }
00378 return true;
00379 }
00380
00381 void VisualModelImpl::applyTranslation(const double dx, const double dy, const double dz)
00382 {
00383 Vector3 d((GLfloat)dx,(GLfloat)dy,(GLfloat)dz);
00384 VecCoord& x = *getVecX();
00385 for (unsigned int i = 0; i < x.size(); i++)
00386 {
00387 x[i] += d;
00388 }
00389 updateVisual();
00390 }
00391
00392
00393 void VisualModelImpl::applyRotation (const double rx, const double ry, const double rz)
00394 {
00395 Quaternion q=helper::Quater<SReal>::createQuaterFromEuler( Vec<3,SReal>(rx,ry,rz)*M_PI/180.0);
00396 applyRotation(q);
00397 }
00398 void VisualModelImpl::applyRotation(const Quat q)
00399 {
00400 VecCoord& x = *getVecX();
00401 for (unsigned int i = 0; i < x.size(); i++)
00402 {
00403 x[i] = q.rotate(x[i]);
00404 }
00405 updateVisual();
00406 }
00407
00408 void VisualModelImpl::applyScale(const double scale)
00409 {
00410 VecCoord& x = *getVecX();
00411 for (unsigned int i = 0; i < x.size(); i++)
00412 {
00413 x[i] *= (GLfloat) scale;
00414 }
00415 updateVisual();
00416 }
00417
00418 void VisualModelImpl::applyUVTranslation(const double dU, const double dV)
00419 {
00420 for (unsigned int i = 0; i < vtexcoords.size(); i++)
00421 {
00422 vtexcoords[i][0] += (GLfloat) dU;
00423 vtexcoords[i][1] += (GLfloat) dV;
00424 }
00425 }
00426
00427 void VisualModelImpl::applyUVScale(const double scaleU, const double scaleV)
00428 {
00429 for (unsigned int i = 0; i < vtexcoords.size(); i++)
00430 {
00431 vtexcoords[i][0] *= (GLfloat) scaleU;
00432 vtexcoords[i][1] *= (GLfloat) scaleV;
00433 }
00434 }
00435
00436 void VisualModelImpl::init()
00437 {
00438
00439 load(filename.getValue(), "", texturename.getValue());
00440 _topology = getContext()->getMeshTopology();
00441
00442 field_vertices.beginEdit();
00443 field_vnormals.beginEdit();
00444 field_vtexcoords.beginEdit();
00445 field_triangles.beginEdit();
00446 field_quads.beginEdit();
00447
00448
00449
00450 applyScale(scale.getValue());
00451 applyRotation(rotation.getValue()[0],rotation.getValue()[1],rotation.getValue()[2]);
00452 applyTranslation(translation.getValue()[0],translation.getValue()[1],translation.getValue()[2]);
00453
00454
00455 translation.setValue(Vector3());
00456 rotation.setValue(Vector3());
00457 scale.setValue((SReal)1.0);
00458 VisualModel::init();
00459 updateVisual();
00460 }
00461
00462 void VisualModelImpl::computeNormals()
00463 {
00464 if (vertNormIdx.empty())
00465 {
00466 int nbn = vertices.size();
00467
00468
00469
00470 ResizableExtVector<Coord>& normals = vnormals;
00471
00472 normals.resize(nbn);
00473 for (int i = 0; i < nbn; i++)
00474 normals[i].clear();
00475
00476 for (unsigned int i = 0; i < triangles.size() ; i++)
00477 {
00478
00479 const Coord v1 = vertices[triangles[i][0]];
00480 const Coord v2 = vertices[triangles[i][1]];
00481 const Coord v3 = vertices[triangles[i][2]];
00482 Coord n = cross(v2-v1, v3-v1);
00483
00484 n.normalize();
00485 normals[triangles[i][0]] += n;
00486 normals[triangles[i][1]] += n;
00487 normals[triangles[i][2]] += n;
00488
00489 }
00490 for (unsigned int i = 0; i < quads.size() ; i++)
00491 {
00492 const Coord & v1 = vertices[quads[i][0]];
00493 const Coord & v2 = vertices[quads[i][1]];
00494 const Coord & v3 = vertices[quads[i][2]];
00495 const Coord & v4 = vertices[quads[i][3]];
00496 Coord n1 = cross(v2-v1, v4-v1);
00497 Coord n2 = cross(v3-v2, v1-v2);
00498 Coord n3 = cross(v4-v3, v2-v3);
00499 Coord n4 = cross(v1-v4, v3-v4);
00500 n1.normalize(); n2.normalize(); n3.normalize(); n4.normalize();
00501 normals[quads[i][0]] += n1;
00502 normals[quads[i][1]] += n2;
00503 normals[quads[i][2]] += n3;
00504 normals[quads[i][3]] += n4;
00505 }
00506 for (unsigned int i = 0; i < normals.size(); i++)
00507 {
00508 normals[i].normalize();
00509 }
00510 }
00511 else
00512 {
00513 vector<Coord> normals;
00514 int nbn = 0;
00515 for (unsigned int i = 0; i < vertNormIdx.size(); i++)
00516 if (vertNormIdx[i] >= nbn)
00517 nbn = vertNormIdx[i]+1;
00518
00519 normals.resize(nbn);
00520 for (int i = 0; i < nbn; i++)
00521 normals[i].clear();
00522
00523 for (unsigned int i = 0; i < triangles.size() ; i++)
00524 {
00525 const Coord & v1 = vertices[triangles[i][0]];
00526 const Coord & v2 = vertices[triangles[i][1]];
00527 const Coord & v3 = vertices[triangles[i][2]];
00528 Coord n = cross(v2-v1, v3-v1);
00529 n.normalize();
00530 normals[vertNormIdx[triangles[i][0]]] += n;
00531 normals[vertNormIdx[triangles[i][1]]] += n;
00532 normals[vertNormIdx[triangles[i][2]]] += n;
00533 }
00534
00535 for (unsigned int i = 0; i < quads.size() ; i++)
00536 {
00537 const Coord & v1 = vertices[quads[i][0]];
00538 const Coord & v2 = vertices[quads[i][1]];
00539 const Coord & v3 = vertices[quads[i][2]];
00540 const Coord & v4 = vertices[quads[i][3]];
00541 Coord n1 = cross(v2-v1, v4-v1);
00542 Coord n2 = cross(v3-v2, v1-v2);
00543 Coord n3 = cross(v4-v3, v2-v3);
00544 Coord n4 = cross(v1-v4, v3-v4);
00545 n1.normalize(); n2.normalize(); n3.normalize(); n4.normalize();
00546 normals[vertNormIdx[quads[i][0]]] += n1;
00547 normals[vertNormIdx[quads[i][1]]] += n2;
00548 normals[vertNormIdx[quads[i][2]]] += n3;
00549 normals[vertNormIdx[quads[i][3]]] += n4;
00550 }
00551
00552 for (unsigned int i = 0; i < normals.size(); i++)
00553 {
00554 normals[i].normalize();
00555 }
00556 vnormals.resize(vertices.size());
00557 for (unsigned int i = 0; i < vertices.size(); i++)
00558 {
00559 vnormals[i] = normals[vertNormIdx[i]];
00560 }
00561 }
00562 }
00563
00564 void VisualModelImpl::computeBBox()
00565 {
00566 const VecCoord& x = vertices;
00567 Vec3f minBBox(1e10,1e10,1e10);
00568 Vec3f maxBBox(-1e10,-1e10,-1e10);
00569 for (unsigned int i = 0; i < x.size(); i++)
00570 {
00571 const Coord& p = x[i];
00572 for (int c=0;c<3;c++)
00573 {
00574 if (p[c] > maxBBox[c]) maxBBox[c] = p[c];
00575 if (p[c] < minBBox[c]) minBBox[c] = p[c];
00576 }
00577 }
00578 bbox[0] = minBBox;
00579 bbox[1] = maxBBox;
00580 }
00581
00582 bool VisualModelImpl::addBBox(double* minBBox, double* maxBBox)
00583 {
00584 if (bbox[0][0] > bbox[1][0]) return false;
00585 for (unsigned int i=0; i<xforms.size(); i++)
00586 {
00587 const Vec3f& center = xforms[i].getCenter();
00588 const Quat& orientation = xforms[i].getOrientation();
00589 for (int j=0;j<8;j++)
00590 {
00591 Coord p ( bbox[(j>>0)&1][0], bbox[(j>>1)&1][1], bbox[(j>>2)&1][2]);
00592 p = orientation.rotate(p) + center;
00593 for (int c=0;c<3;c++)
00594 {
00595 if (p[c] > maxBBox[c]) maxBBox[c] = p[c];
00596 if (p[c] < minBBox[c]) minBBox[c] = p[c];
00597 }
00598 }
00599 }
00600 return true;
00601 }
00602
00603 void VisualModelImpl::flipFaces()
00604 {
00605 for (unsigned int i = 0; i < triangles.size() ; i++)
00606 {
00607 int temp = triangles[i][1];
00608 triangles[i][1] = triangles[i][2];
00609 triangles[i][2] = temp;
00610 }
00611
00612 for (unsigned int i = 0; i < quads.size() ; i++)
00613 {
00614 int temp = quads[i][1];
00615 quads[i][1] = quads[i][3];
00616 quads[i][3] = temp;
00617
00618 }
00619
00620 for (unsigned int i = 0; i < vnormals.size(); i++)
00621 {
00622 vnormals[i] = -vnormals[i];
00623 }
00624 }
00625
00626 void VisualModelImpl::setColor(float r, float g, float b, float a)
00627 {
00628 helper::io::Mesh::Material M = material.getValue();
00629 M.setColor(r,g,b,a);
00630 material.setValue(M);
00631 }
00632
00633 static int hexval(char c)
00634 {
00635 if (c>='0' && c<='9') return c-'0';
00636 else if (c>='a' && c<='f') return (c-'a')+10;
00637 else if (c>='A' && c<='F') return (c-'A')+10;
00638 else return 0;
00639 }
00640
00641 void VisualModelImpl::setColor(std::string color)
00642 {
00643 if (color.empty()) return;
00644 float r = 1.0f;
00645 float g = 1.0f;
00646 float b = 1.0f;
00647 float a = 1.0f;
00648 if (color[0]>='0' && color[0]<='9')
00649 {
00650 sscanf(color.c_str(),"%f %f %f %f", &r, &g, &b, &a);
00651 }
00652 else if (color[0]=='#' && color.length()>=7)
00653 {
00654 r = (hexval(color[1])*16+hexval(color[2]))/255.0f;
00655 g = (hexval(color[3])*16+hexval(color[4]))/255.0f;
00656 b = (hexval(color[5])*16+hexval(color[6]))/255.0f;
00657 if (color.length()>=9)
00658 a = (hexval(color[7])*16+hexval(color[8]))/255.0f;
00659 }
00660 else if (color[0]=='#' && color.length()>=4)
00661 {
00662 r = (hexval(color[1])*17)/255.0f;
00663 g = (hexval(color[2])*17)/255.0f;
00664 b = (hexval(color[3])*17)/255.0f;
00665 if (color.length()>=5)
00666 a = (hexval(color[4])*17)/255.0f;
00667 }
00668 else if (color == "white") { r = 1.0f; g = 1.0f; b = 1.0f; }
00669 else if (color == "black") { r = 0.0f; g = 0.0f; b = 0.0f; }
00670 else if (color == "red") { r = 1.0f; g = 0.0f; b = 0.0f; }
00671 else if (color == "green") { r = 0.0f; g = 1.0f; b = 0.0f; }
00672 else if (color == "blue") { r = 0.0f; g = 0.0f; b = 1.0f; }
00673 else if (color == "cyan") { r = 0.0f; g = 1.0f; b = 1.0f; }
00674 else if (color == "magenta") { r = 1.0f; g = 0.0f; b = 1.0f; }
00675 else if (color == "yellow") { r = 1.0f; g = 1.0f; b = 0.0f; }
00676 else if (color == "gray") { r = 0.5f; g = 0.5f; b = 0.5f; }
00677 else
00678 {
00679 std::cerr << "Unknown color "<<color<<std::endl;
00680 return;
00681 }
00682 setColor(r,g,b,a);
00683 }
00684
00685 void VisualModelImpl::updateVisual()
00686 {
00687
00688 if (modified && (!vertices.empty() || useTopology))
00689 {
00690 if (useTopology)
00691 {
00695 sofa::core::componentmodel::topology::TopologyModifier* topoMod;
00696 this->getContext()->get(topoMod);
00697
00698 if (topoMod) {
00699 useTopology=false;
00700 computeMesh();
00701 }
00702 else {
00703
00704 if (topoMod == NULL && (_topology->getRevision() != lastMeshRev))
00705 {
00706 computeMesh();
00707 }
00708 }
00709 }
00710 computePositions();
00711 computeNormals();
00712 computeBBox();
00713 modified = false;
00714 }
00715 }
00716
00717
00718 void VisualModelImpl::computePositions()
00719 {
00720 if (!vertPosIdx.empty())
00721 {
00722 for (unsigned int i=0 ; i < vertices.size(); ++i)
00723 vertices[i] = (*inputVertices)[vertPosIdx[i]];
00724 }
00725 }
00726
00727 void VisualModelImpl::computeMesh()
00728 {
00729 if (vertices.empty())
00730 {
00731 if (_topology->hasPos())
00732 {
00733
00734 if (sofa::component::topology::SparseGridTopology * spTopo = dynamic_cast< sofa::component::topology::SparseGridTopology *>(_topology))
00735 {
00736 std::cout << "VisualModel: getting marching cube mesh from topology : ";
00737 sofa::helper::io::Mesh m;
00738 spTopo->getMesh(m);
00739 setMesh(m, !texturename.getValue().empty());
00740 std::cout
00741 <<m.getVertices().size()<<" points, "
00742 <<m.getFacets().size() << " triangles."<<std::endl;
00743 useTopology = false;
00744 return;
00745 }
00746 if (this->f_printLog.getValue())
00747 std::cout << "VisualModel: copying "<<_topology->getNbPoints()<<" points from topology."<<std::endl;
00748 vertices.resize(_topology->getNbPoints());
00749
00750 for (unsigned int i=0;i<vertices.size();i++)
00751 {
00752 vertices[i][0] = (Real)_topology->getPX(i);
00753 vertices[i][1] = (Real)_topology->getPY(i);
00754 vertices[i][2] = (Real)_topology->getPZ(i);
00755 }
00756
00757 }
00758 else
00759 {
00760 core::componentmodel::behavior::BaseMechanicalState* mstate = dynamic_cast<core::componentmodel::behavior::BaseMechanicalState*>(_topology->getContext()->getMechanicalState());
00761 if (mstate)
00762 {
00763 if (this->f_printLog.getValue())
00764 std::cout << "VisualModel: copying "<<mstate->getSize()<<" points from mechanical state."<<std::endl;
00765 vertices.resize(mstate->getSize());
00766
00767 for (unsigned int i=0;i<vertices.size();i++)
00768 {
00769 vertices[i][0] = (Real)mstate->getPX(i);
00770 vertices[i][1] = (Real)mstate->getPY(i);
00771 vertices[i][2] = (Real)mstate->getPZ(i);
00772 }
00773 }
00774 }
00775 }
00776
00777 lastMeshRev = _topology->getRevision();
00778 const vector<sofa::core::componentmodel::topology::BaseMeshTopology::Triangle>& inputTriangles = _topology->getTriangles();
00779 if (this->f_printLog.getValue())
00780 std::cout << "VisualModel: copying "<<inputTriangles.size()<<" triangles from topology."<<std::endl;
00781
00782 triangles.resize(inputTriangles.size());
00783
00784 for (unsigned int i=0; i<triangles.size(); ++i){
00785 triangles[i] = inputTriangles[i];
00786 }
00787
00788 const vector<sofa::core::componentmodel::topology::BaseMeshTopology::Quad>& inputQuads = _topology->getQuads();
00789 if (this->f_printLog.getValue())
00790 std::cout << "VisualModel: copying "<<inputQuads.size()<<" quads from topology."<<std::endl;
00791 quads.resize(inputQuads.size());
00792 for (unsigned int i=0; i<quads.size(); ++i)
00793 quads[i] = inputQuads[i];
00794 }
00795
00796 void VisualModelImpl::handleTopologyChange() {
00797
00798 bool debug_mode = false;
00799
00800 std::list<const TopologyChange *>::const_iterator itBegin=_topology->firstChange();
00801 std::list<const TopologyChange *>::const_iterator itEnd=_topology->lastChange();
00802
00803 while( itBegin != itEnd )
00804 {
00805 core::componentmodel::topology::TopologyChangeType changeType = (*itBegin)->getChangeType();
00806
00807 switch( changeType )
00808 {
00809 case core::componentmodel::topology::ENDING_EVENT:
00810 {
00811
00812 updateVisual();
00813 break;
00814 }
00815
00816 case core::componentmodel::topology::TRIANGLESADDED:
00817 {
00818
00819
00820 const sofa::component::topology::TrianglesAdded *ta=static_cast< const sofa::component::topology::TrianglesAdded * >( *itBegin );
00821 Triangle t;
00822
00823 for (unsigned int i=0;i<ta->getNbAddedTriangles();++i) {
00824
00825 t[0]=(int)(ta->triangleArray[i])[0];
00826 t[1]=(int)(ta->triangleArray[i])[1];
00827 t[2]=(int)(ta->triangleArray[i])[2];
00828 triangles.push_back(t);
00829 }
00830
00831 break;
00832 }
00833
00834 case core::componentmodel::topology::QUADSADDED:
00835 {
00836
00837
00838 const sofa::component::topology::QuadsAdded *ta_const=static_cast< const sofa::component::topology::QuadsAdded * >( *itBegin );
00839 sofa::component::topology::QuadsAdded *ta = const_cast< sofa::component::topology::QuadsAdded * >(ta_const);
00840 Quad t;
00841
00842 for (unsigned int i=0;i<ta->getNbAddedQuads();++i) {
00843
00844 t[0]=(int)(ta->getQuad(i))[0];
00845 t[1]=(int)(ta->getQuad(i))[1];
00846 t[2]=(int)(ta->getQuad(i))[2];
00847 t[3]=(int)(ta->getQuad(i))[3];
00848 quads.push_back(t);
00849 }
00850
00851 break;
00852 }
00853
00854 case core::componentmodel::topology::TRIANGLESREMOVED:
00855 {
00856
00857
00858 unsigned int last;
00859 unsigned int ind_last;
00860
00861 last= _topology->getNbTriangles() - 1;
00862
00863 const sofa::helper::vector<unsigned int> &tab = ( static_cast< const sofa::component::topology::TrianglesRemoved *>( *itBegin ) )->getArray();
00864
00865 Triangle tmp;
00866
00867 for (unsigned int i = 0; i <tab.size(); ++i)
00868 {
00869 unsigned int ind_k = tab[i];
00870
00871 tmp = triangles[ind_k];
00872 triangles[ind_k] = triangles[last];
00873 triangles[last] = tmp;
00874
00875 ind_last = triangles.size() - 1;
00876
00877 if(last != ind_last){
00878
00879 tmp = triangles[last];
00880 triangles[last] = triangles[ind_last];
00881 triangles[ind_last] = tmp;
00882 }
00883
00884 triangles.resize( triangles.size() - 1 );
00885
00886 --last;
00887
00888 }
00889
00890 break;
00891 }
00892
00893 case core::componentmodel::topology::QUADSREMOVED:
00894 {
00895
00896
00897 unsigned int last;
00898 unsigned int ind_last;
00899
00900 last= _topology->getNbQuads() - 1;
00901
00902 const sofa::helper::vector<unsigned int> &tab = ( static_cast< const sofa::component::topology::QuadsRemoved *>( *itBegin ) )->getArray();
00903
00904 Quad tmp;
00905
00906 for (unsigned int i = 0; i <tab.size(); ++i)
00907 {
00908
00909 unsigned int ind_k = tab[i];
00910
00911 tmp = quads[ind_k];
00912 quads[ind_k] = quads[last];
00913 quads[last] = tmp;
00914
00915 ind_last = quads.size() - 1;
00916
00917 if(last != ind_last){
00918
00919 tmp = quads[last];
00920 quads[last] = quads[ind_last];
00921 quads[ind_last] = tmp;
00922
00923 }
00924
00925 quads.resize( quads.size() - 1 );
00926
00927 --last;
00928
00929 }
00930
00931 break;
00932 }
00933
00934
00935
00936 case core::componentmodel::topology::POINTSREMOVED:
00937 {
00938
00939
00940 if (_topology->getNbTriangles()>0) {
00941
00942 unsigned int last = _topology->getNbPoints() -1;
00943
00944 unsigned int i,j;
00945
00946 const sofa::helper::vector<unsigned int> tab = ( static_cast< const sofa::component::topology::PointsRemoved * >( *itBegin ) )->getArray();
00947
00948 sofa::helper::vector<unsigned int> lastIndexVec;
00949
00950 for(unsigned int i_init = 0; i_init < tab.size(); ++i_init){
00951 lastIndexVec.push_back(last - i_init);
00952 }
00953
00954 for ( i = 0; i < tab.size(); ++i){
00955
00956 unsigned int i_next = i;
00957 bool is_reached = false;
00958
00959 while( (!is_reached) && (i_next < lastIndexVec.size() - 1)){
00960
00961 i_next += 1 ;
00962 is_reached = is_reached || (lastIndexVec[i_next] == tab[i]);
00963 }
00964
00965 if(is_reached){
00966 lastIndexVec[i_next] = lastIndexVec[i];
00967 }
00968
00969 const sofa::helper::vector<unsigned int> &shell= _topology->getTriangleVertexShell(lastIndexVec[i]);
00970 for (j=0;j<shell.size();++j) {
00971
00972 unsigned int ind_j = shell[j];
00973
00974 if ((unsigned)triangles[ind_j][0]==last)
00975 triangles[ind_j][0]=tab[i];
00976 else if ((unsigned)triangles[ind_j][1]==last)
00977 triangles[ind_j][1]=tab[i];
00978 else if ((unsigned)triangles[ind_j][2]==last)
00979 triangles[ind_j][2]=tab[i];
00980 }
00981
00982 if (debug_mode) {
00983
00984 for (unsigned int j_loc=0;j_loc<triangles.size();++j_loc) {
00985
00986 bool is_forgotten = false;
00987 if ((unsigned)triangles[j_loc][0]==last){
00988 triangles[j_loc][0]=tab[i];
00989 is_forgotten=true;
00990
00991 }else{
00992 if ((unsigned)triangles[j_loc][1]==last){
00993 triangles[j_loc][1]=tab[i];
00994 is_forgotten=true;
00995
00996 }else{
00997 if ((unsigned)triangles[j_loc][2]==last){
00998 triangles[j_loc][2]=tab[i];
00999 is_forgotten=true;
01000 }
01001 }
01002
01003 }
01004
01005 if(is_forgotten){
01006
01007 int ind_forgotten = j_loc;
01008
01009 bool is_in_shell = false;
01010 for (unsigned int j_glob=0;j_glob<shell.size();++j_glob) {
01011 is_in_shell = is_in_shell || ((int)shell[j_glob] == ind_forgotten);
01012 }
01013
01014 if(!is_in_shell) {
01015 std::cout << "INFO_print : Vis - triangle is forgotten in SHELL !!! global indices (point, triangle) = ( " << last << " , " << ind_forgotten << " )" << std::endl;
01016
01017 if(ind_forgotten<_topology->getNbTriangles()){
01018 const sofa::component::topology::Triangle t_forgotten = _topology->getTriangle(ind_forgotten);
01019 std::cout << "INFO_print : Vis - last = " << last << std::endl;
01020 std::cout << "INFO_print : Vis - lastIndexVec[i] = " << lastIndexVec[i] << std::endl;
01021 std::cout << "INFO_print : Vis - tab.size() = " << tab.size() << " , tab = " << tab << std::endl;
01022 std::cout << "INFO_print : Vis - t_local rectified = " << triangles[j_loc] << std::endl;
01023 std::cout << "INFO_print : Vis - t_global = " << t_forgotten << std::endl;
01024
01025
01026 }
01027
01028 }
01029
01030 }
01031
01032 }
01033 }
01034
01035 --last;
01036 }
01037
01038 }else{
01039
01040 if (_topology->getNbQuads()>0) {
01041
01042 unsigned int last = _topology->getNbPoints() -1;
01043
01044 unsigned int i,j;
01045
01046 const sofa::helper::vector<unsigned int> tab = ( static_cast< const sofa::component::topology::PointsRemoved * >( *itBegin ) )->getArray();
01047
01048 sofa::helper::vector<unsigned int> lastIndexVec;
01049 for(unsigned int i_init = 0; i_init < tab.size(); ++i_init){
01050
01051 lastIndexVec.push_back(last - i_init);
01052 }
01053
01054 for ( i = 0; i < tab.size(); ++i)
01055 {
01056 unsigned int i_next = i;
01057 bool is_reached = false;
01058 while( (!is_reached) && (i_next < lastIndexVec.size() - 1)){
01059
01060 i_next += 1 ;
01061 is_reached = is_reached || (lastIndexVec[i_next] == tab[i]);
01062 }
01063
01064 if(is_reached){
01065
01066 lastIndexVec[i_next] = lastIndexVec[i];
01067
01068 }
01069
01070 const sofa::helper::vector<unsigned int> &shell= _topology->getQuadVertexShell(lastIndexVec[i]);
01071 for (j=0;j<shell.size();++j) {
01072
01073 unsigned int ind_j = shell[j];
01074
01075 if ((unsigned)quads[ind_j][0]==last)
01076 quads[ind_j][0]=tab[i];
01077 else if ((unsigned)quads[ind_j][1]==last)
01078 quads[ind_j][1]=tab[i];
01079 else if ((unsigned)quads[ind_j][2]==last)
01080 quads[ind_j][2]=tab[i];
01081 else if ((unsigned)quads[ind_j][3]==last)
01082 quads[ind_j][3]=tab[i];
01083 }
01084
01085 --last;
01086 }
01087
01089
01090 }
01091
01092
01093 }
01094
01095
01096
01097 break;
01098
01099 }
01100
01101
01102
01103
01104 case core::componentmodel::topology::POINTSRENUMBERING:
01105 {
01106
01107
01108 if (_topology->getNbTriangles()>0) {
01109
01110 unsigned int i;
01111
01112 const sofa::helper::vector<unsigned int> tab = ( static_cast< const sofa::component::topology::PointsRenumbering * >( *itBegin ) )->getinv_IndexArray();
01113
01114 for ( i = 0; i < triangles.size(); ++i)
01115 {
01116 triangles[i][0] = tab[triangles[i][0]];
01117 triangles[i][1] = tab[triangles[i][1]];
01118 triangles[i][2] = tab[triangles[i][2]];
01119 }
01120
01121 }else{
01122 if (_topology->getNbQuads()>0) {
01123
01124 unsigned int i;
01125
01126 const sofa::helper::vector<unsigned int> tab = ( static_cast< const sofa::component::topology::PointsRenumbering * >( *itBegin ) )->getinv_IndexArray();
01127
01128 for ( i = 0; i < quads.size(); ++i)
01129 {
01130 quads[i][0] = tab[quads[i][0]];
01131 quads[i][1] = tab[quads[i][1]];
01132 quads[i][2] = tab[quads[i][2]];
01133 quads[i][3] = tab[quads[i][3]];
01134 }
01135 }
01136 }
01137
01138
01139
01140 break;
01141
01142 }
01143
01144 default:
01145
01146 break;
01147 };
01148
01149 ++itBegin;
01150 }
01151
01152
01153 }
01154
01155 void VisualModelImpl::initVisual()
01156 {
01157
01158
01159
01160
01161 }
01162
01163 void VisualModelImpl::exportOBJ(std::string name, std::ostream* out, std::ostream* mtl, int& vindex, int& nindex, int& tindex)
01164 {
01165 *out << "g "<<name<<"\n";
01166
01167 if (mtl != NULL)
01168 {
01169 std::string name;
01170 if (name.empty())
01171 {
01172 static int count = 0;
01173 std::ostringstream o; o << "mat" << ++count;
01174 name = o.str();
01175 }
01176 *mtl << "newmtl "<<name<<"\n";
01177 *mtl << "illum 4\n";
01178 if (material.getValue().useAmbient)
01179 *mtl << "Ka "<<material.getValue().ambient[0]<<' '<<material.getValue().ambient[1]<<' '<<material.getValue().ambient[2]<<"\n";
01180 if (material.getValue().useDiffuse)
01181 *mtl << "Kd "<<material.getValue().diffuse[0]<<' '<<material.getValue().diffuse[1]<<' '<<material.getValue().diffuse[2]<<"\n";
01182 *mtl << "Tf 1.00 1.00 1.00\n";
01183 *mtl << "Ni 1.00\n";
01184 if (material.getValue().useSpecular)
01185 *mtl << "Ks "<<material.getValue().specular[0]<<' '<<material.getValue().specular[1]<<' '<<material.getValue().specular[2]<<"\n";
01186 if (material.getValue().useShininess)
01187 *mtl << "Ns "<<material.getValue().shininess<<"\n";
01188 if (material.getValue().useDiffuse && material.getValue().diffuse[3]<1.0)
01189 *mtl << "Tf "<<material.getValue().diffuse[3]<<' '<<material.getValue().diffuse[3]<<' '<<material.getValue().diffuse[3]<<"\n";
01190
01191 *out << "usemtl "<<name<<'\n';
01192 }
01193 const ResizableExtVector<Coord>& x = *inputVertices;
01194
01195 int nbv = x.size();
01196
01197 for (unsigned int i=0; i<x.size(); i++)
01198 {
01199 *out << "v "<< std::fixed << x[i][0]<<' '<< std::fixed <<x[i][1]<<' '<< std::fixed <<x[i][2]<<'\n';
01200 }
01201
01202 int nbn = 0;
01203
01204 if (vertNormIdx.empty())
01205 {
01206 nbn = vnormals.size();
01207 for (unsigned int i=0; i<vnormals.size(); i++)
01208 {
01209 *out << "vn "<< std::fixed << vnormals[i][0]<<' '<< std::fixed <<vnormals[i][1]<<' '<< std::fixed <<vnormals[i][2]<<'\n';
01210 }
01211 }
01212 else
01213 {
01214 for (unsigned int i = 0; i < vertNormIdx.size(); i++)
01215 {
01216 if (vertNormIdx[i] >= nbn)
01217 nbn = vertNormIdx[i]+1;
01218 }
01219 vector<int> normVertIdx(nbn);
01220 for (unsigned int i = 0; i < vertNormIdx.size(); i++)
01221 {
01222 normVertIdx[vertNormIdx[i]]=i;
01223 }
01224 for (int i = 0; i < nbn; i++)
01225 {
01226 int j = normVertIdx[i];
01227 *out << "vn "<< std::fixed << vnormals[j][0]<<' '<< std::fixed <<vnormals[j][1]<<' '<< std::fixed <<vnormals[j][2]<<'\n';
01228 }
01229 }
01230
01231 int nbt = 0;
01232 if (!vtexcoords.empty())
01233 {
01234 nbt = vtexcoords.size();
01235 for (unsigned int i=0; i<vtexcoords.size(); i++)
01236 {
01237 *out << "vt "<< std::fixed << vtexcoords[i][0]<<' '<< std::fixed <<vtexcoords[i][1]<<'\n';
01238 }
01239 }
01240
01241 for (unsigned int i = 0; i < triangles.size() ; i++)
01242 {
01243 *out << "f";
01244 for (int j=0;j<3;j++)
01245 {
01246 int i0 = triangles[i][j];
01247 int i_p = vertPosIdx.empty() ? i0 : vertPosIdx[i0];
01248 int i_n = vertNormIdx.empty() ? i0 : vertNormIdx[i0];
01249 if (vtexcoords.empty())
01250 *out << ' ' << i_p+vindex+1 << "//" << i_n+nindex+1;
01251 else
01252 *out << ' ' << i_p+vindex+1 << '/' << i0+tindex+1 << '/' << i_n+nindex+1;
01253 }
01254 *out << '\n';
01255 }
01256 for (unsigned int i = 0; i < quads.size() ; i++)
01257 {
01258 *out << "f";
01259 for (int j=0;j<4;j++)
01260 {
01261 int i0 = quads[i][j];
01262 int i_p = vertPosIdx.empty() ? i0 : vertPosIdx[i0];
01263 int i_n = vertNormIdx.empty() ? i0 : vertNormIdx[i0];
01264 if (vtexcoords.empty())
01265 *out << ' ' << i_p+vindex+1 << "//" << i_n+nindex+1;
01266 else
01267 *out << ' ' << i_p+vindex+1 << '/' << i0+tindex+1 << '/' << i_n+nindex+1;
01268 }
01269 *out << '\n';
01270 }
01271 *out << std::endl;
01272 vindex+=nbv;
01273 nindex+=nbn;
01274 tindex+=nbt;
01275 }
01276
01277 }
01278
01279 }
01280
01281 }
01282