Example #1
0
// ---------------------------------------------------------------------------------
// calculate vertex normals given the triangles
void 
Mesh3D::
calculateVertexNormals()
{
	// create 0-normals
	m_vertexNormals = std::vector< Vector3 >( getNumberOfVertices(), Vector3(0,0,0) );

	for(unsigned int i = 0; i < getNumberOfFaces(); i++) {
		int v1 = getFaceVertexIndex(i,0);
		int v2 = getFaceVertexIndex(i,1);
		int v3 = getFaceVertexIndex(i,2);

		assert( v1 < getNumberOfVertices() );
		assert( v2 < getNumberOfVertices() );
		assert( v3 < getNumberOfVertices() );

		Vector3 p = getVertexPosition( v1 );
		Vector3 q = getVertexPosition( v2 );
		Vector3 r = getVertexPosition( v3 );
		Vector3 n = (q-p).cross(r-p).normalize();

		m_vertexNormals[v1] += n;
		m_vertexNormals[v2] += n;
		m_vertexNormals[v3] += n;
	}

	for(int i = 0; i < getNumberOfVertices(); i++) {
		assert( m_vertexNormals[i].length() > 0 );
		m_vertexNormals[i] = m_vertexNormals[i].normalize();
	}

}
Example #2
0
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
int VertexGeom::writeXdmf(QTextStream& out, QString dcName, QString hdfFileName)
{
  herr_t err = 0;

  // Always start the grid
  out << "  <!-- *************** START OF " << dcName << " *************** -->" << "\n";
  out << "  <Grid Name=\"" << dcName << "\" GridType=\"Uniform\">" << "\n";

#if 0
  DataArrayPath dap = getTemporalDataPath();
  if(dap.isValid())
  {
    IDataArray::Pointer timeValues = getAttributeMatrix(dap.getAttributeMatrixName())->getAttributeArray(dap.getDataArrayName());
    Int32ArrayType::Pointer timeValuePtr = boost::dynamic_pointer_cast<Int32ArrayType>(timeValues);
    out << "    <Time TimeType=\"Single\" Value=\"" << timeValuePtr->getValue(0) << "\"/>\n";
  }
#endif

  out << "    <Topology TopologyType=\"Polyvertex\" NumberOfElements=\"" << getNumberOfVertices() << "\">" << "\n";
  out << "      <DataItem Format=\"HDF\" NumberType=\"Int\" Dimensions=\"" << getNumberOfVertices() << "\">" << "\n";
  out << "        " << hdfFileName << ":/DataContainers/" << dcName << "/" << DREAM3D::Geometry::Geometry << "/" << "Verts" << "\n";
  out << "      </DataItem>" << "\n";
  out << "    </Topology>" << "\n";

  out << "    <Geometry Type=\"XYZ\">" << "\n";
  out << "      <DataItem Format=\"HDF\"  Dimensions=\"" << getNumberOfVertices() << " 3\" NumberType=\"Float\" Precision=\"4\">" << "\n";
  out << "        " << hdfFileName << ":/DataContainers/" << dcName << "/" << DREAM3D::Geometry::Geometry << "/" << DREAM3D::Geometry::SharedVertexList << "\n";
  out << "      </DataItem>" << "\n";
  out << "    </Geometry>" << "\n";
  out << "" << "\n";

  return err;
}
Example #3
0
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void QuadGeom::addAttributeMatrix(const QString& name, AttributeMatrix::Pointer data)
{
  if (data->getType() != 0 || data->getType() != 1 || data->getType() != 2)
  {
    // QuadGeom can only accept vertex, edge, or face Attribute Matrices
    return;
  }
  if (data->getType() == 0 && static_cast<int64_t>(data->getNumTuples()) != getNumberOfVertices())
  {
    return;
  }
  if (data->getType() == 1 && static_cast<int64_t>(data->getNumTuples()) != getNumberOfEdges())
  {
    return;
  }
  if (data->getType() == 2 && data->getNumTuples() != getNumberOfElements())
  {
    return;
  }
  if (data->getName().compare(name) != 0)
  {
    data->setName(name);
  }
  m_AttributeMatrices[name] = data;
}
Example #4
0
// Draw function
void Line::drawFunc()
{
   BEGIN_DLIST
   const unsigned int n = getNumberOfVertices();
   const osg::Vec3* v = getVertices();
   if (n >= 2) {
      if (segment) {
         // Draw as line segments (pairs of vertices)
         glBegin(GL_LINES);
         for (unsigned int i = 0; i < n; i++) {
            lcVertex3v( v[i].ptr() );
         }
         glEnd();
      }
      else {
         // Draw one long line
         glBegin(GL_LINE_STRIP);
         for (unsigned int i = 0; i < n; i++) {
            lcVertex3v( v[i].ptr() );
         }
         glEnd();
      }
   }
   END_DLIST
}
Example #5
0
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
int VertexGeom::writeGeometryToHDF5(hid_t parentId, bool writeXdmf)
{
  herr_t err = 0;
  QVector<size_t> tDims(1, 0);

  if (m_VertexList.get() != NULL)
  {
    err = GeometryHelpers::GeomIO::WriteListToHDF5(parentId, m_VertexList);
    if (err < 0)
    {
      return err;
    }
    if(writeXdmf == true)
    {
      QVector<size_t> cDims(1, 1);
      DataArray<int64_t>::Pointer vertsPtr = DataArray<int64_t>::CreateArray(getNumberOfVertices(), cDims, DREAM3D::StringConstants::VertsName);
      int64_t* verts = vertsPtr->getPointer(0);
      for(size_t i = 0; i < vertsPtr->getNumberOfTuples(); i++)
      {
        verts[i] = i;
      }
      tDims[0] = vertsPtr->getNumberOfTuples();
      err = vertsPtr->writeH5Data(parentId, tDims);
    }
  }

  return err;
}
Example #6
0
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
int QuadGeom::writeXdmf(QTextStream& out, QString dcName, QString hdfFileName)
{
  herr_t err = 0;

  out << "  <!-- *************** START OF " << dcName << " *************** -->" << "\n";
  out << "  <Grid Name=\"" << dcName << "\" GridType=\"Uniform\">" << "\n";

  out << "    <Topology TopologyType=\"Quadrilateral\" NumberOfElements=\"" << getNumberOfQuads() << "\">" << "\n";
  out << "      <DataItem Format=\"HDF\" NumberType=\"Int\" Dimensions=\"" << getNumberOfQuads() << " 4\">" << "\n";
  out << "        " << hdfFileName << ":/DataContainers/" << dcName << "/" << DREAM3D::Geometry::Geometry << "/" << DREAM3D::Geometry::SharedQuadList << "\n";
  out << "      </DataItem>" << "\n";
  out << "    </Topology>" << "\n";

  if (m_VertexList.get() == NULL)
  {
    out << "<!-- ********************* GEOMETRY ERROR ****************************************\n";
    out << "The Geometry with name '" << getName() << "' in DataContainer '" << dcName <<  "' \n";
    out << "did not have any vertices assigned.\n";
    out << "The Geometry types will be missing from the Xdmf which will cause issues when\n";
    out << "trying to load the file\n";
    out << " ********************************************************************************** -->\n";
  }
  else
  {
    out << "    <Geometry Type=\"XYZ\">" << "\n";
    out << "      <DataItem Format=\"HDF\"  Dimensions=\"" << getNumberOfVertices() << " 3\" NumberType=\"Float\" Precision=\"4\">" << "\n";
    out << "        " << hdfFileName << ":/DataContainers/" << dcName << "/" << DREAM3D::Geometry::Geometry << "/" << DREAM3D::Geometry::SharedVertexList << "\n";
    out << "      </DataItem>" << "\n";
    out << "    </Geometry>" << "\n";
    out << "" << "\n";
  }

  return err;
}
Example #7
0
//------------------------------------------------------------------------------
// drawFunc()
//------------------------------------------------------------------------------
void Polygon::drawFunc()
{
    BEGIN_DLIST
    unsigned int nv = getNumberOfVertices();
    const osg::Vec3* vertices = getVertices();

    if (nv >= 2) {

        // Draw with texture
        unsigned int ntc = getNumberOfTextureCoords();
        if (ntc > 0 && hasTexture()) {
            const osg::Vec2* texCoord = getTextureCoord();
            unsigned int tc = 0; // texture count
            glBegin(GL_POLYGON);
            for (unsigned int i = 0; i < nv; i++) {
                if (tc < ntc)  {
                    lcTexCoord2v(texCoord[tc++].ptr());
                }
                lcVertex3v( vertices[i].ptr() );
            }
            glEnd();

        }

        // Draw without texture
        else {
            // get our color gradient, because if we have one, instead of a regular color, we will
            // override it here and set it on a per vertex level.
            ColorGradient* colGradient = dynamic_cast<ColorGradient*>(getColor());
            glBegin(GL_POLYGON);
            osg::Vec3* ptr = nullptr;
            for (unsigned int i = 0; i < nv; i++) {
                if (colGradient != nullptr) {
                    Basic::Color* col = colGradient->getColorByIdx(i+1);
                    if (col != nullptr)
                       glColor4f(static_cast<GLfloat>(col->red()), static_cast<GLfloat>(col->green()),
                                 static_cast<GLfloat>(col->blue()), static_cast<GLfloat>(col->alpha()));
                }
                // if we have a material name, we will set up like we have a material
                if (getMaterialName() != nullptr) {
                    //lcVertex3v( vertices[i].ptr() );
                    ptr = const_cast<osg::Vec3*>(reinterpret_cast<const osg::Vec3*>(vertices[i].ptr()));

                    if (ptr != nullptr) {
                        calcNormal();
                        lcNormal3(norm.x(), norm.y(), -(norm.z()));
                        lcVertex3(ptr->x(), ptr->y(), ptr->z());
                    }
                }
                else {
                    lcVertex3v(vertices[i].ptr());
                }
            }
            glEnd();
        }
    }
    END_DLIST
}
Example #8
0
bool Polygon::calcPlaneCoeff()
{
   if (getNumberOfVertices() >= 3) {
      coeffValid = calcPlaneCoeff(coeff,getVertices());
   }
   else {
      coeffValid = false;
      coeff.set(0,0,0,0);
   }

   return coeffValid;
}
Example #9
0
// Draw function
void Point::drawFunc()
{
   BEGIN_DLIST
   const unsigned int n = getNumberOfVertices();
   const osg::Vec3* v = getVertices();
   glBegin(GL_POINTS);
   for (unsigned int i = 0; i < n; i++) {
      lcVertex3v( v[i].ptr() );
   }
   glEnd();
   END_DLIST
}
Example #10
0
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
int EdgeGeom::writeGeometryToHDF5(hid_t parentId, bool SIMPL_NOT_USED(writeXdmf))
{
  herr_t err = 0;

  if (m_VertexList.get() != NULL)
  {
    err = GeometryHelpers::GeomIO::WriteListToHDF5(parentId, m_VertexList);
    if (err < 0)
    {
      return err;
    }
  }

  if (m_EdgeList.get() != NULL)
  {
    err = GeometryHelpers::GeomIO::WriteListToHDF5(parentId, m_EdgeList);
    if (err < 0)
    {
      return err;
    }
  }

  if (m_EdgeCentroids.get() != NULL)
  {
    err = GeometryHelpers::GeomIO::WriteListToHDF5(parentId, m_EdgeCentroids);
    if (err < 0)
    {
      return err;
    }
  }

  if (m_EdgeNeighbors.get() != NULL)
  {
    size_t numEdges = getNumberOfEdges();
    err = GeometryHelpers::GeomIO::WriteDynamicListToHDF5<uint16_t, int64_t>(parentId, m_EdgeNeighbors, numEdges, DREAM3D::StringConstants::EdgeNeighbors);
    if (err < 0)
    {
      return err;
    }
  }

  if (m_EdgesContainingVert.get() != NULL)
  {
    size_t numVerts = getNumberOfVertices();
    err = GeometryHelpers::GeomIO::WriteDynamicListToHDF5<uint16_t, int64_t>(parentId, m_EdgesContainingVert, numVerts, DREAM3D::StringConstants::EdgesContainingVert);
    if (err < 0)
    {
      return err;
    }
  }

  return err;
}
Example #11
0
/**
 * Initializes the GameObject by creating vao's and vbo's
 * and sending the vertex data over to the graphics card.
 */
