diff --git a/include/osgUtil/TangentSpaceGenerator b/include/osgUtil/TangentSpaceGenerator index f158fac0a..05936daea 100644 --- a/include/osgUtil/TangentSpaceGenerator +++ b/include/osgUtil/TangentSpaceGenerator @@ -40,7 +40,7 @@ public: TangentSpaceGenerator(); TangentSpaceGenerator(const TangentSpaceGenerator ©, const osg::CopyOp ©op = osg::CopyOp::SHALLOW_COPY); - void generate(osg::Geometry *geo, int normal_map_tex_unit = 0); + void generate(osg::Geometry *geo, int normal_map_tex_unit = 0, bool use_indices = false); inline osg::Vec4Array *getTangentArray() { return T_.get(); } inline const osg::Vec4Array *getTangentArray() const { return T_.get(); } @@ -55,18 +55,71 @@ public: inline void setBinormalArray(osg::Vec4Array *array) { B_ = array; } inline osg::IndexArray *getIndices() { return indices_.get(); } + protected: + virtual ~TangentSpaceGenerator() {} TangentSpaceGenerator &operator=(const TangentSpaceGenerator &) { return *this; } - void compute_basis_vectors(osg::PrimitiveSet *pset, - const osg::Array *vx, - const osg::Array *nx, - const osg::Array *tx, - const osg::IndexArray *vix, - const osg::IndexArray *nix, - const osg::IndexArray *tix, - int iA, int iB, int iC); + // Base class for computing basis vectors + class BasisVectorsComputer : public osg::Referenced + { + public: + explicit BasisVectorsComputer(TangentSpaceGenerator* base) : base_( base ) {} + + virtual void compute(osg::PrimitiveSet *pset, + const osg::Array *vx, + const osg::Array *nx, + const osg::Array *tx, + const osg::IndexArray *vix, + const osg::IndexArray *nix, + const osg::IndexArray *tix, + int iA, int iB, int iC) = 0; + + protected: + virtual ~BasisVectorsComputer() {} + BasisVectorsComputer(const TangentSpaceGenerator ©, const osg::CopyOp ©op); + + TangentSpaceGenerator* base_; + }; + + // Class for computing basis vectors without using indices + class VectorsComputerNoIndices : public BasisVectorsComputer + { + public: + explicit VectorsComputerNoIndices(TangentSpaceGenerator* base) : BasisVectorsComputer( base ) {} + + void compute(osg::PrimitiveSet *pset, + const osg::Array *vx, + const osg::Array *nx, + const osg::Array *tx, + const osg::IndexArray *vix, + const osg::IndexArray *nix, + const osg::IndexArray *tix, + int iA, int iB, int iC); + + protected: + virtual ~VectorsComputerNoIndices() {} + }; + + // Class for computing basis vectors using indices + class VectorsComputerUsingIndices : public BasisVectorsComputer + { + public: + explicit VectorsComputerUsingIndices(TangentSpaceGenerator* base) : BasisVectorsComputer( base ) {} + + void compute(osg::PrimitiveSet *pset, + const osg::Array *vx, + const osg::Array *nx, + const osg::Array *tx, + const osg::IndexArray *vix, + const osg::IndexArray *nix, + const osg::IndexArray *tix, + int iA, int iB, int iC); + + protected: + virtual ~VectorsComputerUsingIndices() {} + }; private: osg::ref_ptr T_; diff --git a/src/osgUtil/TangentSpaceGenerator.cpp b/src/osgUtil/TangentSpaceGenerator.cpp index 264283d3d..595c2296a 100644 --- a/src/osgUtil/TangentSpaceGenerator.cpp +++ b/src/osgUtil/TangentSpaceGenerator.cpp @@ -1,6 +1,7 @@ #include #include +#include using namespace osgUtil; @@ -20,7 +21,7 @@ TangentSpaceGenerator::TangentSpaceGenerator(const TangentSpaceGenerator ©, { } -void TangentSpaceGenerator::generate(osg::Geometry *geo, int normal_map_tex_unit) +void TangentSpaceGenerator::generate(osg::Geometry *geo, int normal_map_tex_unit, bool use_indices) { const osg::Array *vx = geo->getVertexArray(); const osg::IndexArray *vix = geo->getVertexIndices(); @@ -31,6 +32,13 @@ void TangentSpaceGenerator::generate(osg::Geometry *geo, int normal_map_tex_unit if (!vx || !tx) return; + + osg::ref_ptr computer; + if (use_indices) + computer = new VectorsComputerUsingIndices(this); + else + computer = new VectorsComputerNoIndices(this); + unsigned int vertex_count = vx->getNumElements(); if (geo->getVertexIndices() == NULL) { T_->assign(vertex_count, osg::Vec4()); @@ -59,14 +67,14 @@ void TangentSpaceGenerator::generate(osg::Geometry *geo, int normal_map_tex_unit case osg::PrimitiveSet::TRIANGLES: for (i=0; icompute(pset, vx, nx, tx, vix, nix, tix, i, i+1, i+2); } break; case osg::PrimitiveSet::QUADS: for (i=0; icompute(pset, vx, nx, tx, vix, nix, tix, i, i+1, i+2); + computer->compute(pset, vx, nx, tx, vix, nix, tix, i+2, i+3, i); } break; @@ -78,9 +86,9 @@ void TangentSpaceGenerator::generate(osg::Geometry *geo, int normal_map_tex_unit unsigned iN = static_cast(*pi-2); for (i=0; icompute(pset, vx, nx, tx, vix, nix, tix, j, j+1, j+2); } else { - compute_basis_vectors(pset, vx, nx, tx, vix, nix, tix, j+1, j, j+2); + computer->compute(pset, vx, nx, tx, vix, nix, tix, j+1, j, j+2); } } j += 2; @@ -88,9 +96,9 @@ void TangentSpaceGenerator::generate(osg::Geometry *geo, int normal_map_tex_unit } else { for (i=0; icompute(pset, vx, nx, tx, vix, nix, tix, i, i+1, i+2); } else { - compute_basis_vectors(pset, vx, nx, tx, vix, nix, tix, i+1, i, i+2); + computer->compute(pset, vx, nx, tx, vix, nix, tix, i+1, i, i+2); } } } @@ -103,13 +111,13 @@ void TangentSpaceGenerator::generate(osg::Geometry *geo, int normal_map_tex_unit for (osg::DrawArrayLengths::const_iterator pi=dal->begin(); pi!=dal->end(); ++pi) { unsigned iN = static_cast(*pi-2); for (i=0; icompute(pset, vx, nx, tx, vix, nix, tix, 0, j+1, j+2); } j += 2; } } else { for (i=0; icompute(pset, vx, nx, tx, vix, nix, tix, 2, i+1, i+2); } } break; @@ -151,471 +159,467 @@ void TangentSpaceGenerator::generate(osg::Geometry *geo, int normal_map_tex_unit * version of each (different indices for each one?) */ } -#if 1 // Original compute_basis_vectors implementation - void TangentSpaceGenerator::compute_basis_vectors(osg::PrimitiveSet* pset, - const osg::Array* vx, - const osg::Array* nx, - const osg::Array* tx, - const osg::IndexArray* /*vix*/, - const osg::IndexArray* /*nix*/, - const osg::IndexArray* /*tix*/, - int iA, int iB, int iC) +void TangentSpaceGenerator::VectorsComputerNoIndices::compute(osg::PrimitiveSet *pset, + const osg::Array* vx, + const osg::Array* nx, + const osg::Array* tx, + const osg::IndexArray* /*vix*/, + const osg::IndexArray* /*nix*/, + const osg::IndexArray* /*tix*/, + int iA, int iB, int iC) +{ + iA = pset->index(iA); + iB = pset->index(iB); + iC = pset->index(iC); + + osg::Vec3 P1; + osg::Vec3 P2; + osg::Vec3 P3; + + int i; // VC6 doesn't like for-scoped variables + + switch (vx->getType()) { - iA = pset->index(iA); - iB = pset->index(iB); - iC = pset->index(iC); + case osg::Array::Vec2ArrayType: + for (i=0; i<2; ++i) { + P1.ptr()[i] = static_cast(*vx)[iA].ptr()[i]; + P2.ptr()[i] = static_cast(*vx)[iB].ptr()[i]; + P3.ptr()[i] = static_cast(*vx)[iC].ptr()[i]; + } + break; - osg::Vec3 P1; - osg::Vec3 P2; - osg::Vec3 P3; + case osg::Array::Vec3ArrayType: + P1 = static_cast(*vx)[iA]; + P2 = static_cast(*vx)[iB]; + P3 = static_cast(*vx)[iC]; + break; - int i; // VC6 doesn't like for-scoped variables + case osg::Array::Vec4ArrayType: + for (i=0; i<3; ++i) { + P1.ptr()[i] = static_cast(*vx)[iA].ptr()[i]; + P2.ptr()[i] = static_cast(*vx)[iB].ptr()[i]; + P3.ptr()[i] = static_cast(*vx)[iC].ptr()[i]; + } + break; - switch (vx->getType()) + default: + osg::notify(osg::WARN) << "Warning: TangentSpaceGenerator: vertex array must be Vec2Array, Vec3Array or Vec4Array" << std::endl; + } + + osg::Vec3 N1; + osg::Vec3 N2; + osg::Vec3 N3; + + if(nx) + { + switch (nx->getType()) { - case osg::Array::Vec2ArrayType: - for (i=0; i<2; ++i) { - P1.ptr()[i] = static_cast(*vx)[iA].ptr()[i]; - P2.ptr()[i] = static_cast(*vx)[iB].ptr()[i]; - P3.ptr()[i] = static_cast(*vx)[iC].ptr()[i]; - } - break; - - case osg::Array::Vec3ArrayType: - P1 = static_cast(*vx)[iA]; - P2 = static_cast(*vx)[iB]; - P3 = static_cast(*vx)[iC]; - break; - - case osg::Array::Vec4ArrayType: - for (i=0; i<3; ++i) { - P1.ptr()[i] = static_cast(*vx)[iA].ptr()[i]; - P2.ptr()[i] = static_cast(*vx)[iB].ptr()[i]; - P3.ptr()[i] = static_cast(*vx)[iC].ptr()[i]; - } - break; - - default: - osg::notify(osg::WARN) << "Warning: TangentSpaceGenerator: vertex array must be Vec2Array, Vec3Array or Vec4Array" << std::endl; - } - - osg::Vec3 N1; - osg::Vec3 N2; - osg::Vec3 N3; - - if(nx) - { - switch (nx->getType()) - { - case osg::Array::Vec2ArrayType: - for (i=0; i<2; ++i) { - N1.ptr()[i] = static_cast(*nx)[iA].ptr()[i]; - N2.ptr()[i] = static_cast(*nx)[iB].ptr()[i]; - N3.ptr()[i] = static_cast(*nx)[iC].ptr()[i]; - } - break; - - case osg::Array::Vec3ArrayType: - N1 = static_cast(*nx)[iA]; - N2 = static_cast(*nx)[iB]; - N3 = static_cast(*nx)[iC]; - break; - - case osg::Array::Vec4ArrayType: - for (i=0; i<3; ++i) { - N1.ptr()[i] = static_cast(*nx)[iA].ptr()[i]; - N2.ptr()[i] = static_cast(*nx)[iB].ptr()[i]; - N3.ptr()[i] = static_cast(*nx)[iC].ptr()[i]; - } - break; - - default: - osg::notify(osg::WARN) << "Warning: TangentSpaceGenerator: normal array must be Vec2Array, Vec3Array or Vec4Array" << std::endl; + case osg::Array::Vec2ArrayType: + for (i=0; i<2; ++i) { + N1.ptr()[i] = static_cast(*nx)[iA].ptr()[i]; + N2.ptr()[i] = static_cast(*nx)[iB].ptr()[i]; + N3.ptr()[i] = static_cast(*nx)[iC].ptr()[i]; } - } + break; - osg::Vec2 uv1; - osg::Vec2 uv2; - osg::Vec2 uv3; + case osg::Array::Vec3ArrayType: + N1 = static_cast(*nx)[iA]; + N2 = static_cast(*nx)[iB]; + N3 = static_cast(*nx)[iC]; + break; - switch (tx->getType()) - { - case osg::Array::Vec2ArrayType: - uv1 = static_cast(*tx)[iA]; - uv2 = static_cast(*tx)[iB]; - uv3 = static_cast(*tx)[iC]; - break; - - case osg::Array::Vec3ArrayType: - for (i=0; i<2; ++i) { - uv1.ptr()[i] = static_cast(*tx)[iA].ptr()[i]; - uv2.ptr()[i] = static_cast(*tx)[iB].ptr()[i]; - uv3.ptr()[i] = static_cast(*tx)[iC].ptr()[i]; - } - break; - - case osg::Array::Vec4ArrayType: - for (i=0; i<2; ++i) { - uv1.ptr()[i] = static_cast(*tx)[iA].ptr()[i]; - uv2.ptr()[i] = static_cast(*tx)[iB].ptr()[i]; - uv3.ptr()[i] = static_cast(*tx)[iC].ptr()[i]; - } - break; - - default: - osg::notify(osg::WARN) << "Warning: TangentSpaceGenerator: texture coord array must be Vec2Array, Vec3Array or Vec4Array" << std::endl; - } - - if(nx){ - osg::Vec3 V, T1, T2, T3, B1, B2, B3; - - V = osg::Vec3(P2.x() - P1.x(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ - osg::Vec3(P3.x() - P1.x(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); - if (V.x() != 0) { - V.normalize(); - T1.x() += -V.y() / V.x(); - B1.x() += -V.z() / V.x(); - T2.x() += -V.y() / V.x(); - B2.x() += -V.z() / V.x(); - T3.x() += -V.y() / V.x(); - B3.x() += -V.z() / V.x(); + case osg::Array::Vec4ArrayType: + for (i=0; i<3; ++i) { + N1.ptr()[i] = static_cast(*nx)[iA].ptr()[i]; + N2.ptr()[i] = static_cast(*nx)[iB].ptr()[i]; + N3.ptr()[i] = static_cast(*nx)[iC].ptr()[i]; } + break; - V = osg::Vec3(P2.y() - P1.y(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ - osg::Vec3(P3.y() - P1.y(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); - if (V.x() != 0) { - V.normalize(); - T1.y() += -V.y() / V.x(); - B1.y() += -V.z() / V.x(); - T2.y() += -V.y() / V.x(); - B2.y() += -V.z() / V.x(); - T3.y() += -V.y() / V.x(); - B3.y() += -V.z() / V.x(); - } - - V = osg::Vec3(P2.z() - P1.z(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ - osg::Vec3(P3.z() - P1.z(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); - if (V.x() != 0) { - V.normalize(); - T1.z() += -V.y() / V.x(); - B1.z() += -V.z() / V.x(); - T2.z() += -V.y() / V.x(); - B2.z() += -V.z() / V.x(); - T3.z() += -V.y() / V.x(); - B3.z() += -V.z() / V.x(); - } - - osg::Vec3 tempvec; - tempvec = N1 ^ T1; - (*T_)[iA] = osg::Vec4(tempvec ^ N1, 0); - tempvec = B1 ^ N1; - (*B_)[iA] = osg::Vec4(N1 ^ tempvec, 0); - tempvec = N2 ^ T2; - (*T_)[iB] = osg::Vec4(tempvec ^ N2, 0); - tempvec = B2 ^ N2; - (*B_)[iB] = osg::Vec4(N2 ^ tempvec, 0); - tempvec = N3 ^ T3; - (*T_)[iC] = osg::Vec4(tempvec ^ N3, 0); - tempvec = B3 ^ N3; - (*B_)[iC] = osg::Vec4(N3 ^ tempvec, 0); - - (*N_)[iA] += osg::Vec4(N1, 0); - (*N_)[iB] += osg::Vec4(N2, 0); - (*N_)[iC] += osg::Vec4(N3, 0); - } - else{ - osg::Vec3 face_normal = (P2 - P1) ^ (P3 - P1); - - osg::Vec3 V; - - V = osg::Vec3(P2.x() - P1.x(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ - osg::Vec3(P3.x() - P1.x(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); - if (V.x() != 0) { - V.normalize(); - (*T_)[iA].x() += -V.y() / V.x(); - (*B_)[iA].x() += -V.z() / V.x(); - (*T_)[iB].x() += -V.y() / V.x(); - (*B_)[iB].x() += -V.z() / V.x(); - (*T_)[iC].x() += -V.y() / V.x(); - (*B_)[iC].x() += -V.z() / V.x(); - } - - V = osg::Vec3(P2.y() - P1.y(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ - osg::Vec3(P3.y() - P1.y(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); - if (V.x() != 0) { - V.normalize(); - (*T_)[iA].y() += -V.y() / V.x(); - (*B_)[iA].y() += -V.z() / V.x(); - (*T_)[iB].y() += -V.y() / V.x(); - (*B_)[iB].y() += -V.z() / V.x(); - (*T_)[iC].y() += -V.y() / V.x(); - (*B_)[iC].y() += -V.z() / V.x(); - } - - V = osg::Vec3(P2.z() - P1.z(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ - osg::Vec3(P3.z() - P1.z(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); - if (V.x() != 0) { - V.normalize(); - (*T_)[iA].z() += -V.y() / V.x(); - (*B_)[iA].z() += -V.z() / V.x(); - (*T_)[iB].z() += -V.y() / V.x(); - (*B_)[iB].z() += -V.z() / V.x(); - (*T_)[iC].z() += -V.y() / V.x(); - (*B_)[iC].z() += -V.z() / V.x(); - } - - (*N_)[iA] += osg::Vec4(face_normal, 0); - (*N_)[iB] += osg::Vec4(face_normal, 0); - (*N_)[iC] += osg::Vec4(face_normal, 0); + default: + osg::notify(osg::WARN) << "Warning: TangentSpaceGenerator: normal array must be Vec2Array, Vec3Array or Vec4Array" << std::endl; } } -#else + osg::Vec2 uv1; + osg::Vec2 uv2; + osg::Vec2 uv3; - // Ruben's new code, supporting index arrays - void TangentSpaceGenerator::compute_basis_vectors(osg::PrimitiveSet *pset, - const osg::Array *vx, - const osg::Array *nx, - const osg::Array *tx, - const osg::IndexArray *vix, - const osg::IndexArray *nix, - const osg::IndexArray *tix, - int iA, int iB, int iC) + switch (tx->getType()) { - int v1 = pset->index(iA); - int v2 = pset->index(iB); - int v3 = pset->index(iC); - int viA = v1; - int viB = v2; - int viC = v3; + case osg::Array::Vec2ArrayType: + uv1 = static_cast(*tx)[iA]; + uv2 = static_cast(*tx)[iB]; + uv3 = static_cast(*tx)[iC]; + break; - if (vix != NULL) { - viA = vix->index(v1); - viB = vix->index(v2); - viC = vix->index(v3); + case osg::Array::Vec3ArrayType: + for (i=0; i<2; ++i) { + uv1.ptr()[i] = static_cast(*tx)[iA].ptr()[i]; + uv2.ptr()[i] = static_cast(*tx)[iB].ptr()[i]; + uv3.ptr()[i] = static_cast(*tx)[iC].ptr()[i]; } - int niA = viA; - int niB = viA; - int niC = viA; - int tiA = viA; - int tiB = viA; - int tiC = viA; - if (nix != NULL) { - niA = nix->index(v1); - niB = nix->index(v2); - niC = nix->index(v3); + break; + + case osg::Array::Vec4ArrayType: + for (i=0; i<2; ++i) { + uv1.ptr()[i] = static_cast(*tx)[iA].ptr()[i]; + uv2.ptr()[i] = static_cast(*tx)[iB].ptr()[i]; + uv3.ptr()[i] = static_cast(*tx)[iC].ptr()[i]; } - if (tix != NULL) { - tiA = tix->index(v1); - tiB = tix->index(v2); - tiC = tix->index(v3); + break; + + default: + osg::notify(osg::WARN) << "Warning: TangentSpaceGenerator: texture coord array must be Vec2Array, Vec3Array or Vec4Array" << std::endl; + } + + if(nx){ + osg::Vec3 V, T1, T2, T3, B1, B2, B3; + + V = osg::Vec3(P2.x() - P1.x(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ + osg::Vec3(P3.x() - P1.x(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); + if (V.x() != 0) { + V.normalize(); + T1.x() += -V.y() / V.x(); + B1.x() += -V.z() / V.x(); + T2.x() += -V.y() / V.x(); + B2.x() += -V.z() / V.x(); + T3.x() += -V.y() / V.x(); + B3.x() += -V.z() / V.x(); } - osg::Vec3 P1; - osg::Vec3 P2; - osg::Vec3 P3; + V = osg::Vec3(P2.y() - P1.y(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ + osg::Vec3(P3.y() - P1.y(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); + if (V.x() != 0) { + V.normalize(); + T1.y() += -V.y() / V.x(); + B1.y() += -V.z() / V.x(); + T2.y() += -V.y() / V.x(); + B2.y() += -V.z() / V.x(); + T3.y() += -V.y() / V.x(); + B3.y() += -V.z() / V.x(); + } - int i; // VC6 doesn't like for-scoped variables + V = osg::Vec3(P2.z() - P1.z(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ + osg::Vec3(P3.z() - P1.z(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); + if (V.x() != 0) { + V.normalize(); + T1.z() += -V.y() / V.x(); + B1.z() += -V.z() / V.x(); + T2.z() += -V.y() / V.x(); + B2.z() += -V.z() / V.x(); + T3.z() += -V.y() / V.x(); + B3.z() += -V.z() / V.x(); + } - switch (vx->getType()) + osg::Vec3 tempvec; + tempvec = N1 ^ T1; + (*base_->T_)[iA] = osg::Vec4(tempvec ^ N1, 0); + tempvec = B1 ^ N1; + (*base_->B_)[iA] = osg::Vec4(N1 ^ tempvec, 0); + tempvec = N2 ^ T2; + (*base_->T_)[iB] = osg::Vec4(tempvec ^ N2, 0); + tempvec = B2 ^ N2; + (*base_->B_)[iB] = osg::Vec4(N2 ^ tempvec, 0); + tempvec = N3 ^ T3; + (*base_->T_)[iC] = osg::Vec4(tempvec ^ N3, 0); + tempvec = B3 ^ N3; + (*base_->B_)[iC] = osg::Vec4(N3 ^ tempvec, 0); + + (*base_->N_)[iA] += osg::Vec4(N1, 0); + (*base_->N_)[iB] += osg::Vec4(N2, 0); + (*base_->N_)[iC] += osg::Vec4(N3, 0); + } + else{ + osg::Vec3 face_normal = (P2 - P1) ^ (P3 - P1); + + osg::Vec3 V; + + V = osg::Vec3(P2.x() - P1.x(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ + osg::Vec3(P3.x() - P1.x(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); + if (V.x() != 0) { + V.normalize(); + (*base_->T_)[iA].x() += -V.y() / V.x(); + (*base_->B_)[iA].x() += -V.z() / V.x(); + (*base_->T_)[iB].x() += -V.y() / V.x(); + (*base_->B_)[iB].x() += -V.z() / V.x(); + (*base_->T_)[iC].x() += -V.y() / V.x(); + (*base_->B_)[iC].x() += -V.z() / V.x(); + } + + V = osg::Vec3(P2.y() - P1.y(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ + osg::Vec3(P3.y() - P1.y(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); + if (V.x() != 0) { + V.normalize(); + (*base_->T_)[iA].y() += -V.y() / V.x(); + (*base_->B_)[iA].y() += -V.z() / V.x(); + (*base_->T_)[iB].y() += -V.y() / V.x(); + (*base_->B_)[iB].y() += -V.z() / V.x(); + (*base_->T_)[iC].y() += -V.y() / V.x(); + (*base_->B_)[iC].y() += -V.z() / V.x(); + } + + V = osg::Vec3(P2.z() - P1.z(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ + osg::Vec3(P3.z() - P1.z(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); + if (V.x() != 0) { + V.normalize(); + (*base_->T_)[iA].z() += -V.y() / V.x(); + (*base_->B_)[iA].z() += -V.z() / V.x(); + (*base_->T_)[iB].z() += -V.y() / V.x(); + (*base_->B_)[iB].z() += -V.z() / V.x(); + (*base_->T_)[iC].z() += -V.y() / V.x(); + (*base_->B_)[iC].z() += -V.z() / V.x(); + } + + (*base_->N_)[iA] += osg::Vec4(face_normal, 0); + (*base_->N_)[iB] += osg::Vec4(face_normal, 0); + (*base_->N_)[iC] += osg::Vec4(face_normal, 0); + } +} + +// This method is the original code of Ruben +void TangentSpaceGenerator::VectorsComputerUsingIndices::compute(osg::PrimitiveSet *pset, + const osg::Array *vx, + const osg::Array *nx, + const osg::Array *tx, + const osg::IndexArray *vix, + const osg::IndexArray *nix, + const osg::IndexArray *tix, + int iA, int iB, int iC) +{ + int v1 = pset->index(iA); + int v2 = pset->index(iB); + int v3 = pset->index(iC); + int viA = v1; + int viB = v2; + int viC = v3; + + if (vix != NULL) { + viA = vix->index(v1); + viB = vix->index(v2); + viC = vix->index(v3); + } + int niA = viA; + int niB = viA; + int niC = viA; + int tiA = viA; + int tiB = viA; + int tiC = viA; + if (nix != NULL) { + niA = nix->index(v1); + niB = nix->index(v2); + niC = nix->index(v3); + } + if (tix != NULL) { + tiA = tix->index(v1); + tiB = tix->index(v2); + tiC = tix->index(v3); + } + + osg::Vec3 P1; + osg::Vec3 P2; + osg::Vec3 P3; + + int i; // VC6 doesn't like for-scoped variables + + switch (vx->getType()) + { + case osg::Array::Vec2ArrayType: + for (i=0; i<2; ++i) { + P1.ptr()[i] = static_cast(*vx)[viA].ptr()[i]; + P2.ptr()[i] = static_cast(*vx)[viB].ptr()[i]; + P3.ptr()[i] = static_cast(*vx)[viC].ptr()[i]; + } + break; + + case osg::Array::Vec3ArrayType: + P1 = static_cast(*vx)[viA]; + P2 = static_cast(*vx)[viB]; + P3 = static_cast(*vx)[viC]; + break; + + case osg::Array::Vec4ArrayType: + for (i=0; i<3; ++i) { + P1.ptr()[i] = static_cast(*vx)[viA].ptr()[i]; + P2.ptr()[i] = static_cast(*vx)[viB].ptr()[i]; + P3.ptr()[i] = static_cast(*vx)[viC].ptr()[i]; + } + break; + + default: + osg::notify(osg::WARN) << "Warning: TangentSpaceGenerator: vertex array must be Vec2Array, Vec3Array or Vec4Array" << std::endl; + } + + osg::Vec3 N1; + osg::Vec3 N2; + osg::Vec3 N3; + + if(nx) + { + switch (nx->getType()) { - case osg::Array::Vec2ArrayType: - for (i=0; i<2; ++i) { - P1.ptr()[i] = static_cast(*vx)[viA].ptr()[i]; - P2.ptr()[i] = static_cast(*vx)[viB].ptr()[i]; - P3.ptr()[i] = static_cast(*vx)[viC].ptr()[i]; - } - break; - - case osg::Array::Vec3ArrayType: - P1 = static_cast(*vx)[viA]; - P2 = static_cast(*vx)[viB]; - P3 = static_cast(*vx)[viC]; - break; - - case osg::Array::Vec4ArrayType: - for (i=0; i<3; ++i) { - P1.ptr()[i] = static_cast(*vx)[viA].ptr()[i]; - P2.ptr()[i] = static_cast(*vx)[viB].ptr()[i]; - P3.ptr()[i] = static_cast(*vx)[viC].ptr()[i]; - } - break; - - default: - osg::notify(osg::WARN) << "Warning: TangentSpaceGenerator: vertex array must be Vec2Array, Vec3Array or Vec4Array" << std::endl; - } - - osg::Vec3 N1; - osg::Vec3 N2; - osg::Vec3 N3; - - if(nx) - { - switch (nx->getType()) - { - case osg::Array::Vec2ArrayType: - for (i=0; i<2; ++i) { - N1.ptr()[i] = static_cast(*nx)[niA].ptr()[i]; - N2.ptr()[i] = static_cast(*nx)[niB].ptr()[i]; - N3.ptr()[i] = static_cast(*nx)[niC].ptr()[i]; - } - break; - - case osg::Array::Vec3ArrayType: - N1 = static_cast(*nx)[niA]; - N2 = static_cast(*nx)[niB]; - N3 = static_cast(*nx)[niC]; - break; - - case osg::Array::Vec4ArrayType: - for (i=0; i<3; ++i) { - N1.ptr()[i] = static_cast(*nx)[niA].ptr()[i]; - N2.ptr()[i] = static_cast(*nx)[niB].ptr()[i]; - N3.ptr()[i] = static_cast(*nx)[niC].ptr()[i]; - } - break; - - default: - osg::notify(osg::WARN) << "Warning: TangentSpaceGenerator: normal array must be Vec2Array, Vec3Array or Vec4Array" << std::endl; + case osg::Array::Vec2ArrayType: + for (i=0; i<2; ++i) { + N1.ptr()[i] = static_cast(*nx)[niA].ptr()[i]; + N2.ptr()[i] = static_cast(*nx)[niB].ptr()[i]; + N3.ptr()[i] = static_cast(*nx)[niC].ptr()[i]; } - } + break; - osg::Vec2 uv1; - osg::Vec2 uv2; - osg::Vec2 uv3; + case osg::Array::Vec3ArrayType: + N1 = static_cast(*nx)[niA]; + N2 = static_cast(*nx)[niB]; + N3 = static_cast(*nx)[niC]; + break; - switch (tx->getType()) - { - case osg::Array::Vec2ArrayType: - uv1 = static_cast(*tx)[tiA]; - uv2 = static_cast(*tx)[tiB]; - uv3 = static_cast(*tx)[tiC]; - break; - - case osg::Array::Vec3ArrayType: - for (i=0; i<2; ++i) { - uv1.ptr()[i] = static_cast(*tx)[tiA].ptr()[i]; - uv2.ptr()[i] = static_cast(*tx)[tiB].ptr()[i]; - uv3.ptr()[i] = static_cast(*tx)[tiC].ptr()[i]; - } - break; - - case osg::Array::Vec4ArrayType: - for (i=0; i<2; ++i) { - uv1.ptr()[i] = static_cast(*tx)[tiA].ptr()[i]; - uv2.ptr()[i] = static_cast(*tx)[tiB].ptr()[i]; - uv3.ptr()[i] = static_cast(*tx)[tiC].ptr()[i]; - } - break; - - default: - osg::notify(osg::WARN) << "Warning: TangentSpaceGenerator::compute_basis_vectors(,,,) texture coord array must be Vec2Array, Vec3Array or Vec4Array" << std::endl; - } - - if (nx) - { - osg::Vec3 V, T1, T2, T3, B1, B2, B3; - - V = osg::Vec3(P2.x() - P1.x(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ - osg::Vec3(P3.x() - P1.x(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); - if (V.x() != 0) { - V.normalize(); - T1.x() = -V.y() / V.x(); - B1.x() = -V.z() / V.x(); - T2.x() = -V.y() / V.x(); - B2.x() = -V.z() / V.x(); - T3.x() = -V.y() / V.x(); - B3.x() = -V.z() / V.x(); - } else { - osg::notify(osg::NOTICE)<<"Bu!" << uv1 << " || " << uv2 << " || " << uv3 << std::endl; + case osg::Array::Vec4ArrayType: + for (i=0; i<3; ++i) { + N1.ptr()[i] = static_cast(*nx)[niA].ptr()[i]; + N2.ptr()[i] = static_cast(*nx)[niB].ptr()[i]; + N3.ptr()[i] = static_cast(*nx)[niC].ptr()[i]; } + break; - V = osg::Vec3(P2.y() - P1.y(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ - osg::Vec3(P3.y() - P1.y(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); - if (V.x() != 0) { - V.normalize(); - T1.y() = -V.y() / V.x(); - B1.y() = -V.z() / V.x(); - T2.y() = -V.y() / V.x(); - B2.y() = -V.z() / V.x(); - T3.y() = -V.y() / V.x(); - B3.y() = -V.z() / V.x(); - } - - V = osg::Vec3(P2.z() - P1.z(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ - osg::Vec3(P3.z() - P1.z(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); - if (V.x() != 0) { - V.normalize(); - T1.z() = -V.y() / V.x(); - B1.z() = -V.z() / V.x(); - T2.z() = -V.y() / V.x(); - B2.z() = -V.z() / V.x(); - T3.z() = -V.y() / V.x(); - B3.z() = -V.z() / V.x(); - } - - (*T_)[v1] = osg::Vec4(T1, 0); - (*B_)[v1] = osg::Vec4(B1, 0); - (*T_)[v2] = osg::Vec4(T2, 0); - (*B_)[v2] = osg::Vec4(B2, 0); - (*T_)[v3] = osg::Vec4(T3, 0); - (*B_)[v3] = osg::Vec4(B3, 0); - - (*N_)[v1] += osg::Vec4(N1, 0); - (*N_)[v2] += osg::Vec4(N2, 0); - (*N_)[v3] += osg::Vec4(N3, 0); - - } - else{ - osg::Vec3 face_normal = (P2 - P1) ^ (P3 - P1); - - osg::Vec3 V; - - V = osg::Vec3(P2.x() - P1.x(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ - osg::Vec3(P3.x() - P1.x(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); - if (V.x() != 0) { - V.normalize(); - (*T_)[v1].x() += -V.y() / V.x(); - (*B_)[v1].x() += -V.z() / V.x(); - (*T_)[v2].x() += -V.y() / V.x(); - (*B_)[v2].x() += -V.z() / V.x(); - (*T_)[v3].x() += -V.y() / V.x(); - (*B_)[v3].x() += -V.z() / V.x(); - } - - V = osg::Vec3(P2.y() - P1.y(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ - osg::Vec3(P3.y() - P1.y(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); - if (V.x() != 0) { - V.normalize(); - (*T_)[v1].y() += -V.y() / V.x(); - (*B_)[v1].y() += -V.z() / V.x(); - (*T_)[v2].y() += -V.y() / V.x(); - (*B_)[v2].y() += -V.z() / V.x(); - (*T_)[v3].y() += -V.y() / V.x(); - (*B_)[v3].y() += -V.z() / V.x(); - } - - V = osg::Vec3(P2.z() - P1.z(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ - osg::Vec3(P3.z() - P1.z(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); - if (V.x() != 0) { - V.normalize(); - (*T_)[v1].z() += -V.y() / V.x(); - (*B_)[v1].z() += -V.z() / V.x(); - (*T_)[v2].z() += -V.y() / V.x(); - (*B_)[v2].z() += -V.z() / V.x(); - (*T_)[v3].z() += -V.y() / V.x(); - (*B_)[v3].z() += -V.z() / V.x(); - } - - (*N_)[v1] += osg::Vec4(face_normal, 0); - (*N_)[v2] += osg::Vec4(face_normal, 0); - (*N_)[v3] += osg::Vec4(face_normal, 0); - } - if ( (*B_)[v1].length() == 0 || (*B_)[v2].length() == 0 || (*B_)[v3].length() == 0) { - osg::notify(osg::WARN) << "WARNING: zero binormal/s!" << std::endl; - osg::notify(osg::WARN) << " " << P1 << "|" << P2 << "|" << P3 << std::endl; - osg::notify(osg::WARN) << " " << iA << "|" << iB << "|" << iC << std::endl; + default: + osg::notify(osg::WARN) << "Warning: TangentSpaceGenerator: normal array must be Vec2Array, Vec3Array or Vec4Array" << std::endl; } } -#endif + + osg::Vec2 uv1; + osg::Vec2 uv2; + osg::Vec2 uv3; + + switch (tx->getType()) + { + case osg::Array::Vec2ArrayType: + uv1 = static_cast(*tx)[tiA]; + uv2 = static_cast(*tx)[tiB]; + uv3 = static_cast(*tx)[tiC]; + break; + + case osg::Array::Vec3ArrayType: + for (i=0; i<2; ++i) { + uv1.ptr()[i] = static_cast(*tx)[tiA].ptr()[i]; + uv2.ptr()[i] = static_cast(*tx)[tiB].ptr()[i]; + uv3.ptr()[i] = static_cast(*tx)[tiC].ptr()[i]; + } + break; + + case osg::Array::Vec4ArrayType: + for (i=0; i<2; ++i) { + uv1.ptr()[i] = static_cast(*tx)[tiA].ptr()[i]; + uv2.ptr()[i] = static_cast(*tx)[tiB].ptr()[i]; + uv3.ptr()[i] = static_cast(*tx)[tiC].ptr()[i]; + } + break; + + default: + osg::notify(osg::WARN) << "Warning: TangentSpaceGenerator::compute_basis_vectors(,,,) texture coord array must be Vec2Array, Vec3Array or Vec4Array" << std::endl; + } + + if (nx) + { + osg::Vec3 V, T1, T2, T3, B1, B2, B3; + + V = osg::Vec3(P2.x() - P1.x(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ + osg::Vec3(P3.x() - P1.x(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); + if (V.x() != 0) { + V.normalize(); + T1.x() = -V.y() / V.x(); + B1.x() = -V.z() / V.x(); + T2.x() = -V.y() / V.x(); + B2.x() = -V.z() / V.x(); + T3.x() = -V.y() / V.x(); + B3.x() = -V.z() / V.x(); + } else { + osg::notify(osg::NOTICE)<<"Bu!" << uv1 << " || " << uv2 << " || " << uv3 << std::endl; + } + + V = osg::Vec3(P2.y() - P1.y(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ + osg::Vec3(P3.y() - P1.y(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); + if (V.x() != 0) { + V.normalize(); + T1.y() = -V.y() / V.x(); + B1.y() = -V.z() / V.x(); + T2.y() = -V.y() / V.x(); + B2.y() = -V.z() / V.x(); + T3.y() = -V.y() / V.x(); + B3.y() = -V.z() / V.x(); + } + + V = osg::Vec3(P2.z() - P1.z(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ + osg::Vec3(P3.z() - P1.z(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); + if (V.x() != 0) { + V.normalize(); + T1.z() = -V.y() / V.x(); + B1.z() = -V.z() / V.x(); + T2.z() = -V.y() / V.x(); + B2.z() = -V.z() / V.x(); + T3.z() = -V.y() / V.x(); + B3.z() = -V.z() / V.x(); + } + + (*base_->T_)[v1] = osg::Vec4(T1, 0); + (*base_->B_)[v1] = osg::Vec4(B1, 0); + (*base_->T_)[v2] = osg::Vec4(T2, 0); + (*base_->B_)[v2] = osg::Vec4(B2, 0); + (*base_->T_)[v3] = osg::Vec4(T3, 0); + (*base_->B_)[v3] = osg::Vec4(B3, 0); + + (*base_->N_)[v1] += osg::Vec4(N1, 0); + (*base_->N_)[v2] += osg::Vec4(N2, 0); + (*base_->N_)[v3] += osg::Vec4(N3, 0); + + } + else{ + osg::Vec3 face_normal = (P2 - P1) ^ (P3 - P1); + + osg::Vec3 V; + + V = osg::Vec3(P2.x() - P1.x(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ + osg::Vec3(P3.x() - P1.x(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); + if (V.x() != 0) { + V.normalize(); + (*base_->T_)[v1].x() += -V.y() / V.x(); + (*base_->B_)[v1].x() += -V.z() / V.x(); + (*base_->T_)[v2].x() += -V.y() / V.x(); + (*base_->B_)[v2].x() += -V.z() / V.x(); + (*base_->T_)[v3].x() += -V.y() / V.x(); + (*base_->B_)[v3].x() += -V.z() / V.x(); + } + + V = osg::Vec3(P2.y() - P1.y(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ + osg::Vec3(P3.y() - P1.y(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); + if (V.x() != 0) { + V.normalize(); + (*base_->T_)[v1].y() += -V.y() / V.x(); + (*base_->B_)[v1].y() += -V.z() / V.x(); + (*base_->T_)[v2].y() += -V.y() / V.x(); + (*base_->B_)[v2].y() += -V.z() / V.x(); + (*base_->T_)[v3].y() += -V.y() / V.x(); + (*base_->B_)[v3].y() += -V.z() / V.x(); + } + + V = osg::Vec3(P2.z() - P1.z(), uv2.x() - uv1.x(), uv2.y() - uv1.y()) ^ + osg::Vec3(P3.z() - P1.z(), uv3.x() - uv1.x(), uv3.y() - uv1.y()); + if (V.x() != 0) { + V.normalize(); + (*base_->T_)[v1].z() += -V.y() / V.x(); + (*base_->B_)[v1].z() += -V.z() / V.x(); + (*base_->T_)[v2].z() += -V.y() / V.x(); + (*base_->B_)[v2].z() += -V.z() / V.x(); + (*base_->T_)[v3].z() += -V.y() / V.x(); + (*base_->B_)[v3].z() += -V.z() / V.x(); + } + + (*base_->N_)[v1] += osg::Vec4(face_normal, 0); + (*base_->N_)[v2] += osg::Vec4(face_normal, 0); + (*base_->N_)[v3] += osg::Vec4(face_normal, 0); + } + if ( (*base_->B_)[v1].length() == 0 || (*base_->B_)[v2].length() == 0 || (*base_->B_)[v3].length() == 0) { + osg::notify(osg::WARN) << "WARNING: zero binormal/s!" << std::endl; + osg::notify(osg::WARN) << " " << P1 << "|" << P2 << "|" << P3 << std::endl; + osg::notify(osg::WARN) << " " << iA << "|" << iB << "|" << iC << std::endl; + } +}