 pvec3PositionStream;
    m_pInputDiffuseOrNormalStream = ptDiffuseOrNormalStream;
    m_pInputTextureCoordinateStream = pvec2TextureCoordinateStream;
    m_cInputVertices = cVertices;

    m_pInputIndexStream = puIndexStream;
    m_cInputIndices = cIndices;

    m_uRenderedIndices = 0;
}


//+-----------------------------------------------------------------------------
//
//  Member:
//      CHw3DGeometryRenderer::PrepareIndexed
//
//  Synopsis:
//      Prepares the class for rendering in indexed primitive mode.
//
//------------------------------------------------------------------------------
template <class TDiffuseOrNormal>
HRESULT
CHw3DGeometryRenderer<TDiffuseOrNormal>::PrepareIndexed(
    __out_ecount(1) UINT * const puStartVertex,
    __out_ecount(1) UINT * const puStartIndex,
    __out_ecount(1) UINT * const pcPrimitives,
    __out_ecount(1) bool * const pfNeedsToRender,
    __in_ecount(1) CHwD3DVertexBuffer *pVertexBuffer,
    __in_ecount(1) CHwD3DIndexBuffer *pIndexBuffer
    )
{
    HRESULT hr = S_OK;

    void *pLockedOutputVertices = NULL;

    UINT cIndicesToCopy = 0;
    UINT cVerticesToCopy = 0;
    
    Assert(m_cInputIndices % 3 == 0);

    *pfNeedsToRender = true;

    //
    // If we haven't loaded the vertices into the buffer, do that first.
    //

    if (m_uRenderedIndices == 0)
    {
        //
        // Grab vertices in the vertex buffer
        //

        IFC(pVertexBuffer->Lock(
            m_cInputVertices,
            GetVertexStride(),
            &pLockedOutputVertices,
            puStartVertex
            ));

        //
        // Copy our stream data into the vertex buffer.
        //
        CopyVerticesIntoBuffer(
            pLockedOutputVertices,
            m_cInputVertices
            );

        cVerticesToCopy = m_cInputVertices;
    }

    //
    // Now since this is the first attempted render for the indexed
    // primitive we see if we should see if there is space at the end of the
    // indices for us to tag our indices off of.
    //
    cIndicesToCopy = pIndexBuffer->GetNextUsableNumberOfElements(sizeof(WORD));

    //
    // Check to see if we've got more space than we need.
    //
    if (cIndicesToCopy > RemainingIndices())
    {
        cIndicesToCopy = RemainingIndices();

        //
        // If there aren't any indices left to copy, we're done.
        //
        if (cIndicesToCopy == 0)
        {
            *pfNeedsToRender = false;
            goto Cleanup;
        }
    }

    //
    // Number of indices should always be a multiple of 3 since we're rendering
    // triangles.
    //
    Assert(cIndicesToCopy%3 == 0);

    IFC(pIndexBuffer->CopyFromInputBuffer(
        &m_pInputIndexStream[m_uRenderedIndices],
        cIndicesToCopy,
        puStartIndex
        ));


    m_uRenderedIndices += cIndicesToCopy;

    *pcPrimitives = cIndicesToCopy/3;

Cleanup:
    if (pVertexBuffer->Locked())
    {
        HRESULT hr2 = THR(pVertexBuffer->Unlock(m_cInputVertices));
        
        if (SUCCEEDED(hr))
        {
            hr = hr2;
        }
    }

    RRETURN(hr);
}