void GameObject::initGameObject() {
    if (scene == nullptr) {
        abortWithMessage("In GameObject::initGameObject(): Scene for GameObject was never set");
    }
    
    if (initialized) {
        return;
    }
    
    glGenVertexArrays(1, &vao);
    glGenBuffers(2, vbo);
    
    scene->middleman->bufferObject(vao, vbo, getNumberOfVertices(), getVertices(), getNumberOfVertices(), getVertexColors());
    
    std::vector<GameObject*>::iterator it = children.begin();
    while (it != children.end()) {
        (*it)->initGameObject();
        it++;
    }
    
    initialized = true;
}
Example #12
0
// Draw function
void LineLoop::drawFunc()
{
   BEGIN_DLIST
   const unsigned int n = getNumberOfVertices();
   const osg::Vec3* v = getVertices();
   if (n >= 2) {
      glBegin(GL_LINE_LOOP);
      for (unsigned int i = 0; i < n; i++) {
         lcVertex3v( v[i].ptr() );
      }
      glEnd();
   }
   END_DLIST
}
Example #13
0
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void VertexGeom::findDerivatives(DoubleArrayType::Pointer field, DoubleArrayType::Pointer derivatives)
{
  int64_t numVerts = getNumberOfVertices();
  int cDims = field->getNumberOfComponents();
  double* derivsPtr = derivatives->getPointer(0);
  for (int64_t i = 0; i < numVerts; i++)
  {
    for (int j = 0; j < cDims; j++)
    {
      derivsPtr[i * 3 * cDims + j * 3] = 0.0;
      derivsPtr[i * 3 * cDims + j * 3 + 1] = 0.0;
      derivsPtr[i * 3 * cDims + j * 3 + 2] = 0.0;
    }
  }
}
Example #14
0
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
QString VertexGeom::getInfoString(DREAM3D::InfoStringFormat format)
{
  QString info;
  QTextStream ss (&info);

  if(format == DREAM3D::HtmlFormat)
  {
    ss << "<tr bgcolor=\"#D3D8E0\"><th colspan=2>Vertex Geometry Info</th></tr>";
    ss << "<tr bgcolor=\"#C3C8D0\"><th align=\"right\">NumberOfElements</th><td>" << getNumberOfVertices() << "</td></tr>";
    ss << "</tbody></table>";
  }
  else
  {

  }
  return info;
}
Example #15
0
void GameObject::draw() {
    if (scene == nullptr) {
        abortWithMessage("In GameObject::draw(): Scene for GameObject was never set");
    }
    
    mat4 mv = getModelViewMatrix();
    
    scene->middleman->updateModelViewMatrix(mv);
    glBindVertexArray(vao);
    glDrawArrays(GL_TRIANGLES, 0, getNumberOfVertices());
    
    std::vector<GameObject*>::iterator it = children.begin();
    while (it != children.end()) {
        (*it)->draw();
        it++;
    }
}
Example #16
0
//---------------------------------------------------------------------------------
void Mesh3D::genericUV()
{
	try
	{
		for( int j = 0 ; j < getNumberOfVertices(); j+=3)
		{
			m_vertexUV.push_back(Vector2(0, 0));
			m_vertexUV.push_back(Vector2(0, 1));
			m_vertexUV.push_back(Vector2(1, 1));
			//m_vertexIndices[i][j]

		}
		std::cout << "Done\n";

	}
	catch(...)
	{
		std::cerr << "Error in genericUV" << std::endl;
	}


}
Example #17
0
ossim_uint32 ossimPolygon::getVertexCount()const
{
   return getNumberOfVertices();
}
Example #18
0
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
int QuadGeom::findElementsContainingVert()
{
  m_QuadsContainingVert = ElementDynamicList::New();
  GeometryHelpers::Connectivity::FindElementsContainingVert<uint16_t, int64_t>(m_QuadList, m_QuadsContainingVert, getNumberOfVertices());
  if (m_QuadsContainingVert.get() == NULL)
  {
    return -1;
  }
  return 1;
}
Example #19
0
// Draw function
void Quad::drawFunc()
{
    bool ok = false;

    // Draw with texture
    const unsigned int nv = getNumberOfVertices();
    if (nv > 3) {
        if (!strip) {
            int rem = nv % 4;
            if (rem != 0) std::cerr << "Quad::drawFunc() - Quad have to have multiple of 4 vertices, add or remove vertices!!" << std::endl;
            else {
                BEGIN_DLIST
                glBegin(GL_QUADS);
                ok = true;
            }
        }
        else {
            int rem = nv % 2;
            if (rem != 0) std::cerr << "Quad::drawFunc() - quad strips have to have multiple of 2 vertices, add or remove vertices!!" << std::endl;
            else {
                BEGIN_DLIST
                glBegin(GL_QUAD_STRIP);
                ok = true;
            }
        }

        if (ok) {
            // get our regular vertices here
            const osg::Vec3* v = getVertices();

            const unsigned int ntc = getNumberOfTextureCoords();
            // draw with texture
            if (ntc > 0 && hasTexture()) {
                const osg::Vec2* texCoord = getTextureCoord();
                unsigned int tc = 0; // texture count
                for (unsigned int i = 0; i < nv; i++) {
                    // add our textures coordinates
                    if (tc < ntc)  lcTexCoord2v(texCoord[tc++].ptr());
                    // now our vertices
                    lcVertex3v( v[i].ptr() );
                }

            }
            // draw without texture
            else {
                // get our color gradient and apply it (if we have one)
                ColorGradient* colGradient = dynamic_cast<ColorGradient*>(getColor());

                for (unsigned int i = 0; i < nv; i++) {
                    if (colGradient != nullptr) {
                        Basic::Color* col = colGradient->getColorByIdx(i+1);
                        if (col != nullptr)
                            glColor4f(static_cast<GLfloat>(col->red()),
                                      static_cast<GLfloat>(col->green()),
                                      static_cast<GLfloat>(col->blue()),
                                      static_cast<GLfloat>(col->alpha()));
                    }
                    // now add our vertex
                    lcVertex3v( v[i].ptr() );
                }
            }
            glEnd();
            END_DLIST
        }
    }

    else std::cerr << "Quad::drawFunc() - Quad or QuadStrip needs at least 4 vertices!" << std::endl;
void ModelOBJ::generateTangents()
{
    const int *pTriangle = 0;
    Vertex *pVertex0 = 0;
    Vertex *pVertex1 = 0;
    Vertex *pVertex2 = 0;
    float edge1[3] = {0.0f, 0.0f, 0.0f};
    float edge2[3] = {0.0f, 0.0f, 0.0f};
    float texEdge1[2] = {0.0f, 0.0f};
    float texEdge2[2] = {0.0f, 0.0f};
    float tangent[3] = {0.0f, 0.0f, 0.0f};
    float bitangent[3] = {0.0f, 0.0f, 0.0f};
    float det = 0.0f;
    float nDotT = 0.0f;
    float bDotB = 0.0f;
    float length = 0.0f;
    int totalVertices = getNumberOfVertices();
    int totalTriangles = getNumberOfTriangles();

    // Initialize all the vertex tangents and bitangents.
    for (int i = 0; i < totalVertices; ++i)
    {
        pVertex0 = &m_vertexBuffer[i];

        pVertex0->tangent[0] = 0.0f;
        pVertex0->tangent[1] = 0.0f;
        pVertex0->tangent[2] = 0.0f;
        pVertex0->tangent[3] = 0.0f;

        pVertex0->bitangent[0] = 0.0f;
        pVertex0->bitangent[1] = 0.0f;
        pVertex0->bitangent[2] = 0.0f;
    }

    // Calculate the vertex tangents and bitangents.
    for (int i = 0; i < totalTriangles; ++i)
    {
        pTriangle = &m_indexBuffer[i * 3];

        pVertex0 = &m_vertexBuffer[pTriangle[0]];
        pVertex1 = &m_vertexBuffer[pTriangle[1]];
        pVertex2 = &m_vertexBuffer[pTriangle[2]];

        // Calculate the triangle face tangent and bitangent.

        edge1[0] = pVertex1->position[0] - pVertex0->position[0];
        edge1[1] = pVertex1->position[1] - pVertex0->position[1];
        edge1[2] = pVertex1->position[2] - pVertex0->position[2];

        edge2[0] = pVertex2->position[0] - pVertex0->position[0];
        edge2[1] = pVertex2->position[1] - pVertex0->position[1];
        edge2[2] = pVertex2->position[2] - pVertex0->position[2];

        texEdge1[0] = pVertex1->texCoord[0] - pVertex0->texCoord[0];
        texEdge1[1] = pVertex1->texCoord[1] - pVertex0->texCoord[1];

        texEdge2[0] = pVertex2->texCoord[0] - pVertex0->texCoord[0];
        texEdge2[1] = pVertex2->texCoord[1] - pVertex0->texCoord[1];

        det = texEdge1[0] * texEdge2[1] - texEdge2[0] * texEdge1[1];

        if (fabs(det) < 1e-6f)
        {
            tangent[0] = 1.0f;
            tangent[1] = 0.0f;
            tangent[2] = 0.0f;

            bitangent[0] = 0.0f;
            bitangent[1] = 1.0f;
            bitangent[2] = 0.0f;
        }
        else
        {
            det = 1.0f / det;

            tangent[0] = (texEdge2[1] * edge1[0] - texEdge1[1] * edge2[0]) * det;
            tangent[1] = (texEdge2[1] * edge1[1] - texEdge1[1] * edge2[1]) * det;
            tangent[2] = (texEdge2[1] * edge1[2] - texEdge1[1] * edge2[2]) * det;

            bitangent[0] = (-texEdge2[0] * edge1[0] + texEdge1[0] * edge2[0]) * det;
            bitangent[1] = (-texEdge2[0] * edge1[1] + texEdge1[0] * edge2[1]) * det;
            bitangent[2] = (-texEdge2[0] * edge1[2] + texEdge1[0] * edge2[2]) * det;
        }

        // Accumulate the tangents and bitangents.

        pVertex0->tangent[0] += tangent[0];
        pVertex0->tangent[1] += tangent[1];
        pVertex0->tangent[2] += tangent[2];
        pVertex0->bitangent[0] += bitangent[0];
        pVertex0->bitangent[1] += bitangent[1];
        pVertex0->bitangent[2] += bitangent[2];

        pVertex1->tangent[0] += tangent[0];
        pVertex1->tangent[1] += tangent[1];
        pVertex1->tangent[2] += tangent[2];
        pVertex1->bitangent[0] += bitangent[0];
        pVertex1->bitangent[1] += bitangent[1];
        pVertex1->bitangent[2] += bitangent[2];

        pVertex2->tangent[0] += tangent[0];
        pVertex2->tangent[1] += tangent[1];
        pVertex2->tangent[2] += tangent[2];
        pVertex2->bitangent[0] += bitangent[0];
        pVertex2->bitangent[1] += bitangent[1];
        pVertex2->bitangent[2] += bitangent[2];
    }

    // Orthogonalize and normalize the vertex tangents.
    for (int i = 0; i < totalVertices; ++i)
    {
        pVertex0 = &m_vertexBuffer[i];

        // Gram-Schmidt orthogonalize tangent with normal.

        nDotT = pVertex0->normal[0] * pVertex0->tangent[0] +
                pVertex0->normal[1] * pVertex0->tangent[1] +
                pVertex0->normal[2] * pVertex0->tangent[2];

        pVertex0->tangent[0] -= pVertex0->normal[0] * nDotT;
        pVertex0->tangent[1] -= pVertex0->normal[1] * nDotT;
        pVertex0->tangent[2] -= pVertex0->normal[2] * nDotT;

        // Normalize the tangent.

        length = 1.0f / sqrtf(pVertex0->tangent[0] * pVertex0->tangent[0] +
                              pVertex0->tangent[1] * pVertex0->tangent[1] +
                              pVertex0->tangent[2] * pVertex0->tangent[2]);

        pVertex0->tangent[0] *= length;
        pVertex0->tangent[1] *= length;
        pVertex0->tangent[2] *= length;

        // Calculate the handedness of the local tangent space.
        // The bitangent vector is the cross product between the triangle face
        // normal vector and the calculated tangent vector. The resulting
        // bitangent vector should be the same as the bitangent vector
        // calculated from the set of linear equations above. If they point in
        // different directions then we need to invert the cross product
        // calculated bitangent vector. We store this scalar multiplier in the
        // tangent vector's 'w' component so that the correct bitangent vector
        // can be generated in the normal mapping shader's vertex shader.
        //
        // Normal maps have a left handed coordinate system with the origin
        // located at the top left of the normal map texture. The x coordinates
        // run horizontally from left to right. The y coordinates run
        // vertically from top to bottom. The z coordinates run out of the
        // normal map texture towards the viewer. Our handedness calculations
        // must take this fact into account as well so that the normal mapping
        // shader's vertex shader will generate the correct bitangent vectors.
        // Some normal map authoring tools such as Crazybump
        // (http://www.crazybump.com/) includes options to allow you to control
        // the orientation of the normal map normal's y-axis.

        bitangent[0] = (pVertex0->normal[1] * pVertex0->tangent[2]) - 
                       (pVertex0->normal[2] * pVertex0->tangent[1]);
        bitangent[1] = (pVertex0->normal[2] * pVertex0->tangent[0]) -
                       (pVertex0->normal[0] * pVertex0->tangent[2]);
        bitangent[2] = (pVertex0->normal[0] * pVertex0->tangent[1]) - 
                       (pVertex0->normal[1] * pVertex0->tangent[0]);

        bDotB = bitangent[0] * pVertex0->bitangent[0] + 
                bitangent[1] * pVertex0->bitangent[1] + 
                bitangent[2] * pVertex0->bitangent[2];

        pVertex0->tangent[3] = (bDotB < 0.0f) ? 1.0f : -1.0f;

        pVertex0->bitangent[0] = bitangent[0];
        pVertex0->bitangent[1] = bitangent[1];
        pVertex0->bitangent[2] = bitangent[2];
    }

    m_hasTangents = true;
}
void ModelOBJ::generateNormals()
{
    const int *pTriangle = 0;
    Vertex *pVertex0 = 0;
    Vertex *pVertex1 = 0;
    Vertex *pVertex2 = 0;
    float edge1[3] = {0.0f, 0.0f, 0.0f};
    float edge2[3] = {0.0f, 0.0f, 0.0f};
    float normal[3] = {0.0f, 0.0f, 0.0f};
    float length = 0.0f;
    int totalVertices = getNumberOfVertices();
    int totalTriangles = getNumberOfTriangles();

    // Initialize all the vertex normals.
    for (int i = 0; i < totalVertices; ++i)
    {
        pVertex0 = &m_vertexBuffer[i];
        pVertex0->normal[0] = 0.0f;
        pVertex0->normal[1] = 0.0f;
        pVertex0->normal[2] = 0.0f;
    }

    // Calculate the vertex normals.
    for (int i = 0; i < totalTriangles; ++i)
    {
        pTriangle = &m_indexBuffer[i * 3];

        pVertex0 = &m_vertexBuffer[pTriangle[0]];
        pVertex1 = &m_vertexBuffer[pTriangle[1]];
        pVertex2 = &m_vertexBuffer[pTriangle[2]];

        // Calculate triangle face normal.

        edge1[0] = pVertex1->position[0] - pVertex0->position[0];
        edge1[1] = pVertex1->position[1] - pVertex0->position[1];
        edge1[2] = pVertex1->position[2] - pVertex0->position[2];

        edge2[0] = pVertex2->position[0] - pVertex0->position[0];
        edge2[1] = pVertex2->position[1] - pVertex0->position[1];
        edge2[2] = pVertex2->position[2] - pVertex0->position[2];

        normal[0] = (edge1[1] * edge2[2]) - (edge1[2] * edge2[1]);
        normal[1] = (edge1[2] * edge2[0]) - (edge1[0] * edge2[2]);
        normal[2] = (edge1[0] * edge2[1]) - (edge1[1] * edge2[0]);

        // Accumulate the normals.

        pVertex0->normal[0] += normal[0];
        pVertex0->normal[1] += normal[1];
        pVertex0->normal[2] += normal[2];

        pVertex1->normal[0] += normal[0];
        pVertex1->normal[1] += normal[1];
        pVertex1->normal[2] += normal[2];

        pVertex2->normal[0] += normal[0];
        pVertex2->normal[1] += normal[1];
        pVertex2->normal[2] += normal[2];
    }

    // Normalize the vertex normals.
    for (int i = 0; i < totalVertices; ++i)
    {
        pVertex0 = &m_vertexBuffer[i];

        length = 1.0f / sqrtf(pVertex0->normal[0] * pVertex0->normal[0] +
            pVertex0->normal[1] * pVertex0->normal[1] +
            pVertex0->normal[2] * pVertex0->normal[2]);

        pVertex0->normal[0] *= length;
        pVertex0->normal[1] *= length;
        pVertex0->normal[2] *= length;
    }

    m_hasNormals = true;
}