// David Eberly, Geometric Tools, Redmond WA 98052 // Copyright (c) 1998-2020 // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt // Version: 4.0.2019.08.13 #pragma once #include #include #include namespace WwiseGTE { template class RectanglePatchMesh : public Mesh { public: // Create a mesh (x(u,v),y(u,v),z(u,v)) defined by the specified // surface. It is required that surface->IsRectangular() return // 'true'. RectanglePatchMesh(MeshDescription const& description, std::shared_ptr> const& surface) : Mesh(description, { MeshTopology::RECTANGLE }), mSurface(surface) { if (!this->mDescription.constructed) { // The logger system will report these errors in the Mesh // constructor. mSurface = nullptr; return; } LogAssert(mSurface != nullptr && mSurface->IsRectangular(), "A nonnull rectangular surface is required."); if (!this->mTCoords) { mDefaultTCoords.resize(this->mDescription.numVertices); this->mTCoords = mDefaultTCoords.data(); this->mTCoordStride = sizeof(Vector2); this->mDescription.allowUpdateFrame = this->mDescription.wantDynamicTangentSpaceUpdate; if (this->mDescription.allowUpdateFrame) { if (!this->mDescription.hasTangentSpaceVectors) { this->mDescription.allowUpdateFrame = false; } if (!this->mNormals) { this->mDescription.allowUpdateFrame = false; } } } this->ComputeIndices(); InitializeTCoords(); InitializePositions(); if (this->mDescription.allowUpdateFrame) { InitializeFrame(); } else if (this->mNormals) { InitializeNormals(); } } // Member access. inline std::shared_ptr> const& GetSurface() const { return mSurface; } protected: void InitializeTCoords() { Real uMin = mSurface->GetUMin(); Real uDelta = (mSurface->GetUMax() - uMin) / static_cast(this->mDescription.numCols - 1); Real vMin = mSurface->GetVMin(); Real vDelta = (mSurface->GetVMax() - vMin) / static_cast(this->mDescription.numRows - 1); Vector2 tcoord; for (uint32_t r = 0, i = 0; r < this->mDescription.numRows; ++r) { tcoord[1] = vMin + vDelta * (Real)r; for (uint32_t c = 0; c < this->mDescription.numCols; ++c, ++i) { tcoord[0] = uMin + uDelta * (Real)c; this->TCoord(i) = tcoord; } } } void InitializePositions() { for (uint32_t r = 0, i = 0; r < this->mDescription.numRows; ++r) { for (uint32_t c = 0; c < this->mDescription.numCols; ++c, ++i) { Vector2 tcoord = this->TCoord(i); this->Position(i) = mSurface->GetPosition(tcoord[0], tcoord[1]); } } } void InitializeNormals() { for (uint32_t r = 0, i = 0; r < this->mDescription.numRows; ++r) { for (uint32_t c = 0; c < this->mDescription.numCols; ++c, ++i) { Vector2 tcoord = this->TCoord(i); Vector3 values[6]; mSurface->Evaluate(tcoord[0], tcoord[1], 1, values); Normalize(values[1], true); Normalize(values[2], true); this->Normal(i) = UnitCross(values[1], values[2], true); } } } void InitializeFrame() { for (unsigned int r = 0, i = 0; r < this->mDescription.numRows; ++r) { for (unsigned int c = 0; c < this->mDescription.numCols; ++c, ++i) { Vector2 tcoord = this->TCoord(i); Vector3 values[6]; mSurface->Evaluate(tcoord[0], tcoord[1], 1, values); Normalize(values[1], true); Normalize(values[2], true); if (this->mDPDUs) { this->DPDU(i) = values[1]; } if (this->mDPDVs) { this->DPDV(i) = values[2]; } ComputeOrthogonalComplement(2, &values[1], true); if (this->mNormals) { this->Normal(i) = values[3]; } if (this->mTangents) { this->Tangent(i) = values[1]; } if (this->mBitangents) { this->Bitangent(i) = values[2]; } } } } virtual void UpdatePositions() override { if (mSurface) { InitializePositions(); } } virtual void UpdateNormals() override { if (mSurface) { InitializeNormals(); } } virtual void UpdateFrame() override { if (mSurface) { InitializeFrame(); } } std::shared_ptr> mSurface; // If the client does not request texture coordinates, they will be // computed internally for use in evaluation of the surface geometry. std::vector> mDefaultTCoords; }; }