00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "mesh.h"
00024 #include "dynload.h"
00025 #include "context.h"
00026 #include "loopsubdiv.h"
00027
00028 using namespace lux;
00029
00030 Mesh::Mesh(const Transform &o2w, bool ro, MeshAccelType acceltype,
00031 int nv, const Point *P, const Normal *N, const float *UV,
00032 MeshTriangleType tritype, int trisCount, const int *tris,
00033 MeshQuadType quadtype, int nquadsCount, const int *quads,
00034 MeshSubdivType subdivtype, int nsubdivlevels,
00035 boost::shared_ptr<Texture<float> > dmMap, float dmScale, float dmOffset,
00036 bool dmNormalSmooth, bool dmSharpBoundary) : Shape(o2w, ro)
00037 {
00038 accelType = acceltype;
00039
00040 subdivType = subdivtype;
00041 nSubdivLevels = max(0, nsubdivlevels);
00042 displacementMap = dmMap;
00043 displacementMapScale = dmScale;
00044 displacementMapOffset = dmOffset;
00045 displacementMapNormalSmooth = dmNormalSmooth;
00046 displacementMapSharpBoundary = dmSharpBoundary;
00047 mustSubdivide = nSubdivLevels > 0;
00048
00049
00050
00051
00052 nverts = nv;
00053 p = new Point[nverts];
00054 if (!mustSubdivide) {
00055
00056 for (int i = 0; i < nverts; ++i)
00057 p[i] = ObjectToWorld(P[i]);
00058 } else {
00059
00060 memcpy(p, P, nverts * sizeof(Point));
00061 }
00062
00063
00064 if (UV) {
00065 uvs = new float[2 * nverts];
00066 memcpy(uvs, UV, 2 * nverts*sizeof(float));
00067 } else
00068 uvs = NULL;
00069
00070 if (N) {
00071 n = new Normal[nverts];
00072 if (!mustSubdivide) {
00073
00074 for (int i = 0; i < nverts; ++i)
00075 n[i] = Normalize(ObjectToWorld(N[i]));
00076 } else {
00077
00078 memcpy(n, N, nverts * sizeof(Normal));
00079 }
00080 } else
00081 n = NULL;
00082
00083
00084 quadType = quadtype;
00085 nquads = nquadsCount;
00086 vector<int> quadsOk;
00087 vector<int> quadsToSplit;
00088 if (nquads == 0)
00089 quadVertexIndex = NULL;
00090 else {
00091
00092 for (int i = 0; i < nquads; i++) {
00093 const int idx = 4 * i;
00094 const Point &p0 = p[quads[idx]];
00095 const Point &p1 = p[quads[idx + 1]];
00096 const Point &p2 = p[quads[idx + 2]];
00097 const Point &p3 = p[quads[idx + 3]];
00098
00099
00100 if (!mustSubdivide && MeshQuadrilateral::IsPlanar(p0, p1, p2, p3)) {
00101 quadsOk.push_back(quads[idx]);
00102 quadsOk.push_back(quads[idx + 1]);
00103 quadsOk.push_back(quads[idx + 2]);
00104 quadsOk.push_back(quads[idx + 3]);
00105 } else {
00106
00107 quadsToSplit.push_back(quads[idx]);
00108 quadsToSplit.push_back(quads[idx + 1]);
00109 quadsToSplit.push_back(quads[idx + 2]);
00110 quadsToSplit.push_back(quads[idx + 3]);
00111 }
00112 }
00113
00114 nquads = quadsOk.size() / 4;
00115 if (nquads == 0)
00116 quadVertexIndex = NULL;
00117 else {
00118 quadVertexIndex = new int[4 * nquads];
00119 for (int i = 0; i < 4 * nquads; ++i)
00120 quadVertexIndex[i] = quadsOk[i];
00121 }
00122 }
00123
00124 if (!quadsToSplit.empty()) {
00125 std::stringstream ss;
00126 ss << "Mesh: splitting " << (quadsToSplit.size() / 4) << " quads";
00127 if( nSubdivLevels > 0 )
00128 ss << " to allow subdivision";
00129 else
00130 ss << " because they are non-planar";
00131 luxError(LUX_NOERROR, LUX_INFO, ss.str().c_str());
00132 }
00133
00134
00135 triType = tritype;
00136 ntris = trisCount;
00137 if (ntris == 0) {
00138 if (quadsToSplit.size() == 0)
00139 triVertexIndex = NULL;
00140 else {
00141
00142 const size_t nquadsToSplit = quadsToSplit.size() / 4;
00143 ntris = 2 * nquadsToSplit;
00144 triVertexIndex = new int[3 * ntris];
00145
00146 for (size_t i = 0; i < nquadsToSplit; i++) {
00147 const size_t qidx = 4 * i;
00148 const size_t tidx = 2 * 3 * i;
00149
00150
00151 triVertexIndex[tidx] = quadsToSplit[qidx];
00152 triVertexIndex[tidx + 1] = quadsToSplit[qidx + 1];
00153 triVertexIndex[tidx + 2] = quadsToSplit[qidx + 2];
00154
00155 triVertexIndex[tidx + 3] = quadsToSplit[qidx];
00156 triVertexIndex[tidx + 4] = quadsToSplit[qidx + 2];
00157 triVertexIndex[tidx + 5] = quadsToSplit[qidx + 3];
00158 }
00159 }
00160 } else {
00161 const size_t nquadsToSplit = quadsToSplit.size() / 4;
00162 ntris += 2 * nquadsToSplit;
00163 triVertexIndex = new int[3 * ntris];
00164 memcpy(triVertexIndex, tris, 3 * trisCount * sizeof(int));
00165
00166
00167 for (size_t i = 0; i < nquadsToSplit; i++) {
00168 const size_t qidx = 4 * i;
00169 const size_t tidx = 3 * trisCount + 2 * 3 * i;
00170
00171
00172 triVertexIndex[tidx] = quadsToSplit[qidx];
00173 triVertexIndex[tidx + 1] = quadsToSplit[qidx + 1];
00174 triVertexIndex[tidx + 2] = quadsToSplit[qidx + 2];
00175
00176 triVertexIndex[tidx + 3] = quadsToSplit[qidx];
00177 triVertexIndex[tidx + 4] = quadsToSplit[qidx + 2];
00178 triVertexIndex[tidx + 5] = quadsToSplit[qidx + 3];
00179 }
00180 }
00181 }
00182
00183 Mesh::~Mesh()
00184 {
00185 delete[] triVertexIndex;
00186 delete[] quadVertexIndex;
00187 delete[] p;
00188 delete[] n;
00189 delete[] uvs;
00190 }
00191
00192 BBox Mesh::ObjectBound() const
00193 {
00194 BBox bobj;
00195 for (int i = 0; i < nverts; ++i)
00196 bobj = Union(bobj, WorldToObject(p[i]));
00197 return bobj;
00198 }
00199
00200 BBox Mesh::WorldBound() const
00201 {
00202 BBox worldBounds;
00203 for (int i = 0; i < nverts; ++i)
00204 worldBounds = Union(worldBounds, p[i]);
00205 return worldBounds;
00206 }
00207
00208 template<class T>
00209 class MeshElemSharedPtr : public T
00210 {
00211 public:
00212 MeshElemSharedPtr(const Mesh* m, int n,
00213 boost::shared_ptr<Primitive> aPtr)
00214 : T(m,n), ptr(aPtr) { }
00215 private:
00216 const boost::shared_ptr<Primitive> ptr;
00217 };
00218
00219 void Mesh::Refine(vector<boost::shared_ptr<Primitive> > &refined,
00220 const PrimitiveRefinementHints &refineHints,
00221 boost::shared_ptr<Primitive> thisPtr)
00222 {
00223 if (ntris + nquads == 0)
00224 return;
00225
00226
00227 if (mustSubdivide) {
00228 MeshSubdivType concreteSubdivType = subdivType;
00229 switch (concreteSubdivType) {
00230 case SUBDIV_LOOP: {
00231
00232 boost::shared_ptr<LoopSubdiv::SubdivResult> res;
00233 LoopSubdiv loopsubdiv(ObjectToWorld, reverseOrientation,
00234 ntris, nverts, triVertexIndex, p, uvs,
00235 nSubdivLevels, displacementMap,
00236 displacementMapScale, displacementMapOffset,
00237 displacementMapNormalSmooth, displacementMapSharpBoundary);
00238 res = loopsubdiv.Refine();
00239
00240 if (!res)
00241 break;
00242
00243
00244 delete[] p;
00245 delete[] n;
00246 delete[] uvs;
00247 delete[] triVertexIndex;
00248
00249
00250 nverts = res->nverts;
00251 ntris = res->ntris;
00252 triVertexIndex = new int[3 * ntris];
00253 memcpy(triVertexIndex, res->indices, 3 * ntris * sizeof(int));
00254 p = new Point[nverts];
00255 for( int i = 0; i< nverts; ++i)
00256 p[i] = ObjectToWorld(res->P[i]);
00257 if (res->uv) {
00258 uvs = new float[2 * nverts];
00259 memcpy(uvs, res->uv, 2 * nverts * sizeof(float));
00260 } else
00261 uvs = NULL;
00262
00263 if (res->N) {
00264 n = new Normal[nverts];
00265 for( int i = 0; i< nverts; ++i)
00266 n[i] = Normalize(ObjectToWorld(res->N[i]));
00267 } else
00268 n = NULL;
00269
00270 break;
00271 }
00272 default: {
00273 std::stringstream ss;
00274 ss << "Unknow subdivision type in a mesh: " << concreteSubdivType;
00275 luxError(LUX_CONSISTENCY, LUX_ERROR, ss.str().c_str());
00276 break;
00277 }
00278 }
00279
00280 mustSubdivide = false;
00281 }
00282
00283 vector<boost::shared_ptr<Primitive> > refinedPrims;
00284 refinedPrims.reserve(ntris + nquads);
00285
00286 MeshTriangleType concreteTriType = triType;
00287 if (triType == TRI_AUTO) {
00288
00289
00290
00291
00292
00293
00294
00295 if (ntris <= 200000)
00296 concreteTriType = TRI_WALD;
00297 else
00298 concreteTriType = TRI_BARY;
00299 }
00300 switch (concreteTriType) {
00301 case TRI_WALD:
00302 for (int i = 0; i < ntris; ++i) {
00303 MeshWaldTriangle *currTri;
00304 if (refinedPrims.size() > 0)
00305 currTri = new MeshWaldTriangle(this, i);
00306 else
00307 currTri = new MeshElemSharedPtr<MeshWaldTriangle>(this, i, thisPtr);
00308 if (!currTri->isDegenerate()) {
00309 boost::shared_ptr<Primitive> o(currTri);
00310 refinedPrims.push_back(o);
00311 } else
00312 delete currTri;
00313 }
00314 break;
00315 case TRI_BARY:
00316 for (int i = 0; i < ntris; ++i) {
00317 MeshBaryTriangle *currTri;
00318 if (refinedPrims.size() > 0)
00319 currTri = new MeshBaryTriangle(this, i);
00320 else
00321 currTri = new MeshElemSharedPtr<MeshBaryTriangle>(this, i, thisPtr);
00322 if (!currTri->isDegenerate()) {
00323 boost::shared_ptr<Primitive> o(currTri);
00324 refinedPrims.push_back(o);
00325 } else
00326 delete currTri;
00327 }
00328 break;
00329 default: {
00330 std::stringstream ss;
00331 ss << "Unknow triangle type in a mesh: " << concreteTriType;
00332 luxError(LUX_CONSISTENCY, LUX_ERROR, ss.str().c_str());
00333 break;
00334 }
00335 }
00336 int numConcreteTris = refinedPrims.size();
00337
00338
00339 switch (quadType) {
00340 case QUAD_QUADRILATERAL:
00341 for (int i = 0; i < nquads; ++i) {
00342 MeshQuadrilateral* currQuad = new MeshQuadrilateral(this, i);
00343 if (!currQuad->isDegenerate()) {
00344 if (refinedPrims.size() > 0) {
00345 boost::shared_ptr<Primitive> o(currQuad);
00346 refinedPrims.push_back(o);
00347 } else {
00348 delete currQuad;
00349 boost::shared_ptr<Primitive> o(
00350 new MeshElemSharedPtr<MeshQuadrilateral>(this, i, thisPtr));
00351 refinedPrims.push_back(o);
00352 }
00353 } else
00354 delete currQuad;
00355 }
00356 break;
00357 default: {
00358 std::stringstream ss;
00359 ss << "Unknow quad type in a mesh: " << quadType;
00360 luxError(LUX_CONSISTENCY, LUX_ERROR, ss.str().c_str());
00361 break;
00362 }
00363 }
00364 int numConcreteQuads = refinedPrims.size() - numConcreteTris;
00365
00366
00367 MeshAccelType concreteAccelType = accelType;
00368 if (accelType == ACCEL_AUTO) {
00369 if (refinedPrims.size() <= 250000)
00370 concreteAccelType = ACCEL_NONE;
00371 else if (refinedPrims.size() <= 500000)
00372 concreteAccelType = ACCEL_KDTREE;
00373 else if (refinedPrims.size() <= 8000000)
00374 concreteAccelType = ACCEL_QBVH;
00375 else
00376 concreteAccelType = ACCEL_GRID;
00377 }
00378
00379
00380 std::stringstream ss;
00381 ss << "Mesh: accel = ";
00382 switch (concreteAccelType) {
00383 case ACCEL_NONE:
00384 ss << "none (global)";
00385 break;
00386 case ACCEL_QBVH:
00387 ss << "qbvh";
00388 break;
00389 case ACCEL_GRID:
00390 ss << "grid";
00391 break;
00392 case ACCEL_BRUTEFORCE:
00393 ss << "bruteforce";
00394 break;
00395 case ACCEL_KDTREE:
00396 ss << "kdtree";
00397 break;
00398 default:
00399 ss << "?";
00400 }
00401 ss << ", triangles = " << numConcreteTris << " ";
00402 switch (concreteTriType) {
00403 case TRI_BARY:
00404 ss << "bary";
00405 break;
00406 case TRI_WALD:
00407 ss << "wald";
00408 break;
00409 default:
00410 ss << "?";
00411 }
00412 ss << ", quads = " << numConcreteQuads << " ";
00413 switch (quadType) {
00414 case QUAD_QUADRILATERAL:
00415 ss << "quadrilateral";
00416 break;
00417 default:
00418 ss << "?";
00419 }
00420 luxError(LUX_NOERROR, LUX_DEBUG, ss.str().c_str());
00421
00422
00423 if (concreteAccelType == ACCEL_NONE) {
00424
00425
00426 const u_int offset = refined.size();
00427 refined.resize(refined.size() + refinedPrims.size());
00428 for(u_int i = 0; i < refinedPrims.size(); ++i)
00429 refined[offset+i].swap(refinedPrims[i]);
00430 } else {
00431 ParamSet paramset;
00432 boost::shared_ptr<Aggregate> accel;
00433 switch (concreteAccelType) {
00434 case ACCEL_KDTREE:
00435 accel = MakeAccelerator("kdtree", refinedPrims, paramset);
00436 break;
00437 case ACCEL_QBVH:
00438 accel = MakeAccelerator("qbvh", refinedPrims, paramset);
00439 break;
00440 case ACCEL_GRID:
00441 accel = MakeAccelerator("grid", refinedPrims, paramset);
00442 break;
00443 case ACCEL_BRUTEFORCE:
00444 accel = MakeAccelerator("bruteforce", refinedPrims, paramset);
00445 break;
00446 default:
00447 std::stringstream ss;
00448 ss << "Unknow accel type in a mesh: " << concreteAccelType;
00449 luxError(LUX_CONSISTENCY, LUX_ERROR, ss.str().c_str());
00450 }
00451 if (refineHints.forSampling)
00452
00453 refined.push_back(boost::shared_ptr<Primitive>(new PrimitiveSet(accel)));
00454 else
00455 refined.push_back(accel);
00456 }
00457 }
00458
00459 static Shape *CreateShape( const Transform &o2w, bool reverseOrientation, const ParamSet ¶ms,
00460 const string& accelTypeStr, const string& triTypeStr,
00461 const int* triIndices, int triIndicesCount,
00462 const float* UV, int UVCount,
00463 const string& subdivSchemeStr, int nSubdivLevels) {
00464
00465 Mesh::MeshAccelType accelType;
00466 if (accelTypeStr == "kdtree") accelType = Mesh::ACCEL_KDTREE;
00467 else if (accelTypeStr == "qbvh") accelType = Mesh::ACCEL_QBVH;
00468 else if (accelTypeStr == "bruteforce") accelType = Mesh::ACCEL_BRUTEFORCE;
00469 else if (accelTypeStr == "grid") accelType = Mesh::ACCEL_GRID;
00470 else if (accelTypeStr == "none") accelType = Mesh::ACCEL_NONE;
00471 else if (accelTypeStr == "auto") accelType = Mesh::ACCEL_AUTO;
00472 else {
00473 std::stringstream ss;
00474 ss << "Acceleration structure type '" << accelTypeStr << "' unknown. Using \"auto\".";
00475 luxError(LUX_BADTOKEN,LUX_WARNING,ss.str().c_str());
00476 accelType = Mesh::ACCEL_AUTO;
00477 }
00478
00479
00480 int npi;
00481 const Point *P = params.FindPoint("P", &npi);
00482
00483
00484 if (UV && (UVCount != npi * 2)) {
00485 luxError(LUX_CONSISTENCY, LUX_ERROR, "Number of \"UV\"s for mesh must match \"P\"s");
00486 UV = NULL;
00487 }
00488 if (!P) return NULL;
00489
00490 int nni;
00491 const Normal *N = params.FindNormal("N", &nni);
00492 if (N && (nni != npi)) {
00493 luxError(LUX_CONSISTENCY, LUX_ERROR, "Number of \"N\"s for mesh must match \"P\"s");
00494 N = NULL;
00495 }
00496
00497
00498 Mesh::MeshTriangleType triType;
00499 if (triTypeStr == "wald") triType = Mesh::TRI_WALD;
00500 else if (triTypeStr == "bary") triType = Mesh::TRI_BARY;
00501 else if (triTypeStr == "auto") triType = Mesh::TRI_AUTO;
00502 else {
00503 std::stringstream ss;
00504 ss << "Triangle type '" << triTypeStr << "' unknown. Using \"auto\".";
00505 luxError(LUX_BADTOKEN,LUX_WARNING,ss.str().c_str());
00506 triType = Mesh::TRI_AUTO;
00507 }
00508
00509 if (triIndices) {
00510 for (int i = 0; i < triIndicesCount; ++i) {
00511 if (triIndices[i] >= npi) {
00512 std::stringstream ss;
00513 ss << "Mesh has out of-bounds triangle vertex index " << triIndices[i] <<
00514 " (" << npi << " \"P\" values were given";
00515 luxError(LUX_CONSISTENCY, LUX_ERROR, ss.str().c_str());
00516 return NULL;
00517 }
00518 }
00519
00520 triIndicesCount /= 3;
00521 } else
00522 triIndicesCount = 0;
00523
00524
00525 Mesh::MeshQuadType quadType;
00526 string quadTypeStr = params.FindOneString("quadtype", "quadrilateral");
00527 if (quadTypeStr == "quadrilateral") quadType = Mesh::QUAD_QUADRILATERAL;
00528 else {
00529 std::stringstream ss;
00530 ss << "Quad type '" << quadTypeStr << "' unknown. Using \"quadrilateral\".";
00531 luxError(LUX_BADTOKEN,LUX_WARNING,ss.str().c_str());
00532 quadType = Mesh::QUAD_QUADRILATERAL;
00533 }
00534
00535 int quadIndicesCount;
00536 const int *quadIndices = params.FindInt("quadindices", &quadIndicesCount);
00537 if (quadIndices) {
00538 for (int i = 0; i < quadIndicesCount; ++i) {
00539 if (quadIndices[i] >= npi) {
00540 std::stringstream ss;
00541 ss << "Mesh has out of-bounds quad vertex index " << quadIndices[i] <<
00542 " (" << npi << " \"P\" values were given";
00543 luxError(LUX_CONSISTENCY, LUX_ERROR, ss.str().c_str());
00544 return NULL;
00545 }
00546 }
00547
00548 quadIndicesCount /= 4;
00549 } else
00550 quadIndicesCount = 0;
00551
00552 if ((!triIndices) && (!quadIndices)) return NULL;
00553
00554
00555 string displacementMapName = params.FindOneString("displacementmap", "");
00556 float displacementMapScale = params.FindOneFloat("dmscale", 0.1f);
00557 float displacementMapOffset = params.FindOneFloat("dmoffset", 0.0f);
00558 bool displacementMapNormalSmooth = params.FindOneBool("dmnormalsmooth", true);
00559 bool displacementMapSharpBoundary = params.FindOneBool("dmsharpboundary", false);
00560
00561 boost::shared_ptr<Texture<float> > displacementMap;
00562 if (displacementMapName != "") {
00563
00564 map<string, boost::shared_ptr<Texture<float> > > *floatTextures = Context::getActiveFloatTextures();
00565
00566 displacementMap = (*floatTextures)[displacementMapName];
00567
00568 if (displacementMap.get() == NULL) {
00569 std::stringstream ss;
00570 ss << "Unknow float texture '" << displacementMapName << "' in a Mesh shape.";
00571 luxError(LUX_SYNTAX, LUX_WARNING, ss.str().c_str());
00572 }
00573 }
00574
00575
00576 Mesh::MeshSubdivType subdivType;
00577 if (subdivSchemeStr == "loop") subdivType = Mesh::SUBDIV_LOOP;
00578 else {
00579 std::stringstream ss;
00580 ss << "Subdivision type '" << subdivSchemeStr << "' unknown. Using \"loop\".";
00581 luxError(LUX_BADTOKEN,LUX_WARNING,ss.str().c_str());
00582 subdivType = Mesh::SUBDIV_LOOP;
00583 }
00584
00585 return new Mesh(o2w, reverseOrientation,
00586 accelType,
00587 npi, P, N, UV,
00588 triType, triIndicesCount, triIndices,
00589 quadType, quadIndicesCount, quadIndices,
00590 subdivType, nSubdivLevels, displacementMap, displacementMapScale, displacementMapOffset,
00591 displacementMapNormalSmooth, displacementMapSharpBoundary);
00592 }
00593
00594 Shape *Mesh::CreateShape(const Transform &o2w, bool reverseOrientation, const ParamSet ¶ms) {
00595 string accelTypeStr = params.FindOneString("acceltype", "auto");
00596
00597 string triTypeStr = params.FindOneString("tritype", "auto");
00598 int triIndicesCount;
00599 const int *triIndices = params.FindInt("triindices", &triIndicesCount);
00600 int uvCoordinatesCount;
00601 const float *uvCoordinates = params.FindFloat("uv", &uvCoordinatesCount);
00602
00603 string subdivscheme = params.FindOneString("subdivscheme", "loop");
00604 int nsubdivlevels = params.FindOneInt("nsubdivlevels", 0);
00605
00606 return ::CreateShape( o2w, reverseOrientation, params, accelTypeStr, triTypeStr,
00607 triIndices, triIndicesCount, uvCoordinates, uvCoordinatesCount,
00608 subdivscheme, nsubdivlevels);
00609 }
00610
00611 static DynamicLoader::RegisterShape<Mesh> r("mesh");
00612
00613 Shape* Mesh::BaryMesh::CreateShape(const Transform &o2w, bool reverseOrientation, const ParamSet ¶ms) {
00614 string accelTypeStr = "auto";
00615 string triTypeStr = "bary";
00616 int indicesCount;
00617 const int* indices = params.FindInt( "indices", &indicesCount );
00618 int uvCoordinatesCount;
00619 const float *uvCoordinates = params.FindFloat("uv", &uvCoordinatesCount);
00620 if( uvCoordinates == NULL ) {
00621 uvCoordinates = params.FindFloat("st", &uvCoordinatesCount);
00622 }
00623 return ::CreateShape( o2w, reverseOrientation, params, accelTypeStr, triTypeStr,
00624 indices, indicesCount, uvCoordinates, uvCoordinatesCount,
00625 "loop", 0);
00626 }
00627
00628 static DynamicLoader::RegisterShape<Mesh::BaryMesh> rbary("barytrianglemesh");
00629
00630 Shape* Mesh::WaldMesh::CreateShape(const Transform &o2w, bool reverseOrientation, const ParamSet ¶ms) {
00631 string accelTypeStr = "auto";
00632 string triTypeStr = "auto";
00633 int indicesCount;
00634 const int* indices = params.FindInt( "indices", &indicesCount );
00635 int uvCoordinatesCount;
00636 const float *uvCoordinates = params.FindFloat("uv", &uvCoordinatesCount);
00637 if( uvCoordinates == NULL ) {
00638 uvCoordinates = params.FindFloat("st", &uvCoordinatesCount);
00639 }
00640 return ::CreateShape( o2w, reverseOrientation, params, accelTypeStr, triTypeStr,
00641 indices, indicesCount, uvCoordinates, uvCoordinatesCount,
00642 "loop", 0);
00643 }
00644
00645 static DynamicLoader::RegisterShape<Mesh::WaldMesh> rwald1("waldtrianglemesh");
00646 static DynamicLoader::RegisterShape<Mesh::WaldMesh> rwald2("trianglemesh");
00647
00648 Shape* Mesh::LoopMesh::CreateShape(const Transform &o2w, bool reverseOrientation, const ParamSet ¶ms) {
00649 string accelTypeStr = "auto";
00650 string triTypeStr = "auto";
00651
00652 int indicesCount;
00653 const int* indices = params.FindInt( "indices", &indicesCount );
00654 int uvCoordinatesCount;
00655 const float *uvCoordinates = params.FindFloat("uv", &uvCoordinatesCount);
00656 if( uvCoordinates == NULL ) {
00657 uvCoordinates = params.FindFloat("st", &uvCoordinatesCount);
00658 }
00659
00660 string subdivscheme = params.FindOneString("scheme", "loop");
00661 int nsubdivlevels = params.FindOneInt("nlevels", 3);
00662
00663 return ::CreateShape( o2w, reverseOrientation, params, accelTypeStr, triTypeStr,
00664 indices, indicesCount, uvCoordinates, uvCoordinatesCount,
00665 subdivscheme, nsubdivlevels);
00666 }
00667
00668 static DynamicLoader::RegisterShape<Mesh::LoopMesh> rloop("loopsubdiv");