//+-----------------------------------------------------------------------------
//
//  Member:
//      CHw3DGeometryRenderer::PrepareNonIndexed
//
//  Synopsis:
//      Prepares the class for rendering in non-indexed primitive mode.
//
//------------------------------------------------------------------------------
template <class TDiffuseOrNormal>
HRESULT
CHw3DGeometryRenderer<TDiffuseOrNormal>::PrepareNonIndexed(
    __out_ecount(1) UINT * const puStartVertex,
    __out_ecount(1) UINT * const pcPrimitives,
    __out_ecount(1) bool * const pfNeedsToRender,
    __in_ecount(1) CHwD3DVertexBuffer *pVertexBuffer
    )
{
    HRESULT hr = S_OK;
    
    UINT cVerticesToCopy = 0;
    void *pLockedOutputVertices = NULL;

    *pfNeedsToRender = true;

    //
    // Since we have a mesh that's too big to fit all in one render, it makes
    // sense to fill the vertex buffer completely and render that.  But if 
    // there's still space in the existing buffer on our first filling we would 
    // rather use that first to avoid a discard.
    //
    cVerticesToCopy = pVertexBuffer->GetNextUsableNumberOfElements(GetVertexStride());

    //
    // Check to see if we've got more space than we need.
    //
    if (cVerticesToCopy > RemainingIndices())
    {
        cVerticesToCopy = RemainingIndices();

        //
        // If we're down to 0 vertices left, it means we've fully rendered the
        // mesh.
        //
        if (cVerticesToCopy == 0)
        {
            *pfNeedsToRender = false;
            goto Cleanup;
        }
    }

    //
    // Grab the vertices in the buffer.
    //
    IFC(pVertexBuffer->Lock(
        cVerticesToCopy,
        GetVertexStride(),
        &pLockedOutputVertices,
        puStartVertex
        ));

    //
    // Copy the indexed triangles into the vertex buffer.
    //
    CopyIndexOrderedVerticesIntoBuffer(
        pLockedOutputVertices,
        m_uRenderedIndices,
        cVerticesToCopy
        );

    //
    // We're rendering non-indexed, so the number of vertices we render
    // sould be a multiple of 3 since we're rendering triangles.
    //
    Assert(cVerticesToCopy%3 == 0);

    *pcPrimitives = cVerticesToCopy/3;

    m_uRenderedIndices += cVerticesToCopy;

Cleanup:
    if (pVertexBuffer->Locked())
    {
        HRESULT hr2 = THR(pVertexBuffer->Unlock(cVerticesToCopy));
        
        if (SUCCEEDED(hr))
        {
            hr = hr2;
        }
    }

    RRETURN(hr);
}

//+-----------------------------------------------------------------------------
//
//  Member:
//      CHw3DGeometryRenderer::CopyVerticesIntoBuffer
//
//  Synopsis:
//      Copies triangle vertices into the vertex buffer.
//
//      Note: We cannot reorder the vertices any differently than their
//            natural order in the inputstreams.  Doing so would cause
//            indices to refer to the wrong vertices.
//
//------------------------------------------------------------------------------
template <class TDiffuseOrNormal>
void
CHw3DGeometryRenderer<TDiffuseOrNormal>::CopyVerticesIntoBuffer(
    __out_xcount(cVerticesToCopy*GetVertexStride()) void * const pCardVertexBuffer,
    UINT cVerticesToCopy
    )
{
    DWORD dwVertexStride = GetVertexStride();
    
    Assert(m_pInputPositionStream);
    Assert(m_pInputTextureCoordinateStream);
    Assert(m_pInputIndexStream);

    Assert(cVerticesToCopy <= m_cInputVertices);

    //
    // Gather pointers to each of the subelements of the vertex
    //

    BYTE *pbPosition        = reinterpret_cast<BYTE *>(pCardVertexBuffer);
    BYTE *pbDiffuseOrNormal = pbPosition + sizeof(vector3);   
    BYTE *pbTextureCoord    = pbDiffuseOrNormal + sizeof(TDiffuseOrNormal);

    //
    // Input Light values are optional, if there aren't any then we default to Solid White
    //

    const TDiffuseOrNormal *ptInputDiffuseOrNormalArray = NULL;

    //
    // A multiplier for the vertex index.  This let's us use either an array of light
    // values