text: // Geometric Tools, LLC
  // Copyright (c) 1998-2014
  // Distributed under the Boost Software License, Version 1.0.
  // http://www.boost.org/LICENSE_1_0.txt
  // http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
  //
  // File Version: 5.0.0 (2010/01/01)
  
  #include "MeshEnvelope.h"
  #include "CreateEnvelope.h"
  
  WM5_WINDOW_APPLICATION(MeshEnvelope);
  
  //----------------------------------------------------------------------------
  MeshEnvelope::MeshEnvelope ()
      :
      WindowApplication2("SampleMathematics/MeshEnvelope", 0, 0, 512, 512,
          Float4(1.0f, 1.0f, 1.0f, 1.0f))
  {
      mVertices = 0;
      mIndices = 0;
      mEnvelopeVertices = 0;
      mSize = GetWidth();
  }
  //----------------------------------------------------------------------------
  bool MeshEnvelope::OnInitialize ()
  {
      if (!WindowApplication2::OnInitialize())
      {
          return false;
      }
  
      // Load the 3D face mesh.
  #ifdef WM5_LITTLE_ENDIAN
      std::string path = Environment::GetPathR("FacePN.wmof");
  #else
      std::string path = Environment::GetPathR("FacePN.be.wmof");
  #endif
      InStream inStream;
      inStream.Load(path);
      TriMeshPtr mesh = StaticCast<TriMesh>(inStream.GetObjectAt(0));
      VertexBufferAccessor vba(mesh);
      mNumVertices = vba.GetNumVertices();
  
  #if 1
      // Rotate the mesh just to see how the algorithm behaves.
      Matrix3f rotate(Vector3f::UNIT_X, Mathf::HALF_PI);
      for (int j = 0; j < mNumVertices; ++j)
      {
          vba.Position<Vector3f>(j) = rotate*vba.Position<Vector3f>(j);
      }
  #endif
  
      // Project the mesh onto the xy-plane.
      mVertices = new1<Vector2f>(mNumVertices);
      float x = vba.Position<Vector3f>(0).X();
      float y = vba.Position<Vector3f>(0).Y();
      mVertices[0].X() = x;
      mVertices[0].Y() = y;
      float xmin = x, xmax = x;
      float ymin = y, ymax = y;
      int i;
      for (i = 1; i < mNumVertices; ++i)
      {
          x = vba.Position<Vector3f>(i).X();
          y = vba.Position<Vector3f>(i).Y();
          mVertices[i][0] = x;
          mVertices[i][1] = y;
  
          if (x < xmin)
          {
              xmin = x;
          }
          else if (x > xmax)
          {
              xmax = x;
          }
  
          if (y < ymin)
          {
              ymin = y;
          }
          else if (y > ymax)
          {
              ymax = y;
          }
      }
  
      // Transform the mesh into window coordinates.
      float xOffset = 0.125f*mSize;
      float yOffset = 0.125f*mSize;
      float xMult = (0.75f*mSize)/(xmax - xmin);
      float yMult = (0.75f*mSize)/(ymax - ymin);
      for (i = 0; i < mNumVertices; ++i)
      {
          mVertices[i].X() = xOffset + xMult*(mVertices[i].X() - xmin);
          mVertices[i].Y() = yOffset + yMult*(mVertices[i].Y() - ymin);
      }
  
      // Copy the mesh connectivity information.
      IndexBuffer* ibuffer = mesh->GetIndexBuffer();
      mNumIndices = ibuffer->GetNumElements();
      mIndices = new1<int>(mNumIndices);
      size_t numBytes = mNumIndices*sizeof(int);
      memcpy(mIndices, ibuffer->GetData(), numBytes);
  
      // Create the envelope of the mesh.
      CreateEnvelope(mNumVertices, mVertices, mNumIndices, mIndices,
          mNumEnvelopeVertices, mEnvelopeVertices);
  
      DoFlip(true);
      OnDisplay();
      return true;
  }
  //----------------------------------------------------------------------------
  void MeshEnvelope::OnTerminate ()
  {
      delete1(mVertices);
      delete1(mIndices);
      delete1(mEnvelopeVertices);
  
      WindowApplication2::OnTerminate();
  }
  //----------------------------------------------------------------------------
  void MeshEnvelope::OnDisplay ()
  {
      ClearScreen();
  
      // Draw the mesh triangles.
      ColorRGB black(0, 0, 0);
      int i, v0, v1, v2, x0, y0, x1, y1, x2, y2;
      for (i = 0; i < mNumIndices; /**/)
      {
          v0 = mIndices[i++];
          v1 = mIndices[i++];
          v2 = mIndices[i++];
          x0 = (int)mVertices[v0].X();
          y0 = (int)mVertices[v0].Y();
          x1 = (int)mVertices[v1].X();
          y1 = (int)mVertices[v1].Y();
          x2 = (int)mVertices[v2].X();
          y2 = (int)mVertices[v2].Y();
          DrawLine(x0, y0, x1, y1, black);
          DrawLine(x1, y1, x2, y2, black);
          DrawLine(x2, y2, x0, y0, black);
      }
  
      // Draw the mesh envelope.
      ColorRGB red(255, 0, 0);
      x0 = (int)mEnvelopeVertices[0].X();
      y0 = (int)mEnvelopeVertices[0].Y();
      x1 = x0;
      y1 = y0;
      for (i = 1; i < mNumEnvelopeVertices; ++i)
      {
          x2 = (int)mEnvelopeVertices[i].X();
          y2 = (int)mEnvelopeVertices[i].Y();
          DrawLine(x1, y1, x2, y2, red);
          x1 = x2;
          y1 = y2;
      }
      DrawLine(x1, y1, x0, y0, red);
  
      WindowApplication2::OnDisplay();
  }
  //----------------------------------------------------------------------------
  