Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/third_party/rust/wpf-gpu-raster/src/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 96 kB image not shown  

Quelle  hwvertexbuffer.rs   Sprache: unbekannt

 
Spracherkennung für: .rs vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.


//-----------------------------------------------------------------------------
//

//
//  Description:
//      Contains HW Vertex Buffer and Builder class implementations
//
//
//  Notes:
//        
//        +--------------------------------------+
//        |                                      |
//        |           Start Stratum              |
//     1  |                                      |
//        |                                      |
//        +--------------------------------------+
//     2  |======================================|
//        +--------------------------------------+
//        |          /   \             / \       |
//        |         /     \           /   \      |
//        |   A    /   B   \    C    /  D  \  E  |
//     3  |       /         \       /       \    |
//        |      /           \     /         \   |
//        |     /             \   /           \  |
//        |    /               \ /             \ |
//        +--------------------------------------+
//        |    \               / \             / |
//        |     \             /   \           /  |
//     4  |  F   \     G     /  H  \    I    / J |
//        |       \         /       \       /    |
//        +--------------------------------------+
//     5  |======================================|
//        +--------------------------------------+
//     6  |======================================|
//        +--------------------------------------+
//        |                                      |
//        |                                      |
//     7  |           Stop Stratum               |
//        |                                      |
//        |                                      |
//        +--------------------------------------+
//        
//  
//  Strata & complement mode.
//  
//  The anti-aliased HW rasterizer produces a series of "strata" where
//  each strata can be a complex span rendered using lines (#'s 2,5,6) or
//  a series of trapezoids (#'s 3 & 4.)  In normal mode the trapezoid
//  regions B,D,G,I are filled in.
//  
//  Complement mode complicates things.  Complex spans are relatively easy
//  because we get the whole line's worth of data at once.  Trapezoids are
//  more complex because we get B,D,G and I separately.  We handle this by
//  tracking the current stratum and finishing the last incomplete
//  trapezoid stratum when a new stratum begins.  Regions E & J finish
//  trapezoid strata.  We also need to add rectangles at the beginning and
//  end of the geometry (start and stop) to fill out the complement
//  region.
//  
//  This is implemented like so:
//  
//    1. Strata are generated from top to bottom without gaps.
//    2. Before drawing any lines or trapezoids call
//       PrepareStratum(a, b, fTrapezoid) where a & b are the extent of
//       the current stratum and fTrapezoid is true if you are drawing
//       a trapezoid.  This will take care of creating the start
//       stratum and/or finishing a trapezoid stratum if necessary.
//    3. When completely done call EndBuildingOutside() which will
//       close a pending trapezoid and/or produce the stop stratum.
//  
//-----------------------------------------------------------------------------

const FORCE_TRIANGLES: bool = true;

//+----------------------------------------------------------------------------
//
//  Constants to control when we stop waffling because the tiles are too
//  small to make a difference.
//
//  Future Consideration:  can produce an excessive number of triangles.
//   How we mitigate or handle this could be improved.  Right now we stop
//   waffling if the waffle size is less than a quarter-pixel.
//   Two big improvements that could be made are:
//    - multipacking very small textures (but note that we cannot rely
//      on prefiltering to ensure that small screen space means small texture
//      source)
//    - clipping primitives to approximately the screen size
//
//-----------------------------------------------------------------------------
//const c_rMinWaffleWidthPixels: f32 = 0.25;


const FLOAT_ZERO: f32 = 0.;
const FLOAT_ONE: f32 = 1.;

//+----------------------------------------------------------------------------
//
//  Class:     CHwVertexBuffer and CHwTVertexBuffer<class TVertex>
//
//  Synopsis:  This class accumulates geometry data for a primitive
//
//-----------------------------------------------------------------------------

use crate::{types::*, geometry_sink::IGeometrySink, aacoverage::c_nShiftSizeSquared, OutputVertex, nullable_ref::Ref};


//+----------------------------------------------------------------------------
//
//  Class:     CHwVertexBuffer::Builder
//
//  Synopsis:  Base vertex builder class
//
//  Responsibilities:
//    - Given ordered basic vertex information expand/convert/pass-thru
//      to vertex buffer  (Basic vertex information is minimal vertex
//      information sent from the caller that may or may not have been
//      passed thru a tessellator.)
//    - Choosing vertex format from a minimal required vertex format
//
//  Not responsible for:
//    - Allocating space in vertex buffer
//
//  Inputs required:
//    - Key and data to translate input basic vertex info to full vertex data
//    - Vertex info from tessellation (or other Geometry Generator)
//    - Vertex buffer to send output to
//

/*pub struct CHwVertexBufferBuilder /* : public IGeometrySink */
{
    /* 
public:

    static HRESULT Create(
        MilVertexFormat vfIn,
        MilVertexFormat vfOut,
        MilVertexFormatAttribute vfaAntiAliasScaleLocation,
        __in_ecount_opt(1) CHwPipeline *pPipeline,
        __in_ecount_opt(1) CD3DDeviceLevel1 *pDevice,
        __in_ecount(1) CBufferDispenser *pBufferDispenser,
        __deref_out_ecount(1) CHwVertexBuffer::Builder **ppVertexBufferBuilder
        );

    virtual ~Builder()
    {
#if DBG
        Assert(!m_fDbgDestroyed);
        m_fDbgDestroyed = true;
#endif DBG
    }

    //+------------------------------------------------------------------------
    //
    //  Member:    SetConstantMapping
    //
    //  Synopsis:  Use this method to specify that the given color source for
    //             the given vertex destination is constant (won't differ per
    //             vertex)
    //
    //-------------------------------------------------------------------------

    virtual HRESULT SetConstantMapping(
        MilVertexFormatAttribute mvfaDestination,
        __in_ecount(1) const CHwConstantColorSource *pConstCS
        ) PURE;


    //+------------------------------------------------------------------------
    //
    //  Member:    FinalizeMappings
    //
    //  Synopsis:  Use this method to let builder know that all mappings have
    //             been sent
    //
    //-------------------------------------------------------------------------

    virtual HRESULT FinalizeMappings(
        ) PURE;

    //+------------------------------------------------------------------------
    //
    //  Member:    SetOutsideBounds
    //
    //  Synopsis:  Enables rendering zero-alpha geometry outside of the input
    //             shape but within the given bounding rectangle, if fNeedInside
    //             isn't true then it doesn't render geometry with full alpha.
    //
    //-------------------------------------------------------------------------
    virtual void SetOutsideBounds(
        __in_ecount_opt(1) const CMILSurfaceRect *prcBounds,
        bool fNeedInside
        ) PURE;

    //+------------------------------------------------------------------------
    //
    //  Member:    HasOutsideBounds
    //
    //  Synopsis:  Returns true if outside bounds have been set.
    //
    //-------------------------------------------------------------------------
    virtual bool HasOutsideBounds() const PURE;

    //+------------------------------------------------------------------------
    //
    //  Member:    BeginBuilding
    //
    //  Synopsis:  This method lets the builder know it should start from a
    //             clean slate
    //
    //-------------------------------------------------------------------------

    virtual HRESULT BeginBuilding(
        ) PURE;

    //+------------------------------------------------------------------------
    //
    //  Member:    EndBuilding
    //
    //  Synopsis:  Use this method to let the builder know that all of the
    //             vertex data has been sent
    //
    //-------------------------------------------------------------------------

    virtual HRESULT EndBuilding(
        __deref_opt_out_ecount(1) CHwVertexBuffer **ppVertexBuffer
        ) PURE;

    //+------------------------------------------------------------------------
    //
    //  Member:    FlushReset
    //
    //  Synopsis:  Send pending state and geometry to the device and reset
    //             the vertex buffer.
    //
    //-------------------------------------------------------------------------

    MIL_FORCEINLINE HRESULT FlushReset()
    {
        return FlushInternal(NULL);
    }
        
    //
    // Currently all CHwVertexBuffer::Builder are supposed to be allocated via
    // a CBufferDispenser.
    //

    DECLARE_BUFFERDISPENSER_DELETE

protected:

    Builder()
    {
        m_mvfIn = MILVFAttrNone;

#if DBG
        m_mvfDbgOut = MILVFAttrNone;
#endif

        m_mvfaAntiAliasScaleLocation = MILVFAttrNone;

        m_pPipelineNoRef = NULL;
        m_pDeviceNoRef = NULL;
        
#if DBG
        m_fDbgDestroyed = false;
#endif DBG
    }

    //+------------------------------------------------------------------------
    //
    //  Member:    FlushInternal
    //
    //  Synopsis:  Send any pending state and geometry to the device.
    //             If the optional argument is NULL then reset the
    //             vertex buffer.
    //             If the optional argument is non-NULL AND we have
    //             not yet flushed the vertex buffer return the vertex
    //             buffer.
    //
    //-------------------------------------------------------------------------

    virtual HRESULT FlushInternal(
        __deref_opt_out_ecount_opt(1) CHwVertexBuffer **ppVertexBuffer
        ) PURE;


    CHwPipeline *m_pPipelineNoRef;
    CD3DDeviceLevel1 *m_pDeviceNoRef;

    MilVertexFormat m_mvfIn;         // Vertex fields that are pre-generated

#if DBG
    MilVertexFormat m_mvfDbgOut;     // Output format of the vertex
#endif

    MilVertexFormat m_mvfGenerated;  // Vertex fields that are dynamically
                                     // generated by this builder

    MilVertexFormatAttribute m_mvfaAntiAliasScaleLocation;  // Vertex field that
                                                            // contains PPAA
                                                            // falloff factor

#if DBG
private:

    bool m_fDbgDestroyed;     // Used to check single Release pattern

#endif DBG
*/
}*/
#[derive(Default)]
pub struct CD3DVertexXYZDUV2 {
    x: f32,
    y: f32,
    //Z: f32,
    coverage: f32,
    /*U0: f32, V0: f32,
    U1: f32, V1: f32,*/
}
pub type CHwVertexBuffer<'z> = CHwTVertexBuffer<'z, OutputVertex>;
#[derive(Default)]
pub struct CHwTVertexBuffer<'z, TVertex>
{
    //m_rgIndices: DynArray<WORD>,     // Dynamic array of indices


    //m_pBuilder: Rc<CHwTVertexBufferBuilder<TVertex>>,

    /* 
#if DBG
public:
    
    CHwTVertexBuffer()
    {
        m_fDbgNonLineSegmentTriangleStrip = false;
    }
#endif

protected:

    //+------------------------------------------------------------------------
    //
    //  Member:    Reset
    //
    //  Synopsis:  Mark the beginning of a new list of vertices; the existing
    //             list is discarded
    //
    //-------------------------------------------------------------------------

    MIL_FORCEINLINE void Reset(
        __in_ecount(1) Builder *pVBB
        )
    {
#if DBG
        m_fDbgNonLineSegmentTriangleStrip = false;
#endif
        m_rgIndices.SetCount(0);
        m_rgVerticesTriList.SetCount(0);
        m_rgVerticesTriStrip.SetCount(0);
        m_rgVerticesLineList.SetCount(0);
        m_rgVerticesNonIndexedTriList.SetCount(0);

        m_pBuilder = pVBB;
    }

    //+------------------------------------------------------------------------
    //
    //  Member:    AddNonIndexedTriListVertices
    //
    //  Synopsis:  Reserve space for consecutive vertices and return start
    //             index
    //
    //-------------------------------------------------------------------------

    MIL_FORCEINLINE HRESULT AddNonIndexedTriListVertices(
        UINT uCount,
        __deref_ecount(uCount) TVertex **ppVertices
        );

    //+------------------------------------------------------------------------
    //
    //  Member:    AddTriListVertices
    //
    //  Synopsis:  Reserve space for consecutive vertices and return start
    //             index
    //
    //-------------------------------------------------------------------------

    MIL_FORCEINLINE HRESULT AddTriListVertices(
        UINT uDelta,
        __deref_ecount(uDelta) TVertex **ppVertices,
        __out_ecount(1) WORD *pwIndexStart
        );

    //+------------------------------------------------------------------------
    //
    //  Member:    AddTriStripVertices
    //
    //  Synopsis:  Reserve space for consecutive vertices and return start
    //             index
    //
    //-------------------------------------------------------------------------

    MIL_FORCEINLINE HRESULT AddTriStripVertices(
        UINT uCount,
        __deref_ecount(uCount) TVertex **ppVertices
        );

    //+------------------------------------------------------------------------
    //
    //  Member:    AddLineListVertices
    //
    //  Synopsis:  Reserve space for consecutive vertices and return start
    //             index
    //
    //-------------------------------------------------------------------------

    MIL_FORCEINLINE HRESULT AddLineListVertices(
        UINT uCount,
        __deref_ecount(uCount) TVertex **ppVertices
        );

public:

    //+------------------------------------------------------------------------
    //
    //  Member:    AddLine implements ILineSink<PointXYA>
    //
    //  Synopsis:  Add a line given two points with x, y, & alpha.
    //
    //-------------------------------------------------------------------------
    HRESULT AddLine(
        __in_ecount(1) const PointXYA &v0,
        __in_ecount(1) const PointXYA &v1
        );

    //+------------------------------------------------------------------------
    //
    //  Member:    AddTriangle implements ITriangleSink<PointXYA>
    //
    //  Synopsis:  Add a triangle given three points with x, y, & alpha.
    //
    //-------------------------------------------------------------------------

    HRESULT AddTriangle(
        __in_ecount(1) const PointXYA &v0,
        __in_ecount(1) const PointXYA &v1,
        __in_ecount(1) const PointXYA &v2
        );

    // Re-introduce parent AddTriangle(WORD,WORD,WORD) into this scope.
    using CHwVertexBuffer::AddTriangle;
    
    //+------------------------------------------------------------------------
    //
    //  Member:    AddLineAsTriangleStrip
    //
    //  Synopsis:  Add a horizontal line using a trinagle strip
    //
    //-------------------------------------------------------------------------
    HRESULT AddLineAsTriangleStrip(
        __in_ecount(1) const TVertex *pBegin, // Begin
        __in_ecount(1) const TVertex *pEnd    // End
        );

    //+------------------------------------------------------------------------
    //
    //  Member:    SendVertexFormat
    //
    //  Synopsis:  Send contained vertex format to device
    //
    //-------------------------------------------------------------------------

    HRESULT SendVertexFormat(
        __inout_ecount(1) CD3DDeviceLevel1 *pDevice
        ) const;

    //+------------------------------------------------------------------------
    //
    //  Member:    DrawPrimitive
    //
    //  Synopsis:  Send the geometry data to the device and execute rendering
    //
    //-------------------------------------------------------------------------

    HRESULT DrawPrimitive(
        __inout_ecount(1) CD3DDeviceLevel1 *pDevice
        ) const;

protected:
    //+------------------------------------------------------------------------
    //
    //  Member:    GetNumTriListVertices
    //
    //  Synopsis:  Return current number of vertices
    //
    //-------------------------------------------------------------------------

    MIL_FORCEINLINE DWORD GetNumTriListVertices() const
    {
        return m_rgVerticesTriList.GetCount();
    }

    //+------------------------------------------------------------------------
    //
    //  Member:    GetTriListVertices
    //
    //  Synopsis:  Return pointer to beginning of vertex list and their count
    //
    //-------------------------------------------------------------------------

    MIL_FORCEINLINE void GetTriListVertices(
        __deref_out_ecount_full(*puNumVertices) TVertex **ppVertices,
        __out_ecount(1) UINT * puNumVertices
        )
    {
        *ppVertices = m_rgVerticesTriList.GetDataBuffer();
        *puNumVertices = m_rgVerticesTriList.GetCount();
    }

    //+------------------------------------------------------------------------
    //
    //  Member:    GetNumNonIndexedTriListVertices
    //
    //  Synopsis:  Return current number of vertices
    //
    //-------------------------------------------------------------------------

    MIL_FORCEINLINE DWORD GetNumNonIndexedTriListVertices() const
    {
        return m_rgVerticesNonIndexedTriList.GetCount();
    }

    //+------------------------------------------------------------------------
    //
    //  Member:    GetNonIndexedTriListVertices
    //
    //  Synopsis:  Return pointer to beginning of vertex list and their count
    //
    //-------------------------------------------------------------------------

    MIL_FORCEINLINE void GetNonIndexedTriListVertices(
        __deref_out_ecount_full(*puNumVertices) TVertex **ppVertices,
        __out_ecount(1) UINT * puNumVertices
        )
    {
        *ppVertices = m_rgVerticesNonIndexedTriList.GetDataBuffer();
        *puNumVertices = m_rgVerticesNonIndexedTriList.GetCount();
    }

    //+------------------------------------------------------------------------
    //
    //  Member:    GetNumTriStripVertices
    //
    //  Synopsis:  Return current number of vertices
    //
    //-------------------------------------------------------------------------

    MIL_FORCEINLINE DWORD GetNumTriStripVertices() const
    {
        return m_rgVerticesTriStrip.GetCount();
    }

    //+------------------------------------------------------------------------
    //
    //  Member:    GetTriStripVertices
    //
    //  Synopsis:  Return pointer to beginning of vertex list and their count
    //
    //-------------------------------------------------------------------------

    MIL_FORCEINLINE void GetTriStripVertices(
        __deref_out_ecount_full(*puNumVertices) TVertex **ppVertices,
        __out_ecount(1) UINT *puNumVertices
        )
    {
        *ppVertices = m_rgVerticesTriStrip.GetDataBuffer();
        *puNumVertices = m_rgVerticesTriStrip.GetCount();
    }

    //+------------------------------------------------------------------------
    //
    //  Member:    GetNumLineListVertices
    //
    //  Synopsis:  Return current number of vertices
    //
    //-------------------------------------------------------------------------

    MIL_FORCEINLINE DWORD GetNumLineListVertices() const
    {
        return m_rgVerticesLineList.GetCount();
    }

    //+------------------------------------------------------------------------
    //
    //  Member:    GetLineListVertices
    //
    //  Synopsis:  Return pointer to beginning of vertex list and their count
    //
    //-------------------------------------------------------------------------

    MIL_FORCEINLINE void GetLineListVertices(
        __deref_out_ecount_full(*puNumVertices) TVertex **ppVertices,
        __out_ecount(1) UINT * puNumVertices
        )
    {
        *ppVertices = m_rgVerticesLineList.GetDataBuffer();
        *puNumVertices = m_rgVerticesLineList.GetCount();
    }

    //+------------------------------------------------------------------------
    //
    //  Member:    GetLineListVertices
    //
    //  Synopsis:  Return pointer to beginning of vertex list
    //
    //-------------------------------------------------------------------------



*/

    // Dynamic array of vertices for which all allocations are zeroed.
    // XXX: the zero has been removed
    //m_rgVerticesTriList: DynArray<TVertex>,             // Indexed triangle list vertices
    //m_rgVerticesNonIndexedTriList: DynArray<TVertex>,   // Non-indexed triangle list vertices
    m_rgVerticesTriList: DynArray<TVertex>,            // Triangle strip vertices
    //m_rgVerticesLineList: DynArray<TVertex>,            // Linelist vertices

    m_rgVerticesBuffer: Option<&'z mut [TVertex]>,
    m_rgVerticesBufferOffset: usize,

    #[cfg(debug_assertions)]
    // In debug make a note if we add a triangle strip that doesn't have 6 vertices
    // so that we can ensure that we only waffle 6-vertex tri strips.
    m_fDbgNonLineSegmentTriangleStrip: bool,
    subpixel_bias: f32,
}

impl<'z, TVertex: Default> CHwTVertexBuffer<'z, TVertex> {
    pub fn new(rasterization_truncates: bool, output_buffer: Option<&'z mut [TVertex]>) -> Self {
        CHwTVertexBuffer::<TVertex> {
            subpixel_bias: if rasterization_truncates {
                // 1/512 is 0.5 of a subpixel when using 8 bits of subpixel precision.
                1./512.
            } else {
                0.
            },
            m_rgVerticesBuffer: output_buffer,
            m_rgVerticesBufferOffset: 0,
            ..Default::default()
        }
    }

    pub fn flush_output(&mut self) -> Box<[TVertex]> {
        std::mem::take(&mut self.m_rgVerticesTriList).into_boxed_slice()
    }

    pub fn get_output_buffer_size(&self) -> Option<usize> {
        if self.m_rgVerticesBuffer.is_some() {
            Some(self.m_rgVerticesBufferOffset)
        } else {
            None
        }
    }
}

//+----------------------------------------------------------------------------
//
//  Class:     CHwTVertexMappings<class TVertex>
//
//  Synopsis:  Helper class that knows how to populate a vertex from the
//             incoming basic per vertex data, like just X and Y
//
//-----------------------------------------------------------------------------
#[derive(Default)]
struct CHwTVertexMappings<TVertex>
{/* 
public:

    CHwTVertexMappings();

    void SetPositionTransform(
        __in_ecount(1) const MILMatrix3x2 &matPositionTransform
        );

    HRESULT SetConstantMapping(
        MilVertexFormatAttribute mvfaDestination,
        __in_ecount(1) const CHwConstantColorSource *pConstCS
        );

    void PointToUV(
        __in_ecount(1) const MilPoint2F &ptIn,
        __bound UINT uIndex,
        __out_ecount(1) TVertex *pvOut
        );
    
    MIL_FORCEINLINE bool AreWaffling() const
    {
        return false;
    }

private:
    static const size_t s_numOfVertexTextureCoords
        = NUM_OF_VERTEX_TEXTURE_COORDS(TVertex);
public:

    MilVertexFormat m_mvfMapped;

    MilColorF m_colorStatic;

    MILMatrix3x2 m_matPos2DTransform;

    MILMatrix3x2 m_rgmatPointToUV[s_numOfVertexTextureCoords];
    CMilPointAndSizeF m_rgSubrect[s_numOfVertexTextureCoords];
    WaffleModeFlags m_rgWaffleMode[s_numOfVertexTextureCoords];

*/
    m_vStatic: TVertex,
    subpixel_bias: f32,
}

impl<TVertex> CHwTVertexBuffer<'_, TVertex> {
    pub fn Reset(&mut self,
        /*pVBB: &mut CHwTVertexBufferBuilder<TVertex>*/
        )
    {
        #[cfg(debug_assertions)]
        {
            self.m_fDbgNonLineSegmentTriangleStrip = false;
        }

        //self.m_rgIndices.SetCount(0);
        //self.m_rgVerticesTriList.SetCount(0);
        self.m_rgVerticesTriList.SetCount(0);
        self.m_rgVerticesBufferOffset = 0;
        //self.m_rgVerticesLineList.SetCount(0);
        //self.m_rgVerticesNonIndexedTriList.SetCount(0);

        //self.m_pBuilder = pVBB;
    }

    fn IsEmpty(&self) -> bool
    {
        return true
             //  && (self.m_rgIndices.GetCount() == 0)
            //&& (self.m_rgVerticesLineList.GetCount() == 0)
            && (self.m_rgVerticesTriList.GetCount() == 0)
            && self.m_rgVerticesBufferOffset == 0
            //&& (self.m_rgVerticesNonIndexedTriList.GetCount() == 0);
    }

}

//+----------------------------------------------------------------------------
//
//  Class:     CHwTVertexBuffer<class TVertex>::Builder
//
//  Synopsis:  Implements CHwVertexBuffer::Builder for a particular vertex
//             format
//
//-----------------------------------------------------------------------------

pub struct CHwTVertexBufferBuilder<'y, 'z, TVertex>
{
    m_mvfIn: MilVertexFormat,         // Vertex fields that are pre-generated

    #[cfg(debug_assertions)]
    m_mvfDbgOut: MilVertexFormat,     // Output format of the vertex
    
    m_mvfGenerated: MilVertexFormat,  // Vertex fields that are dyn

    m_mvfaAntiAliasScaleLocation: MilVertexFormatAttribute,  // Vertex field that
                                                             // contains PPAA
                                                             // falloff factor

    /*
public:

    static MilVertexFormat GetOutVertexFormat();

    static HRESULT Create(
        __in_ecount(1) CHwTVertexBuffer<TVertex> *pVertexBuffer,
        MilVertexFormat mvfIn,
        MilVertexFormat mvfOut,
        MilVertexFormatAttribute mvfaAntiAliasScaleLocation,
        __inout_ecount(1) CBufferDispenser *pBufferDispenser,
        __deref_out_ecount(1) typename CHwTVertexBuffer<TVertex>::Builder **ppVertexBufferBuilder
        );

    HRESULT SetConstantMapping(
        MilVertexFormatAttribute mvfaDestination,
        __in_ecount(1) const CHwConstantColorSource *pConstCS
        );

    void SetTransformMapping(
        __in_ecount(1) const MILMatrix3x2 &mat2DTransform
        );

    HRESULT FinalizeMappings(
        );

    void SetOutsideBounds(
        __in_ecount_opt(1) const CMILSurfaceRect *prcBounds,
        bool fNeedInside
        );

    bool HasOutsideBounds() const
    {
        return NeedOutsideGeometry();
    }

    HRESULT BeginBuilding(
        );

    HRESULT AddVertex(
        __in_ecount(1) const MilPoint2F &ptPosition,
            // In: Vertex coordinates
        __out_ecount(1) WORD *pIndex
            // Out: The index of the new vertex
        );

    HRESULT AddIndexedVertices(
        UINT cVertices,                                                  // In: number of vertices                                                                                            
        __in_bcount(cVertices*uVertexStride) const void *pVertexBuffer,  // In: vertex buffer containing the vertices                                                                         
        UINT uVertexStride,                                              // In: size of each vertex                                                                                           
        MilVertexFormat mvfFormat,                                       // In: format of each vertex                                                                                         
        UINT cIndices,                                                   // In: Number of indices                                                                                             
        __in_ecount(cIndices) const UINT *puIndexBuffer                  // In: index buffer                                                             
        );

    HRESULT AddTriangle(
        DWORD i1,                    // In: Index of triangle's first vertex
        DWORD i2,                    // In: Index of triangle's second vertex
        DWORD i3                     // In: Index of triangle's third vertex
        );

    HRESULT AddComplexScan(
        INT nPixelY,
            // In: y coordinate in pixel space
        __in_ecount(1) const CCoverageInterval *pIntervalSpanStart
            // In: coverage segments
        );

   HRESULT AddParallelogram(
        __in_ecount(4)  const MilPoint2F *rgPosition
        );
   
    HRESULT AddTrapezoid(
        float rPixelYTop,               // In: y coordinate of top of trapezoid
        float rPixelXTopLeft,           // In: x coordinate for top left
        float rPixelXTopRight,          // In: x coordinate for top right
        float rPixelYBottom,            // In: y coordinate of bottom of trapezoid
        float rPixelXBottomLeft,        // In: x coordinate for bottom left
        float rPixelXBottomRight,       // In: x coordinate for bottom right
        float rPixelXLeftDelta,         // In: trapezoid expand radius for left edge
        float rPixelXRightDelta         // In: trapezoid expand radius for right edge
        );

    BOOL IsEmpty();

    HRESULT EndBuilding(
        __deref_opt_out_ecount(1) CHwVertexBuffer **ppVertexBuffer
        );

    HRESULT FlushInternal(
        __deref_opt_out_ecount_opt(1) CHwVertexBuffer **ppVertexBuffer
        );
            
private:

    // Helpers that do AddTrapezoid.  Same parameters
    HRESULT AddTrapezoidStandard( float, float, float, float, float, float, float, float );
    HRESULT AddTrapezoidWaffle( float, float, float, float, float, float, float, float );


    
    HRESULT PrepareStratumSlow(
        float rStratumTop,
        float rStratumBottom,
        bool fTrapezoid,
        float rTrapezoidLeft,
        float rTrapezoidRight
        );
    
    // Wrap up building of outside geometry.
    HRESULT EndBuildingOutside();

    DECLARE_BUFFERDISPENSER_NEW(CHwTVertexBuffer<TVertex>::Builder,
                                Mt(CHwTVertexBuffer_Builder));

    Builder(
        __in_ecount(1) CHwTVertexBuffer<TVertex> *pVertexBuffer
    );

    HRESULT SetupConverter(
        MilVertexFormat mvfIn,
        MilVertexFormat mvfOut,
        MilVertexFormatAttribute mvfaAntiAliasScaleLocation
        );

    HRESULT RenderPrecomputedIndexedTriangles(
        __range(1, SHORT_MAX) UINT cVertices,
        __in_ecount(cVertices) const TVertex *rgoVertices,
        __range(1, UINT_MAX) UINT cIndices,
        __in_ecount(cIndices) const UINT *rguIndices
        );


    // Expands all vertices in the buffer.
    void ExpandVertices();
    
    // Has never been successfully used to declare a method or derived type...
/*    typedef void (CHwTVertexBuffer<TVertex>::Builder::FN_ExpandVertices)(
        UINT uCount,
        TVertex *pVertex
        );*/

    // error C2143: syntax error : missing ';' before '*'
//    typedef FN_ExpandVertices *PFN_ExpandVertices;

    typedef void (CHwTVertexBuffer<TVertex>::Builder::* PFN_ExpandVertices)(
        __range(1,UINT_MAX) UINT uCount,
        __inout_ecount_full(uCount) TVertex *rgVertices
        );

    //
    // Table of vertex expansion routines for common expansion cases:
    //  - There are entries for Z, Diffuse, and one set texture coordinates for
    //    a total of eight combinations.
    //  - Additionally there is a second set of entries for anti-aliasing
    //    falloff applied thru diffuse.
    //

    static const PFN_ExpandVertices sc_pfnExpandVerticesTable[8*2];

    MIL_FORCEINLINE
    void TransferAndOrExpandVerticesInline(
        __range(1,UINT_MAX) UINT uCount,
        __in_ecount(uCount) TVertex const * rgInputVertices,
        __out_ecount(uCount) TVertex *rgOutputVertices,
        MilVertexFormat mvfOut,
        MilVertexFormatAttribute mvfaScaleByFalloff,
        bool fInputOutputAreSameBuffer,
        bool fTransformPosition
        );

    // FN_ExpandVertices ExpandVerticesFast
    template <MilVertexFormat mvfOut, MilVertexFormatAttribute mvfaScaleByFalloff>
    void ExpandVerticesFast(
        __range(1,UINT_MAX) UINT uCount,
        __inout_ecount_full(uCount) TVertex *rgVertices
        )
    {
        TransferAndOrExpandVerticesInline(
            uCount, 
            rgVertices, 
            rgVertices, 
            mvfOut, 
            mvfaScaleByFalloff,
            true, // => fInputOutputAreSameBuffer
            false // => fTransformPosition
            );
    }

    // error C2146: syntax error : missing ';' before identifier 'ExpandVerticesGeneral'
    // error C2501: 'CHwTVertexBufferBuilder<TVertex>::FN_ExpandVertices' : missing storage-class or type specifiers
//    FN_ExpandVertices ExpandVerticesGeneral
//    typename FN_ExpandVertices ExpandVerticesGeneral
    // error C4346: 'CHwTVertexBufferBuilder<TVertex>::FN_ExpandVertices' : dependent name is not a type
//    CHwTVertexBufferBuilder<TVertex>::FN_ExpandVertices ExpandVerticesGeneral
    // Can't define methos here (unless not parameters are used).
//    typename CHwTVertexBufferBuilder<TVertex>::FN_ExpandVertices ExpandVerticesGeneral
    // FN_ExpandVertices ExpandVerticesGeneral
    void ExpandVerticesGeneral(
        __range(1,UINT_MAX) UINT uCount,
        __inout_ecount_full(uCount) TVertex *rgVertices
        )
    {
        TransferAndOrExpandVerticesInline(
            uCount, 
            rgVertices,
            rgVertices,
            m_mvfGenerated, 
            m_mvfaAntiAliasScaleLocation,
            true, // => fInputOutputAreSameBuffer
            false // => fTransformPosition
            );
    }

    void TransferAndExpandVerticesGeneral(
        __range(1,UINT_MAX) UINT uCount,
        __in_ecount(uCount) TVertex const *rgInputVertices,
        __out_ecount_full(uCount) TVertex *rgOutputVertices,
        bool fTransformPosition
        )
    {
        TransferAndOrExpandVerticesInline(
            uCount, 
            rgInputVertices,
            rgOutputVertices,
            m_mvfGenerated, 
            m_mvfaAntiAliasScaleLocation,
            false,              // => fInputOutputAreSameBuffer
            fTransformPosition  // => fTransformPosition
            );
    }

    // FN_ExpandVertices ExpandVerticesInvalid
    void ExpandVerticesInvalid(
        __range(1,UINT_MAX) UINT uCount,
        __inout_ecount_full(uCount) TVertex *rgVertices
        )
    {
        RIP("Invalid ExpandVertices routine.");
    }

    //+------------------------------------------------------------------------
    //
    //  Member:    NeedCoverageGeometry
    //
    //  Synopsis:  True if we should create geometry for a particular
    //             coverage value.
    //
    //-------------------------------------------------------------------------
    bool NeedCoverageGeometry(INT nCoverage) const;





    //+------------------------------------------------------------------------
    //
    //  Member:    ReinterpretFloatAsDWORD
    //
    //  Synopsis:  Quicky helper to convert a float to a DWORD bitwise.
    //
    //-------------------------------------------------------------------------
    static MIL_FORCEINLINE DWORD ReinterpretFloatAsDWORD(float c)
    {
        return reinterpret_cast<DWORD &>(c);
    }

private:
    MIL_FORCEINLINE bool AreWaffling() const
    {
        return m_map.AreWaffling();
    }
   
    void ViewportToPackedCoordinates(
        __range(1,UINT_MAX / uGroupSize) UINT uGroupCount,        
        __inout_ecount(uGroupCount * uGroupSize) TVertex *pVertex,
        __range(2,6) UINT uGroupSize,
        /*__range(0,NUM_OF_VERTEX_TEXTURE_COORDS(TVertex)-1)*/ __bound UINT uIndex
        );
    
    void ViewportToPackedCoordinates(
        __range(1,UINT_MAX / uGroupSize) UINT uGroupCount,
        __inout_ecount(uGroupCount * uGroupSize) TVertex *pVertex,
        __range(2,6) UINT uGroupSize
        );

    template<class TWaffler>
    __out_ecount(1) typename TWaffler::ISink *
    BuildWafflePipeline(
        __out_xcount(NUM_OF_VERTEX_TEXTURE_COORDS(TVertex) * 2) TWaffler *wafflers,
        __out_ecount(1) bool &fWafflersUsed
        ) const;

    
    template<class TWaffler>
    typename TWaffler::ISink *
    BuildWafflePipeline(
        __out_xcount(NUM_OF_VERTEX_TEXTURE_COORDS(TVertex) * 2) TWaffler *wafflers
        ) const
    {
        bool fNotUsed;
        return BuildWafflePipeline(wafflers, fNotUsed);
    }*/

    m_pVB: &'y mut CHwTVertexBuffer<'z, TVertex>,

    //m_pfnExpandVertices: PFN_ExpandVertices,  // Method for expanding vertices

    //m_rgoPrecomputedTriListVertices: *const TVertex,
    //m_cPrecomputedTriListVertices: UINT,

    //m_rguPrecomputedTriListIndices: *const UINT,
    //m_cPrecomputedTriListIndices: UINT,

    //m_map: CHwTVertexMappings<TVertex>,

    // This is true if we had to flush the pipeline as we were getting
    // geometry rather than just filling up a single vertex buffer.
    m_fHasFlushed: bool,

    // The next two members control the generation of the zero-alpha geometry
    // outside the input geometry.
    m_fNeedOutsideGeometry: bool,
    m_fNeedInsideGeometry: bool,
    m_rcOutsideBounds: CMILSurfaceRect, // Bounds for creation of outside geometry

    /* 
    // Helpful m_rcOutsideBounds casts.
    float OutsideLeft() const { return static_cast<float>(m_rcOutsideBounds.left); }
    float OutsideRight() const { return static_cast<float>(m_rcOutsideBounds.right); }
    float OutsideTop() const { return static_cast<float>(m_rcOutsideBounds.top); }
    float OutsideBottom() const { return static_cast<float>(m_rcOutsideBounds.bottom); }
    */
    // This interval (if we are doing outside) shows the location
    // of the current stratum.  It is initialized to [FLT_MAX, -FLT_MAX].
    //
    // If the current stratum is a complex span then
    // m_rCurStratumBottom is set to the bottom of the stratum and
    // m_rCurStratumTop is set to FLT_MAX.
    //
    // If the current stratum is a trapezoidal one, then
    // m_rCurStratumBottom is its bottom and m_rCurStratumTop is its
    // top.
    m_rCurStratumTop: f32,
    m_rCurStratumBottom: f32,

    // If the current stratum is a trapezoidal one, following var stores
    // right boundary of the last trapezoid handled by PrepareStratum.
    // We need it to cloze the stratus properly.
    m_rLastTrapezoidRight: f32,

    // These are needed to implement outside geometry using triangle lists
    m_rLastTrapezoidTopRight: f32,
    m_rLastTrapezoidBottomRight: f32,
}

/*
//+----------------------------------------------------------------------------
//
//  Member:    CHwVertexBuffer::AddTriangle
//
//  Synopsis:  Add a triangle using the three indices given to the list
//
impl CHwVertexBuffer {

fn AddTriangle(
    i1: WORD,         // In: Index of triangle's first vertex
    i2: WORD,         // In: Index of triangle's second vertex
    i3: WORD          // In: Index of triangle's third vertex
    ) -> HRESULT
{
    let hr: HRESULT = S_OK;

    // Asserting indices < max vertex requires a debug only pure virtual method
    // which is too much of a functionality change between retail and debug.
    //
    //
    // Assert(i1 < GetNumTriListVertices());
    // Assert(i2 < GetNumTriListVertices());
    // Assert(i3 < GetNumTriListVertices());

    WORD *pIndices;

    IFC(m_rgIndices.AddMultiple(3, &pIndices));

    pIndices[0] = i1;
    pIndices[1] = i2;
    pIndices[2] = i3;

Cleanup:
    RRETURN(hr);
}

//+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexBuffer<TVertex>::AddTriangle
//
//  Synopsis:  Add a triangle using given three points to the list
//
//-----------------------------------------------------------------------------
template <class TVertex>
HRESULT
CHwTVertexBuffer<TVertex>::AddTriangle(
    __in_ecount(1) const PointXYA &v0,
    __in_ecount(1) const PointXYA &v1,
    __in_ecount(1) const PointXYA &v2)
{
    let hr: HRESULT = S_OK;
    
    TVertex *pVertices;
    hr = AddNonIndexedTriListVertices(3,&pVertices);

    if (hr == E_OUTOFMEMORY)
    {
        DebugBreak ();
    }
    IFC(hr);
    
    pVertices[0].ptPt.X = v0.x;
    pVertices[0].ptPt.Y = v0.y;
    pVertices[0].Diffuse = reinterpret_cast<const DWORD &>(v0.a);
    pVertices[1].ptPt.X = v1.x;
    pVertices[1].ptPt.Y = v1.y;
    pVertices[1].Diffuse = reinterpret_cast<const DWORD &>(v1.a);
    pVertices[2].ptPt.X = v2.x;
    pVertices[2].ptPt.Y = v2.y;
    pVertices[2].Diffuse = reinterpret_cast<const DWORD &>(v2.a);

Cleanup:
    RRETURN(hr);
}
*/

impl CHwVertexBuffer<'_> {
//+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexBuffer<TVertex>::AddLine
//
//  Synopsis:  Add a nominal width line using given two points to the list
//
//-----------------------------------------------------------------------------
fn AddLine(&mut self,
    v0: &PointXYA,
    v1: &PointXYA
    ) -> HRESULT
{
    type TVertex = CD3DVertexXYZDUV2;
    let hr = S_OK;

    let pVertices: &mut [TVertex];
    let mut rgScratchVertices: [TVertex; 2] = Default::default();

    assert!(!(v0.y != v1.y));
    
    let fUseTriangles = /*(v0.y < m_pBuilder->GetViewportTop() + 1) ||*/ FORCE_TRIANGLES;

    //if (fUseTriangles)
    //{
        pVertices = &mut rgScratchVertices;
    //}
    //else
    //{
        //IFC!(AddLineListVertices(2, &pVertices));
    //}
    
    pVertices[0].x = v0.x;
    pVertices[0].y = v0.y;
    pVertices[0].coverage = v0.a;
    pVertices[1].x = v1.x;
    pVertices[1].y = v1.y;
    pVertices[1].coverage = v1.a;

    if (fUseTriangles)
    {
        IFC!(self.AddLineAsTriangleList(&pVertices[0],&pVertices[1]));
    }
    
    RRETURN!(hr);
}
}
/* 
//+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexBuffer<TVertex>::AddTriListVertices
//
//  Synopsis:  Reserve space for consecutive vertices and return start index
//

template <class TVertex>
MIL_FORCEINLINE
HRESULT
CHwTVertexBuffer<TVertex>::AddTriListVertices(
    UINT uDelta,
    __deref_ecount(uDelta) TVertex **ppVertices,
    __out_ecount(1) WORD *pwIndexStart
    )
{
    HRESULT hr = S_OK;

    Assert(ppVertices);

    UINT uCount = static_cast<UINT>(m_rgVerticesTriList.GetCount());
    if (uCount > SHRT_MAX)
    {
        IFC(WGXERR_INVALIDPARAMETER);
    }
    UINT newCount;
    newCount = uDelta + uCount;

    if (newCount > SHRT_MAX)
    {
        IFC(m_pBuilder->FlushReset());
        uCount = 0;
        newCount = uDelta;
    }

    if (newCount > m_rgVerticesTriList.GetCapacity())
    {
        IFC(m_rgVerticesTriList.ReserveSpace(uDelta));
    }

    m_rgVerticesTriList.SetCount(newCount);
    *pwIndexStart = static_cast<WORD>(uCount);
    *ppVertices = &m_rgVerticesTriList[uCount];

  Cleanup:
    RRETURN(hr);
}
*/

impl<TVertex: Clone + Default> CHwTVertexBuffer<'_, TVertex> {

fn AddTriVertices(&mut self, v0: TVertex, v1: TVertex, v2: TVertex) {
    if let Some(output_buffer) = &mut self.m_rgVerticesBuffer {
        let offset = self.m_rgVerticesBufferOffset;
        if offset + 3 <= output_buffer.len() {
            output_buffer[offset] = v0;
            output_buffer[offset + 1] = v1;
            output_buffer[offset + 2] = v2;
        }
        self.m_rgVerticesBufferOffset = offset + 3;
    } else {
        self.m_rgVerticesTriList.reserve(3);
        self.m_rgVerticesTriList.push(v0);
        self.m_rgVerticesTriList.push(v1);
        self.m_rgVerticesTriList.push(v2);
    }
}

fn AddTrapezoidVertices(&mut self, v0: TVertex, v1: TVertex, v2: TVertex, v3: TVertex) {
    if let Some(output_buffer) = &mut self.m_rgVerticesBuffer {
        let offset = self.m_rgVerticesBufferOffset;
        if offset + 6 <= output_buffer.len() {
            output_buffer[offset] = v0;
            output_buffer[offset + 1] = v1.clone();
            output_buffer[offset + 2] = v2.clone();

            output_buffer[offset + 3] = v1;
            output_buffer[offset + 4] = v2;
            output_buffer[offset + 5] = v3;
        }
        self.m_rgVerticesBufferOffset = offset + 6;
    } else {
        self.m_rgVerticesTriList.reserve(6);

        self.m_rgVerticesTriList.push(v0);
        self.m_rgVerticesTriList.push(v1.clone());
        self.m_rgVerticesTriList.push(v2.clone());

        self.m_rgVerticesTriList.push(v1);
        self.m_rgVerticesTriList.push(v2);
        self.m_rgVerticesTriList.push(v3);
    }
}

fn AddedNonLineSegment(&mut self) {
    #[cfg(debug_assertions)]
    {
        self.m_fDbgNonLineSegmentTriangleStrip = true;
    }
}

}

/* 
//+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexBuffer<TVertex>::AddNonIndexedTriListVertices
//
//  Synopsis:  Reserve space for triangle list vertices.
//

template <class TVertex>
MIL_FORCEINLINE
HRESULT
CHwTVertexBuffer<TVertex>::AddNonIndexedTriListVertices(
    UINT uCount,
    __deref_ecount(uCount) TVertex **ppVertices
    )
{
    HRESULT hr = S_OK;

    UINT Count = static_cast<UINT>(m_rgVerticesNonIndexedTriList.GetCount());
    UINT newCount = Count + uCount;

    if (newCount > m_rgVerticesNonIndexedTriList.GetCapacity())
    {
        IFC(m_rgVerticesNonIndexedTriList.ReserveSpace(uCount));
    }

    m_rgVerticesNonIndexedTriList.SetCount(newCount);
    *ppVertices = &m_rgVerticesNonIndexedTriList[Count];

Cleanup:
    RRETURN(hr);
}

//+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexBuffer<TVertex>::AddLineListVertices
//
//  Synopsis:  Reserve space for consecutive vertices
//

template <class TVertex>
MIL_FORCEINLINE
HRESULT
CHwTVertexBuffer<TVertex>::AddLineListVertices(
    UINT uCount,
    __deref_ecount(uCount) TVertex **ppVertices
    )
{
    HRESULT hr = S_OK;

    Assert(ppVertices);

    UINT Count = static_cast<UINT>(m_rgVerticesLineList.GetCount());
    UINT newCount = Count + uCount;

    if (newCount > m_rgVerticesLineList.GetCapacity())
    {
        IFC(m_rgVerticesLineList.ReserveSpace(uCount));
    }

    m_rgVerticesLineList.SetCount(newCount);
    *ppVertices = &m_rgVerticesLineList[Count];

Cleanup:
    RRETURN(hr);
}

//+----------------------------------------------------------------------------
//
//  Class:     CHwVertexBuffer::Builder
//
//-----------------------------------------------------------------------------

//+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexBuffer<TVertex>::Builder::GetOutVertexFormat
//
//  Synopsis:  Return MIL vertex format covered by specific builders
//
//-----------------------------------------------------------------------------

template <>
MilVertexFormat
CHwTVertexBuffer<CD3DVertexXYZDUV2>::Builder::GetOutVertexFormat()
{
    return (MILVFAttrXYZ | MILVFAttrDiffuse | MILVFAttrUV2);
}

template <>
MilVertexFormat
CHwTVertexBuffer<CD3DVertexXYZDUV8>::Builder::GetOutVertexFormat()
{
    return (MILVFAttrXYZ | MILVFAttrDiffuse | MILVFAttrUV8);
}

template <>
MilVertexFormat
CHwTVertexBuffer<CD3DVertexXYZDUV6>::Builder::GetOutVertexFormat()
{
    return (MILVFAttrXYZ | MILVFAttrDiffuse | MILVFAttrUV6);
}

template <>
MilVertexFormat
CHwTVertexBuffer<CD3DVertexXYZNDSUV4>::Builder::GetOutVertexFormat()
{
    return (MILVFAttrXYZ |
            MILVFAttrNormal |
            MILVFAttrDiffuse |
            MILVFAttrSpecular |
            MILVFAttrUV4);
}


//+----------------------------------------------------------------------------
//
//  Member:    CHwVertexBuffer::Builder::Create
//
//  Synopsis:  Choose the appropriate final vertex format and instantiate the
//             matching vertex builder
//
*/
pub type CHwVertexBufferBuilder<'y, 'z> = CHwTVertexBufferBuilder<'y, 'z, OutputVertex>;
impl<'y, 'z> CHwVertexBufferBuilder<'y, 'z> {
pub fn Create(
     vfIn: MilVertexFormat,
     vfOut: MilVertexFormat,
     mvfaAntiAliasScaleLocation: MilVertexFormatAttribute,
    pVertexBuffer: &'y mut CHwVertexBuffer<'z>,
    /*pBufferDispenser: &CBufferDispenser*/
    ) -> CHwVertexBufferBuilder<'y, 'z>
{
    CHwVertexBufferBuilder::CreateTemplate(pVertexBuffer, vfIn, vfOut, mvfaAntiAliasScaleLocation)
    //let hr: HRESULT = S_OK;

    //assert!(ppVertexBufferBuilder);

    //*ppVertexBufferBuilder = None;
/* 
    if (!(vfOut & ~CHwTVertexBuffer<CD3DVertexXYZDUV2>::Builder::GetOutVertexFormat()))
    {
        CHwTVertexBuffer<CD3DVertexXYZDUV2> *pVB = pDevice->GetVB_XYZDUV2();
        CHwTVertexBuffer<CD3DVertexXYZDUV2>::Builder *pVBB = NULL;

        IFC(CHwTVertexBuffer<CD3DVertexXYZDUV2>::Builder::Create(
            pVB,
            vfIn,
            vfOut,
            mvfaAntiAliasScaleLocation,
            pBufferDispenser,
            &pVBB
            ));
        
        *ppVertexBufferBuilder = pVBB;
    }
    else if (!(vfOut & ~CHwTVertexBuffer<CD3DVertexXYZDUV8>::Builder::GetOutVertexFormat()))
    {
        CHwTVertexBuffer<CD3DVertexXYZDUV8> *pVB = pDevice->GetVB_XYZRHWDUV8();
        CHwTVertexBuffer<CD3DVertexXYZDUV8>::Builder *pVBB = NULL;

        IFC(CHwTVertexBuffer<CD3DVertexXYZDUV8>::Builder::Create(
            pVB,
            vfIn,
            vfOut,
            mvfaAntiAliasScaleLocation,
            pBufferDispenser,
            &pVBB
            ));

        *ppVertexBufferBuilder = pVBB;
    }
    else
    {
        // NOTE-2004/03/22-chrisra Adding another vertexbuffer type requires updating enum
        //
        // If we add another buffer builder type kMaxVertexBuilderSize enum in hwvertexbuffer.h file
        // needs to be updated to reflect possible changes to the maximum size of buffer builders.
        //
        IFC(E_NOTIMPL);
    }

    // Store the pipeline, if any, which this VBB can use to spill the vertex buffer to if it
    // overflows.
    (**ppVertexBufferBuilder).m_pPipelineNoRef = pPipeline;
    (**ppVertexBufferBuilder).m_pDeviceNoRef = pDevice;


Cleanup:
    RRETURN(hr);*/
    //hr
}
    /*fn AreWafffling(&self) -> bool {
        false
    }*/

        // Helpful m_rcOutsideBounds casts.
        fn OutsideLeft(&self) -> f32  { return self.m_rcOutsideBounds.left as f32; }
        fn OutsideRight(&self) -> f32 { return self.m_rcOutsideBounds.right as f32; }
        fn OutsideTop(&self) -> f32 { return self.m_rcOutsideBounds.top as f32; }
        fn OutsideBottom(&self) -> f32 { return self.m_rcOutsideBounds.bottom as f32; }
}

//+----------------------------------------------------------------------------
//
//  Class:     THwTVertexMappings<class TVertex>
//
//-----------------------------------------------------------------------------

//+----------------------------------------------------------------------------
//
//  Member:    THwTVertexMappings<TVertex>::THwTVertexMappings
//
//  Synopsis:  ctor
//
//-----------------------------------------------------------------------------
/* 
template <class TVertex>
CHwTVertexMappings<TVertex>::CHwTVertexMappings()
 :
    m_mvfMapped(MILVFAttrNone)
{
    for (int i = 0; i < ARRAY_SIZE(m_rgWaffleMode); ++i)
    {
        m_rgWaffleMode[i] = WaffleModeNone;
    }

    m_matPos2DTransform.SetIdentity();
}


//+----------------------------------------------------------------------------
//
//  Member:    THwTVertexMappings<TVertex>::SetPositionTransform
//
//  Synopsis:  Sets the position transform that needs to be applied.
//
//-----------------------------------------------------------------------------
template <class TVertex>
void 
CHwTVertexMappings<TVertex>::SetPositionTransform(
    __in_ecount(1) const MILMatrix3x2 &matPositionTransform
    )
{
    m_matPos2DTransform = matPositionTransform;
}

//+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexMappings<TVertex>::SetConstantMapping
//
//  Synopsis:  Remember the static color for the given vertex field
//

template <class TVertex>
HRESULT
CHwTVertexMappings<TVertex>::SetConstantMapping(
    MilVertexFormatAttribute mvfaLocation,
    __in_ecount(1) const CHwConstantColorSource *pConstCS
    )
{
    HRESULT hr = S_OK;

    Assert(!(m_mvfMapped & mvfaLocation));
    pConstCS->GetColor(m_colorStatic);
    m_mvfMapped |= mvfaLocation;    // Remember this field has been mapped

    RRETURN(hr);
}

//+----------------------------------------------------------------------------
//
//  Function:  GetMILVFAttributeOfTextureCoord
//
//  Synopsis:  Compute MilVertexFormatAttribute for a texture coordinate index
//

MIL_FORCEINLINE
MilVertexFormat
GetMILVFAttributeOfTextureCoord(
    DWORD dwCoordIndex
    )
{
    return MILVFAttrUV1 << dwCoordIndex;
}

//+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexMappings<TVertex>::PointToUV
//
//  Synopsis:  Helper function to populate the texture coordinates at the given
//             index using the given point
//

template <class TVertex>
MIL_FORCEINLINE void
CHwTVertexMappings<TVertex>::PointToUV(
    __in_ecount(1) const MilPoint2F &ptIn,
    __bound UINT uIndex,
    __out_ecount(1) TVertex *pvOut
    )
{
    m_rgmatPointToUV[uIndex].TransformPoint(
        &pvOut->ptTx[uIndex],
        ptIn.X,
        ptIn.Y
        );
}





//+----------------------------------------------------------------------------
//
//  Class:     CHwTVertexBuffer<TVertex>::Builder
//
//-----------------------------------------------------------------------------


*/

impl<'y, 'z, TVertex: Default> CHwTVertexBufferBuilder<'y, 'z, TVertex> {

//+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexBuffer<TVertex>::Builder::Create
//
//  Synopsis:  Instantiate a specific type of vertex builder
//

fn CreateTemplate(
     pVertexBuffer: &'y mut CHwTVertexBuffer<'z, TVertex>,
     mvfIn: MilVertexFormat,
     mvfOut: MilVertexFormat,
     mvfaAntiAliasScaleLocation: MilVertexFormatAttribute,
     /*pBufferDispenser: __inout_ecount(1) CBufferDispenser *,*/
    ) -> Self
{



    let mut pVertexBufferBuilder = CHwTVertexBufferBuilder::<TVertex>::new(pVertexBuffer);

    IFC!(pVertexBufferBuilder.SetupConverter(
        mvfIn,
        mvfOut,
        mvfaAntiAliasScaleLocation
        ));

    return pVertexBufferBuilder;
}

//+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexBuffer<TVertex>::Builder::Builder
//
//  Synopsis:  ctor
//
//-----------------------------------------------------------------------------

fn new(pVertexBuffer: &'y mut CHwTVertexBuffer<'z, TVertex>) -> Self
{
    Self {
    m_pVB: pVertexBuffer,


    //m_rgoPrecomputedTriListVertices: NULL(),
    //m_cPrecomputedTriListVertices: 0,

    //m_rguPrecomputedTriListIndices: NULL(),
    //m_cPrecomputedTriListIndices: 0,

    // These two track the Y extent of the shape this builder is producing.
    m_rCurStratumTop: f32::MAX,
    m_rCurStratumBottom:  -f32::MAX,
    m_fNeedOutsideGeometry: false,
    m_fNeedInsideGeometry: true,

    m_rLastTrapezoidRight: -f32::MAX,
    m_rLastTrapezoidTopRight: -f32::MAX,
    m_rLastTrapezoidBottomRight: -f32::MAX,

    m_fHasFlushed: false,
    //m_map: Default::default(),
    m_rcOutsideBounds: Default::default(),
        #[cfg(debug_assertions)]
        m_mvfDbgOut: MilVertexFormatAttribute::MILVFAttrNone as MilVertexFormat,
        m_mvfIn: MilVertexFormatAttribute::MILVFAttrNone as MilVertexFormat,
        m_mvfGenerated: MilVertexFormatAttribute::MILVFAttrNone  as MilVertexFormat,
        m_mvfaAntiAliasScaleLocation: MilVertexFormatAttribute::MILVFAttrNone,
    }
}

//+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexBuffer<TVertex>::Builder::SetupConverter
//
//  Synopsis:  Choose the appropriate conversion method
//

fn SetupConverter(&mut self,
     mvfIn: MilVertexFormat,
     mvfOut: MilVertexFormat,
     mvfaAntiAliasScaleLocation: MilVertexFormatAttribute,
     ) -> HRESULT
{
    let hr = S_OK;

    self.m_mvfIn = mvfIn;

    #[cfg(debug_assertions)]
    {
    self.m_mvfDbgOut = mvfOut;
    }

    self.m_mvfGenerated = mvfOut & !self.m_mvfIn;
    self.m_mvfaAntiAliasScaleLocation = mvfaAntiAliasScaleLocation;

    assert!((self.m_mvfGenerated & MilVertexFormatAttribute::MILVFAttrXY as MilVertexFormat) == 0);

    RRETURN!(hr);
}
}
/* 

//+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexBuffer<TVertex>::Builder::SetTransformMapping
//
//  Synopsis:  Delegate mapping sets to CHwTVertexMappings
//
//-----------------------------------------------------------------------------

template <class TVertex>
void
CHwTVertexBuffer<TVertex>::Builder::SetTransformMapping(
    __in_ecount(1) const MILMatrix3x2 &mat2DPositionTransform
    )
{
    m_map.SetPositionTransform(mat2DPositionTransform);
}
                                                                    
template <class TVertex>
HRESULT
CHwTVertexBuffer<TVertex>::Builder::SetConstantMapping(
    MilVertexFormatAttribute mvfaLocation,
    __in_ecount(1) const CHwConstantColorSource *pConstCS
    )
{
    HRESULT hr = S_OK;

    IFC(m_map.SetConstantMapping(mvfaLocation, pConstCS));

Cleanup:
    RRETURN(hr);
}

//+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexBuffer<TVertex>::Builder::FinalizeMappings
//
//  Synopsis:  Complete setup of vertex mappings
//

template <class TVertex>
HRESULT
CHwTVertexBuffer<TVertex>::Builder::FinalizeMappings(
    )
{
    HRESULT hr = S_OK;

    //
    // Set default Z if required.
    //

    if (m_mvfGenerated & MILVFAttrZ)
    {
        if (!(m_map.m_mvfMapped & MILVFAttrZ))
        {
            m_map.m_vStatic.Z = 0.5f;
        }
    }

    //
    // If AA falloff is not going to scale the diffuse color and it is
    // generated then see if the color is constant such that we can do any
    // complex conversions just once here instead of in every iteration of the
    // expansion loop.  If AA falloff is going to scale the diffuse color then
    // we can still optimize for the falloff = 1.0 case by precomputing that
    // color now and checking for 1.0 during generation.  Such a precomputation
    // has shown significant to performance.
    //

    if (m_mvfGenerated & MILVFAttrDiffuse)
    {
        if (m_map.m_mvfMapped & MILVFAttrDiffuse)
        {

            // Assumes diffuse color is constant
            m_map.m_vStatic.Diffuse =
                Convert_MilColorF_scRGB_To_Premultiplied_MilColorB_sRGB(&m_map.m_colorStatic);
        }
        else
        {
            // Set default Diffuse value: White
            m_map.m_vStatic.Diffuse = MIL_COLOR(0xFF,0xFF,0xFF,0xFF);
        }
    }

    RRETURN(hr);
}*/
impl<TVertex> CHwTVertexBufferBuilder<'_, '_, TVertex> {

//+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexBuffer<TVertex>::Builder::SetOutsideBounds
//
//
//  Synopsis:  Enables rendering geometry for areas outside the shape but
//             within the bounds.  These areas will be created with
//             zero alpha.
//

pub fn SetOutsideBounds(&mut self,
    prcOutsideBounds: Option<&CMILSurfaceRect>,
    fNeedInside: bool,
    )
{
    // Waffling and outside bounds is not currently implemented.  It's
    // not difficult to do but currently there is no need.
    //assert!(!(self.AreWaffling() && self.prcOutsideBounds));

    if let Some(prcOutsideBounds) = prcOutsideBounds
    {
        self.m_rcOutsideBounds = prcOutsideBounds.clone();
        self.m_fNeedOutsideGeometry = true;
        self.m_fNeedInsideGeometry = fNeedInside;
    }
    else
    {
        self.m_fNeedOutsideGeometry = false;
        self.m_fNeedInsideGeometry = true;
    }
}

//+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexBuffer<TVertex>::Builder::BeginBuilding
//
//  Synopsis:  Prepare for a new primitive by resetting the vertex buffer
//
pub fn BeginBuilding(&mut self,
    ) -> HRESULT
{
    
    let hr: HRESULT = S_OK;

    self.m_fHasFlushed = false;
    self.m_pVB.Reset(/*self*/);

    RRETURN!(hr);
}
}
impl IGeometrySink for CHwVertexBufferBuilder<'_, '_> {

    fn AddTrapezoid(&mut self,
        rPixelYTop: f32,              // In: y coordinate of top of trapezoid
        rPixelXTopLeft: f32,          // In: x coordinate for top left
        rPixelXTopRight: f32,         // In: x coordinate for top right
        rPixelYBottom: f32,           // In: y coordinate of bottom of trapezoid
        rPixelXBottomLeft: f32,       // In: x coordinate for bottom left
        rPixelXBottomRight: f32,      // In: x coordinate for bottom right
        rPixelXLeftDelta: f32,        // In: trapezoid expand radius for left edge
        rPixelXRightDelta: f32        // In: trapezoid expand radius for right edge
        ) -> HRESULT
    {
        let hr = S_OK;
    
        if (/*self.AreWaffling()*/ false)
        {
            /*IFC(AddTrapezoidWaffle(
                    rPixelYTop,
                    rPixelXTopLeft,
                    rPixelXTopRight,
                    rPixelYBottom,
                    rPixelXBottomLeft,
                    rPixelXBottomRight,
                    rPixelXLeftDelta,
                    rPixelXRightDelta));*/
        }
        else
        {
            IFC!(self.AddTrapezoidStandard(
                    rPixelYTop,
                    rPixelXTopLeft,
                    rPixelXTopRight,
                    rPixelYBottom,
                    rPixelXBottomLeft,
                    rPixelXBottomRight,
                    rPixelXLeftDelta,
                    rPixelXRightDelta));
        }
    
    //Cleanup:
        RRETURN!(hr);
    }
    

    fn IsEmpty(&self) -> bool {
        self.m_pVB.IsEmpty()
    }

/* 

//+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexBuffer<TVertex>::Builder::AddVertex
//
//  Synopsis:  Add a vertex to the vertex buffer
//
//             Remember just the given vertex information now and convert later
//             in a single, more optimal pass.
//

template <class TVertex>
HRESULT
CHwTVertexBuffer<TVertex>::Builder::AddVertex(
    __in_ecount(1) const MilPoint2F &ptPosition,
        // Vertex coordinates
    __out_ecount(1) WORD *pIndex
        // The index of the new vertex
    )
{
    HRESULT hr = S_OK;

    Assert(!NeedOutsideGeometry());
    Assert(m_mvfIn == MILVFAttrXY);

    TVertex *pVertex;

    IFC(m_pVB->AddTriListVertices(1, &pVertex, pIndex));

    pVertex->ptPt = ptPosition;

    //  store coverage as a DWORD instead of float

    pVertex->Diffuse = FLOAT_ONE;

Cleanup:
    RRETURN(hr);
}

//+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexBuffer<TVertex>::Builder::AddIndexedVertices, IGeometrySink
//
//  Synopsis:  Add a fully computed, indexed vertex to the vertex buffer
//

template <class TVertex>
HRESULT
CHwTVertexBuffer<TVertex>::Builder::AddIndexedVertices(
    UINT cVertices,
        // In: number of vertices                                                       
    __in_bcount(cVertices*uVertexStride) const void *pVertexBufferNoRef,
        // In: vertex buffer containing the vertices                                    
    UINT uVertexStride,
        // In: size of each vertex                                                      
    MilVertexFormat mvfFormat,
        // In: format of each vertex                                                    
    UINT cIndices,
        // In: Number of indices                                                        
    __in_ecount(cIndices) const UINT *puIndexBuffer
        // In: index buffer                                                             
    )
{
    Assert(m_mvfIn & (MILVFAttrXYZ | MILVFAttrDiffuse | MILVFAttrUV2));
    Assert(mvfFormat == (MILVFAttrXYZ | MILVFAttrDiffuse | MILVFAttrUV2));

    Assert(uVertexStride == sizeof(TVertex));

    m_rgoPrecomputedTriListVertices = reinterpret_cast<const TVertex *>(pVertexBufferNoRef);
    m_cPrecomputedTriListVertices = cVertices;

    m_rguPrecomputedTriListIndices = puIndexBuffer;
    m_cPrecomputedTriListIndices = cIndices;

    return S_OK;
}

//+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexBuffer<TVertex>::Builder::AddTriangle
//
//  Synopsis:  Add a triangle to the vertex buffer
//

template <class TVertex>
HRESULT
CHwTVertexBuffer<TVertex>::Builder::AddTriangle(
    DWORD i1,                    // In: Index of triangle's first vertex
    DWORD i2,                    // In: Index of triangle's second vertex
    DWORD i3                     // In: Index of triangle's third vertex
    )
{
    HRESULT hr = S_OK;

    Assert(!NeedOutsideGeometry());

    if (AreWaffling())
    {
        TVertex *pVertex;
        UINT uNumVertices;
        m_pVB->GetTriListVertices(&pVertex, &uNumVertices);

        Assert(i1 < uNumVertices);
        Assert(i2 < uNumVertices);
        Assert(i3 < uNumVertices);

        PointXYA rgPoints[3];
        rgPoints[0].x = pVertex[i1].ptPt.X;
        rgPoints[0].y = pVertex[i1].ptPt.Y;
        rgPoints[0].a = 1;
        rgPoints[1].x = pVertex[i2].ptPt.X;
        rgPoints[1].y = pVertex[i2].ptPt.Y;
        rgPoints[1].a = 1;
        rgPoints[2].x = pVertex[i3].ptPt.X;
        rgPoints[2].y = pVertex[i3].ptPt.Y;
        rgPoints[2].a = 1;
        
        TriangleWaffler<PointXYA> wafflers[NUM_OF_VERTEX_TEXTURE_COORDS(TVertex) * 2];
        TriangleWaffler<PointXYA>::ISink *pWaffleSinkNoRef = BuildWafflePipeline(wafflers);
        IFC(pWaffleSinkNoRef->AddTriangle(rgPoints[0], rgPoints[1], rgPoints[2]));
    }
    else
    {
        IFC(m_pVB->AddTriangle(
                static_cast<WORD>(i1),
                static_cast<WORD>(i2),
                static_cast<WORD>(i3)
                ));
    }
    
Cleanup:
    RRETURN(hr);
}
*/


//+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexBuffer<TVertex>::Builder::AddComplexScan
//
//  Synopsis:  Add a coverage span to the vertex buffer
//
//-----------------------------------------------------------------------------
    fn AddComplexScan(&mut self,
        nPixelY: INT,
            // In: y coordinate in pixel space
            mut pIntervalSpanStart: Ref<crate::aacoverage::CCoverageInterval>
            // In: coverage segments
        ) -> HRESULT {

    let hr: HRESULT = S_OK;
    //let pVertex: *mut CD3DVertexXYZDUV2 = NULL();

    IFC!(self.PrepareStratum((nPixelY) as f32,
                  (nPixelY+1) as f32, 
                  false, /* Not a trapezoid. */ 
                  0., 0.,
                0., 0., 0., 0.));

    let rPixelY: f32;
    rPixelY = (nPixelY) as f32 + 0.5;

    //LineWaffler<PointXYA> wafflers[NUM_OF_VERTEX_TEXTURE_COORDS(TVertex) * 2];

    // Use sink for waffling & the first line fix up (aka the complicated cases.)
    //ILineSink<PointXYA> *pLineSink = NULL;
    let mut pLineSink = None;

    /*if (self.AreWaffling())
    {
        bool fWafflersUsed;
        pLineSink = BuildWafflePipeline(wafflers, OUT fWafflersUsed);
        if (!fWafflersUsed)
        {
            pLineSink = NULL;
        }
    }*/
    
    // Use triangles instead of lines, for lines too close to the top of the viewport
    // because lines are clipped (before rasterization) against a viewport that only
    // includes half of the top pixel row.  Waffling will take care of this separately.
    if (/*pLineSink.is_none() && rPixelY < self.GetViewportTop() + 1 ||*/ FORCE_TRIANGLES)
    {
        pLineSink = Some(&mut self.m_pVB);
    }

    //
    // Output all segments if creating outside geometry, otherwise only output segments
    // with non-zero coverage.
    //

    if (pLineSink.is_none())
    {
        /* 
        UINT nSegmentCount = 0;

        for (const CCoverageInterval *pIntervalSpanTemp = pIntervalSpanStart;
             pIntervalSpanTemp->m_nPixelX != INT_MAX;
             pIntervalSpanTemp = pIntervalSpanTemp->m_pNext
             )
        {
            if (NeedCoverageGeometry(pIntervalSpanTemp->m_nCoverage))
            {
                ++nSegmentCount;
            }
        }

        //
        // Add vertices
        //
        if (nSegmentCount)
        {
            IFC(m_pVB->AddLineListVertices(nSegmentCount*2, &pVertex));
        }*/
    }

    //
    // Having allocated space (if not using sink), now let's actually output the vertices.
    //

    while ((*pIntervalSpanStart).m_nPixelX.get() != INT::MAX)
    {
        assert!(!(*pIntervalSpanStart).m_pNext.get().is_null());

        //
        // Output line list segments
        //
        // Note that line segments light pixels by going through the the
        // "diamond" interior of a pixel.  While we could accomplish this
        // by going from left edge to right edge of pixel, D3D10 uses the
        // convention that the LASTPIXEL is never lit.  We respect that now
        // by setting D3DRS_LASTPIXEL to FALSE and use line segments that
        // start in center of first pixel and end in center of one pixel
        // beyond last.
        //
        // Since our top left corner is integer, we add 0.5 to get to the
        // pixel center.
        //
        if (self.NeedCoverageGeometry((*pIntervalSpanStart).m_nCoverage.get()))
        {
            let rCoverage: f32 = ((*pIntervalSpanStart).m_nCoverage.get() as f32)/(c_nShiftSizeSquared as f32);
            
            let mut iBegin: LONG = (*pIntervalSpanStart).m_nPixelX.get();
            let mut iEnd: LONG = (*(*pIntervalSpanStart).m_pNext.get()).m_nPixelX.get();
            if (self.NeedOutsideGeometry())
            {
                // Intersect the interval with the outside bounds to create
                // start and stop lines.  The scan begins (ends) with an
                // interval starting (ending) at -inf (+inf).

                // The given geometry is not guaranteed to be within m_rcOutsideBounds but
                // the additional inner min and max (in that order) produce empty spans
                // for intervals not intersecting m_rcOutsideBounds.
                //
                // We could cull here but that should really be done by the geometry
                // generator.

                iBegin = iBegin.max(iEnd.min(self.m_rcOutsideBounds.left));
                iEnd = iEnd.min(iBegin.max(self.m_rcOutsideBounds.right));
            }
            let rPixelXBegin: f32= (iBegin as f32) + 0.5;
            let rPixelXEnd: f32 = (iEnd as f32) + 0.5;

            //
            // Output line (linelist or tristrip) for a pixel
            //

            //if let Some(pLineSink) = pLineSink 
            {
                let mut v0: PointXYA = Default::default(); let mut v1: PointXYA = Default::default();
                v0.x = rPixelXBegin;
                v0.y = rPixelY;
                v0.a = rCoverage;

                v1.x = rPixelXEnd;
                v1.y = rPixelY;
                v1.a = rCoverage;

                IFC!(self.m_pVB.AddLine(&v0,&v1));
            }
            //else
            {
                /* 
                let dwDiffuse = ReinterpretFloatAsDWORD(rCoverage);

                pVertex[0].ptPt.X = rPixelXBegin;
                pVertex[0].ptPt.Y = rPixelY;
                pVertex[0].Diffuse = dwDiffuse;

                pVertex[1].ptPt.X = rPixelXEnd;
                pVertex[1].ptPt.Y = rPixelY;
                pVertex[1].Diffuse = dwDiffuse;

                // Advance output vertex pointer
                pVertex += 2;*/
            }
        }

        //
        // Advance coverage buffer
        //

        pIntervalSpanStart = (*pIntervalSpanStart).m_pNext.get();
    }


//Cleanup:
    RRETURN!(hr);

}
}

//+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexBuffer<TVertex>::Builder::AddLineAsTriangleList
//
//  Synopsis:  Adds a horizontal line as a triangle list to work around
//             issue in D3D9 where horizontal lines with y = 0 may not render.
//
//              Line clipping in D3D9
//             This behavior will change in D3D10 and this work-around will no
//             longer be needed.  (Pixel center conventions will also change.)
//              
//-----------------------------------------------------------------------------
impl CHwVertexBuffer<'_> {
    fn AddLineAsTriangleList(&mut self,
    pBegin: &CD3DVertexXYZDUV2, // Begin
    pEnd: &CD3DVertexXYZDUV2    // End
    ) -> HRESULT
{
    let hr = S_OK;

    // Collect pertinent data from vertices.
    debug_assert!(pBegin.y == pEnd.y);
    debug_assert!(pBegin.coverage == pEnd.coverage);

    // Offset begin and end X left by 0.5 because the line starts on the first
    // pixel center and ends on the center of the pixel after the line segment.
    let x0 = pBegin.x - 0.5;
    let x1 = pEnd.x - 0.5;
    let y = pBegin.y;
    let dwDiffuse = pBegin.coverage;

    //
    // Add the vertices
    //

    // OpenGL doesn't specify how vertex positions are converted to fixed point prior to rasterization. On macOS, with AMD GPUs,
    // the GPU appears to truncate to fixed point instead of rounding. This behaviour is controlled by PA_SU_VTX_CNTL
    // register. To handle this we'll add a 1./512. subpixel bias to the center vertex to cause the coordinates to round instead
    // of truncate.
    //
    // D3D11 requires the fixed point integer result to be within 0.6ULP which implicitly disallows the truncate behaviour above.
    // This means that D2D doesn't need to deal with this problem.
    let subpixel_bias = self.subpixel_bias;


    // Use a single triangle to cover the entire line
    self.AddTriVertices(
        OutputVertex{ x: x0, y: y - 0.5, coverage: dwDiffuse },
        OutputVertex{ x: x0, y: y + 0.5, coverage: dwDiffuse },
        OutputVertex{ x: x1, y: y + subpixel_bias, coverage: dwDiffuse },
    );

    self.AddedNonLineSegment();

  //Cleanup:
    RRETURN!(hr);
}
}

/* 
//+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexBuffer<TVertex>::Builder::AddParallelogram
//
//  Synopsis:  This function adds the coordinates of a parallelogram to the vertex strip buffer. 
//
//  Parameter: rgPosition contains four coordinates of the parallelogram. Coordinates should have 
//              a winding order
//
//-----------------------------------------------------------------------------
template <class TVertex>
HRESULT
CHwTVertexBuffer<TVertex>::Builder::AddParallelogram(
        __in_ecount(4)  const MilPoint2F *rgPosition
        )
{
    HRESULT hr = S_OK;

    if (AreWaffling())
    {
        PointXYA rgPoints[4];
        for (int i = 0; i < 4; ++i)
        {
            rgPoints[i].x = rgPosition[i].X;
            rgPoints[i].y = rgPosition[i].Y;
            rgPoints[i].a = 1;
        }
        TriangleWaffler<PointXYA> wafflers[NUM_OF_VERTEX_TEXTURE_COORDS(TVertex) * 2];
        TriangleWaffler<PointXYA>::ISink *pWaffleSinkNoRef = BuildWafflePipeline(wafflers);
        IFC(pWaffleSinkNoRef->AddTriangle(rgPoints[0], rgPoints[1], rgPoints[3]));
        IFC(pWaffleSinkNoRef->AddTriangle(rgPoints[3], rgPoints[1], rgPoints[2]));
    }
    else
    {
        TVertex *pVertex;
  
        //
        // Add the vertices
        //

        IFC(m_pVB->AddTriStripVertices(6, &pVertex));

        //
        // Duplicate the first vertex. This creates 2 degenerate triangles: one connecting
        // the previous rect to this one and another between vertices 0 and 1.
        //

        pVertex[0].ptPt = rgPosition[0];
        pVertex[0].Diffuse = FLOAT_ONE;

        pVertex[1].ptPt = rgPosition[0];
        pVertex[1].Diffuse = FLOAT_ONE;
    
        pVertex[2].ptPt = rgPosition[1];
        pVertex[2].Diffuse = FLOAT_ONE;

        pVertex[3].ptPt = rgPosition[3];
        pVertex[3].Diffuse = FLOAT_ONE;

        pVertex[4].ptPt = rgPosition[2];
        pVertex[4].Diffuse = FLOAT_ONE;

        //
        // Duplicate the last vertex. This creates 2 degenerate triangles: one
        // between vertices 4 and 5 and one connecting this Rect to the
        // next one.
        //

        pVertex[5].ptPt = rgPosition[2];
        pVertex[5].Diffuse = FLOAT_ONE;
    }
        
  Cleanup:
    RRETURN(hr);
}
    
//+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexBuffer<TVertex>::Builder::BuildWafflePipeline<TWaffler>
//
//  Synopsis:  Builds a pipeline of wafflers into the provided array of wafflers.
//             And returns a pointer (not to be deleted) to the input sink
//             of the waffle pipeline.
//             the final result is sinked int m_pVB.
//
//-----------------------------------------------------------------------------

template<class TVertex>
template<class TWaffler>
__out_ecount(1) typename TWaffler::ISink *
CHwTVertexBuffer<TVertex>::Builder::BuildWafflePipeline(
        __out_xcount(NUM_OF_VERTEX_TEXTURE_COORDS(TVertex) * 2) TWaffler *wafflers,
        __out_ecount(1) bool &fWafflersUsed
    ) const
{
    UINT count = 0;

    for (int i = 0; i < NUM_OF_VERTEX_TEXTURE_COORDS(TVertex); ++i)
    {
        if (m_map.m_rgWaffleMode[i] != 0)
        {
            const MILMatrix3x2 &pMatWaffle = m_map.m_rgmatPointToUV[i];

            // Each column ([a,b,c] transpose) of this matrix specifies a waffler that
            // partitions the plane into regions between the lines:
            //                    ax + by + c = k
            // for every integer k.
            //
            // If this partition width is substantially less than a pixel we have
            // serious problems with waffling generating too many triangles for
            // doubtful visual effect so we don't perform a waffling with width less
            // than c_rMinWaffleWidthPixels.  So we need to know the width of the partition
            // regions:
            //
            // Changing c just translates the partition so let's assume c = 0.
            // The line ax + by = 0 goes through the origin and the line ax + by
            // = 1 is adjacent to it in the partition.  The distance between
            // these lines is also the distance from ax + by = 1 to the origin.
            // Using Lagrange multipliers we can determine that this distance
            // is
            //                     1/sqrt(a*a+b*b).
            // We want to avoid waffling if this is less than c_rMinWaffleWidthPixels
            // or equivalently:
            //   1/sqrt(a*a+b*b) < c_rMinWaffleWidthPixels
            //     sqrt(a*a+b*b) > 1/c_rMinWaffleWidthPixels
            //          a*a+b*b  > 1/(c_rMinWaffleWidthPixels*c_rMinWaffleWidthPixels)
            //          

            const float c_rMaxWaffleMagnitude = 1/(c_rMinWaffleWidthPixels*c_rMinWaffleWidthPixels);
            
            float mag0 = pMatWaffle.m_00*pMatWaffle.m_00+pMatWaffle.m_10*pMatWaffle.m_10;
            if (mag0 < c_rMaxWaffleMagnitude)
            {
                wafflers[count].Set(pMatWaffle.m_00, pMatWaffle.m_10, pMatWaffle.m_20, wafflers+count+1);
                ++count;
            }

            float mag1 = pMatWaffle.m_01*pMatWaffle.m_01+pMatWaffle.m_11*pMatWaffle.m_11;
            if (mag1 < c_rMaxWaffleMagnitude)
            {
                wafflers[count].Set(pMatWaffle.m_01, pMatWaffle.m_11, pMatWaffle.m_21, wafflers+count+1);
                ++count;
            }
        }
    }

    if (count)
    {
        fWafflersUsed = true;
        // As the last step in the chain we send the triangles to our vertex buffer.
        wafflers[count-1].SetSink(m_pVB);
        return &wafflers[0];
    }
    else
    {
        fWafflersUsed = false;
        // If we built no wafflers then sink straight into the vertex buffer.
        return m_pVB;
    }
}


//+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexBuffer<TVertex>::Builder::IsEmpty
//
//  Synopsis:  Does our VB have any triangles/lines?
//
//-----------------------------------------------------------------------------
template <class TVertex>
BOOL
CHwTVertexBuffer<TVertex>::Builder::IsEmpty()
{
    return m_pVB->IsEmpty();
}
*/
//+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexBuffer<TVertex>::Builder::AddTrapezoid
//
//  Synopsis:  Add a trapezoid to the vertex buffer
//
//
//      left edge       right edge
//      ___+_________________+___      <<< top edge
//     /  +  /             \  +  \
//    /  +  /               \  +  \
//   /  +  /                 \  +  \
//  /__+__/___________________\__+__\  <<< bottom edge
//    + ^^                        +
//      delta
//
impl CHwVertexBufferBuilder<'_, '_> {

//+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexBuffer<TVertex>::Builder::AddTrapezoidStandard
//
//  Synopsis:  See AddTrapezoid.  This doesn't do waffling & uses tri strips.
//

fn AddTrapezoidStandard(&mut self,
    rPixelYTop: f32,              // In: y coordinate of top of trapezoid
    rPixelXTopLeft: f32,          // In: x coordinate for top left
    rPixelXTopRight: f32,         // In: x coordinate for top right
    rPixelYBottom: f32,           // In: y coordinate of bottom of trapezoid
    rPixelXBottomLeft: f32,       // In: x coordinate for bottom left
    rPixelXBottomRight: f32,      // In: x coordinate for bottom right
    rPixelXLeftDelta: f32,        // In: trapezoid expand radius for left edge
    rPixelXRightDelta: f32        // In: trapezoid expand radius for right edge
    ) -> HRESULT
{
    type TVertex = CD3DVertexXYZDUV2;
    let hr = S_OK;
    //TVertex *pVertex;

    IFC!(self.PrepareStratum(
        rPixelYTop,
        rPixelYBottom,
        true, /* Trapezoid */
        rPixelXTopLeft.min(rPixelXBottomLeft),
        rPixelXTopRight.max(rPixelXBottomRight),
        rPixelXTopLeft - rPixelXLeftDelta, rPixelXBottomLeft - rPixelXLeftDelta,
        rPixelXTopRight + rPixelXRightDelta, rPixelXBottomRight + rPixelXRightDelta
        ));
    
    //
    // Add the vertices
    //

 let fNeedOutsideGeometry: bool; let fNeedInsideGeometry: bool;
    fNeedOutsideGeometry = self.NeedOutsideGeometry();
    fNeedInsideGeometry = self.NeedInsideGeometry();

    //
    // Fill in the vertices
    //

    self.m_pVB.AddTrapezoidVertices(
        OutputVertex{
            x: rPixelXTopLeft - rPixelXLeftDelta,
            y: rPixelYTop,
            coverage: FLOAT_ZERO,
        },
        OutputVertex{
            x: rPixelXBottomLeft - rPixelXLeftDelta,
            y: rPixelYBottom,
            coverage: FLOAT_ZERO,
        },
        OutputVertex{
            x: rPixelXTopLeft + rPixelXLeftDelta,
            y: rPixelYTop,
            coverage: FLOAT_ONE,
        },
        OutputVertex{
            x: rPixelXBottomLeft + rPixelXLeftDelta,
            y: rPixelYBottom,
            coverage: FLOAT_ONE,
        }
    );


    if (fNeedInsideGeometry)
    {
        self.m_pVB.AddTrapezoidVertices(
            OutputVertex{
                x: rPixelXTopLeft + rPixelXLeftDelta,
                y: rPixelYTop,
                coverage: FLOAT_ONE,
            },
            OutputVertex{
                x: rPixelXBottomLeft + rPixelXLeftDelta,
                y: rPixelYBottom,
                coverage: FLOAT_ONE,
            },
            OutputVertex{
                x: rPixelXTopRight - rPixelXRightDelta,
                y: rPixelYTop,
                coverage: FLOAT_ONE,
            },
            OutputVertex{
                x: rPixelXBottomRight - rPixelXRightDelta,
                y: rPixelYBottom,
                coverage: FLOAT_ONE,
            }
        );
    }

    self.m_pVB.AddTrapezoidVertices(
        OutputVertex{
            x: rPixelXTopRight - rPixelXRightDelta,
            y: rPixelYTop,
            coverage: FLOAT_ONE,
        },
        OutputVertex{
            x: rPixelXBottomRight - rPixelXRightDelta,
            y: rPixelYBottom,
            coverage: FLOAT_ONE,
        },
        OutputVertex{
            x: rPixelXTopRight + rPixelXRightDelta,
            y: rPixelYTop,
            coverage: FLOAT_ZERO,
        },
        OutputVertex{
            x: rPixelXBottomRight + rPixelXRightDelta,
            y: rPixelYBottom,
            coverage: FLOAT_ZERO,
        }
    );

    if (!fNeedOutsideGeometry)
    {
        //
        // Duplicate the last vertex. This creates 2 degenerate triangles: one
        // between vertices 8 and 9 and one connecting this trapezoid to the
        // next one.
        //

        //pVertex.push(OutputVertex{
        //  x: rPixelXBottomRight + rPixelXRightDelta,
        //  y: rPixelYBottom,
        //  coverage: FLOAT_ZERO,
        //});
    }

    self.m_pVB.AddedNonLineSegment();

//Cleanup:
    RRETURN!(hr);
}
}
/* 
//+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexBuffer<TVertex>::Builder::AddTrapezoidWaffle
//
//  Synopsis:  See AddTrapezoid.  This adds a waffled trapezoid.
//
//-----------------------------------------------------------------------------
template <class TVertex>
HRESULT
CHwTVertexBuffer<TVertex>::Builder::AddTrapezoidWaffle(
    float rPixelYTop,              // In: y coordinate of top of trapezoid
    float rPixelXTopLeft,          // In: x coordinate for top left
    float rPixelXTopRight,         // In: x coordinate for top right
    float rPixelYBottom,           // In: y coordinate of bottom of trapezoid
    float rPixelXBottomLeft,       // In: x coordinate for bottom left
    float rPixelXBottomRight,      // In: x coordinate for bottom right
    float rPixelXLeftDelta,        // In: trapezoid expand radius for left edge
    float rPixelXRightDelta        // In: trapezoid expand radius for right edge
    )
{
    HRESULT hr = S_OK;

    // We have 2 (u & v) wafflers per texture coordinate that need waffling.
    TriangleWaffler<PointXYA> wafflers[NUM_OF_VERTEX_TEXTURE_COORDS(TVertex) * 2];
    bool fWafflersUsed = false;

    TriangleWaffler<PointXYA>::ISink *pWaffleSinkNoRef = BuildWafflePipeline(wafflers, OUT fWafflersUsed);

    PointXYA vertices[8];

    //
    // Fill in the strip vertices
    //

    // Nonstandard coverage mapping and waffling are not supported at the same time.
    Assert(!NeedOutsideGeometry());

    vertices[0].x = rPixelXTopLeft - rPixelXLeftDelta;
    vertices[0].y = rPixelYTop;
    vertices[0].a = 0;

    vertices[1].x = rPixelXBottomLeft - rPixelXLeftDelta;
    vertices[1].y = rPixelYBottom;
    vertices[1].a = 0;

    vertices[2].x = rPixelXTopLeft + rPixelXLeftDelta;
    vertices[2].y = rPixelYTop;
    vertices[2].a = 1;

    vertices[3].x = rPixelXBottomLeft + rPixelXLeftDelta;
    vertices[3].y = rPixelYBottom;
    vertices[3].a = 1;

    vertices[4].x = rPixelXTopRight - rPixelXRightDelta;
    vertices[4].y = rPixelYTop;
    vertices[4].a = 1;

    vertices[5].x = rPixelXBottomRight - rPixelXRightDelta;
    vertices[5].y = rPixelYBottom;
    vertices[5].a = 1;

    vertices[6].x = rPixelXTopRight + rPixelXRightDelta;
    vertices[6].y = rPixelYTop;
    vertices[6].a = 0;

    vertices[7].x = rPixelXBottomRight + rPixelXRightDelta;
    vertices[7].y = rPixelYBottom;
    vertices[7].a = 0;

    // Send the triangles in the strip through the waffle pipeline.
    for (int i = 0; i < 6; ++i)
    {
        IFC(pWaffleSinkNoRef->AddTriangle(vertices[i+1], vertices[i], vertices[i+2]));
    }

Cleanup:
    RRETURN(hr);
}
*/
impl CHwVertexBufferBuilder<'_, '_> {

    //+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexBuffer<TVertex>::Builder::NeedCoverageGeometry
//
//  Synopsis:  Returns true if the coverage value needs to be rendered
//             based on NeedInsideGeometry() and NeedOutsideGeometry()
//
//             Two cases where we don't need to generate geometry:
//              1. NeedInsideGeometry is false, and coverage is c_nShiftSizeSquared.
//              2. NeedOutsideGeometry is false and coverage is 0
//
//-----------------------------------------------------------------------------
fn NeedCoverageGeometry(&self,
    nCoverage: INT
    ) -> bool
{
    return    (self.NeedInsideGeometry()  || nCoverage != c_nShiftSizeSquared)
           && (self.NeedOutsideGeometry() || nCoverage != 0);
}

    //+------------------------------------------------------------------------
    //
    //  Member:    NeedOutsideGeometry
    //
    //  Synopsis:  True if we should create geometry with zero alpha for
    //             areas outside the input geometry but within a given
    //             bounding box.
    //
    //-------------------------------------------------------------------------
    fn NeedOutsideGeometry(&self) -> bool
    {
        return self.m_fNeedOutsideGeometry;
    }

        //+------------------------------------------------------------------------
    //
    //  Member:    NeedInsideGeometry
    //
    //  Synopsis:  True if we should create geometry for areas completely
    //             withing the input geometry (i.e. alpha 1.)  Should only
    //             be false if NeedOutsideGeometry is true.
    //
    //-------------------------------------------------------------------------
    fn NeedInsideGeometry(&self) -> bool
    {
        assert!(self.m_fNeedOutsideGeometry || self.m_fNeedInsideGeometry);
        return self.m_fNeedInsideGeometry;
    }



    // Helpers that handle extra shapes in trapezoid mode.
    fn PrepareStratum(&mut self,
        rStratumTop: f32,
        rStratumBottom: f32,
        fTrapezoid: bool,
        rTrapezoidLeft: f32,
        rTrapezoidRight: f32,
        rTrapezoidTopLeft: f32, // = 0
        rTrapezoidBottomLeft: f32, // = 0
        rTrapezoidTopRight: f32, // = 0
        rTrapezoidBottomRight: f32, // = 0

        ) -> HRESULT
    {
        return if self.NeedOutsideGeometry() {
            self.PrepareStratumSlow(
                rStratumTop,
                rStratumBottom,
                fTrapezoid,
                rTrapezoidLeft,
                rTrapezoidRight,
                rTrapezoidTopLeft,
                rTrapezoidBottomLeft,
                rTrapezoidTopRight,
                rTrapezoidBottomRight
                )
     } else { S_OK };
    }

//+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexBuffer<TVertex>::Builder::PrepareStratumSlow
//
//  Synopsis:  Call before producing a new stratum (complex span or trapezoid.)
//             Handles several tasks:
//               1. Producing between top of complement geometry & the 1st
//                  stratum or when a gap between strata occurs (because
//                  the geometry is not closed and has horizontal gaps.)
//                  Passing in FLT_MAX for rStratumTop and rStratumBottom
//                  Fills the gap between the last stratum and the bottom
//                  of the outside.
//               2. Begins and/or ends the triangle strip corresponding to
//                  a trapezoid row.
//               3. Updates status vars m_rCurStratumTop & m_rCurStratumBottom
//
//  Note:      Call PrepareStratum which inlines the check for NeedOutsideGeometry()
//             If NeedOutsideGeometry is false PrepareStratum() does nothing.
//             This (slow) version asserts NeedOutsideGeometry()
//
//-----------------------------------------------------------------------------
fn PrepareStratumSlow(&mut self,
    rStratumTop: f32,
    rStratumBottom: f32,
    fTrapezoid: bool,
    rTrapezoidLeft: f32,
    rTrapezoidRight: f32,
    rTrapezoidTopLeft: f32,
    rTrapezoidBottomLeft: f32,
    rTrapezoidTopRight: f32,
    rTrapezoidBottomRight: f32,
    ) -> HRESULT
{
    type TVertex = OutputVertex;
    let hr: HRESULT = S_OK;
    
    assert!(!(rStratumTop > rStratumBottom));
    assert!(self.NeedOutsideGeometry());

    // There's only once case where a stratum can go "backwards"
    // and that's when we're done building & calling from
    // EndBuildingOutside
        
    let fEndBuildingOutside: f32 = (rStratumBottom == self.OutsideBottom() &&
                                rStratumTop == self.OutsideBottom()) as i32 as f32;

    if (fEndBuildingOutside == 1.)
    {
        assert!(!fTrapezoid);
    }
    else
    {
        assert!(!(rStratumBottom < self.m_rCurStratumBottom));
    }
    
    if (   fEndBuildingOutside == 1.
        || rStratumBottom != self.m_rCurStratumBottom)
    {
        
        // New stratum starting now.  Two things to do
        //  1. Close out current trapezoid stratum if necessary.
        //  2. Begin new trapezoid stratum if necessary.
        
        if (self.m_rCurStratumTop != f32::MAX)
        {
            // we do not clip trapezoids so RIGHT boundary
            // of the stratus can be outside of m_rcOutsideBounds.
            
            let rOutsideRight: f32 = self.OutsideRight().max(self.m_rLastTrapezoidRight);

            // End current trapezoid stratum.

            self.m_pVB.AddTrapezoidVertices(
                OutputVertex{
                    x: self.m_rLastTrapezoidTopRight,
                    y: self.m_rCurStratumTop,
                    coverage: FLOAT_ZERO,
                },
                OutputVertex{
                    x: self.m_rLastTrapezoidBottomRight,
                    y: self.m_rCurStratumBottom,
                    coverage: FLOAT_ZERO,
                },
                OutputVertex{
                    x: rOutsideRight,
                    y: self.m_rCurStratumTop,
                    coverage: FLOAT_ZERO,
                },
                OutputVertex{
                    x: rOutsideRight,
                    y: self.m_rCurStratumBottom,
                    coverage: FLOAT_ZERO,
                }
            );
        }
        // Compute the gap between where the last stratum ended and where
        // this one begins.
        let flGap: f32 = rStratumTop - self.m_rCurStratumBottom;

        if (flGap > 0.)
        {
            // The "special" case of a gap at the beginning is caught here
            // using the sentinel initial value of m_rCurStratumBottom.

            let flRectTop: f32 = if self.m_rCurStratumBottom == -f32::MAX {
                              self.OutsideTop() } else {
                              self.m_rCurStratumBottom };
            let flRectBot: f32  = (rStratumTop as f32);

            // Produce rectangular for any horizontal intervals in the
            // outside bounds that have no generated geometry.
            assert!(self.m_rCurStratumBottom != -f32::MAX || self.m_rCurStratumTop == f32::MAX);

            let outside_left = self.OutsideLeft();
            let outside_right = self.OutsideRight();
            
            // Duplicate first vertex.
            self.m_pVB.AddTrapezoidVertices(
                OutputVertex{
                    x: outside_left,
                    y: flRectTop,
                    coverage: FLOAT_ZERO,
                },
                OutputVertex{
                    x: outside_left,
                    y: flRectBot,
                    coverage: FLOAT_ZERO,
                },
                OutputVertex{
                    x: outside_right,
                    y: flRectTop,
                    coverage: FLOAT_ZERO,
                },
                OutputVertex{
                    x: outside_right,
                    y: flRectBot,
                    coverage: FLOAT_ZERO,
                }
            );
        }

        if (fTrapezoid)
        {

            // we do not clip trapezoids so left boundary
            // of the stratus can be outside of m_rcOutsideBounds.
            
            let rOutsideLeft: f32 = self.OutsideLeft().min(rTrapezoidLeft);

            // Begin new trapezoid stratum.

            self.m_pVB.AddTrapezoidVertices(
                OutputVertex{
                    x: rOutsideLeft,
                    y: rStratumTop,
                    coverage: FLOAT_ZERO,
                },
                OutputVertex{
                    x: rOutsideLeft,
                    y: rStratumBottom,
                    coverage: FLOAT_ZERO,
                },
                OutputVertex{
                    x: rTrapezoidTopLeft,
                    y: rStratumTop,
                    coverage: FLOAT_ZERO,
                },
                OutputVertex{
                    x: rTrapezoidBottomLeft,
                    y: rStratumBottom,
                    coverage: FLOAT_ZERO,
                }
            );
        }
    }
    
    if (fTrapezoid)
    {
        self.m_rLastTrapezoidTopRight = rTrapezoidTopRight;
        self.m_rLastTrapezoidBottomRight = rTrapezoidBottomRight;
        self.m_rLastTrapezoidRight = rTrapezoidRight;
    }

    self.m_rCurStratumTop = if fTrapezoid { rStratumTop } else { f32::MAX };
    self.m_rCurStratumBottom = rStratumBottom;

    RRETURN!(hr);
}
 
//+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexBuffer<TVertex>::Builder::EndBuildingOutside
//
//  Synopsis:  Finish creating outside geometry.
//             1. If no geometry was created then just fill bounds.
//             2. Otherwise:
//                 A. End last trapezoid row
//                 B. Produce stop stratum
// 
//-----------------------------------------------------------------------------
fn EndBuildingOutside(&mut self) -> HRESULT
{
    return self.PrepareStratum(
        self.OutsideBottom(),
        self.OutsideBottom(),
        false, /* Not a trapezoid. */
        0., 0.,
        0., 0.,
        0., 0.,
        );
}

//+----------------------------------------------------------------------------
//
//  Member:    CHwTVertexBuffer<TVertex>::Builder::EndBuilding
//
//  Synopsis:  Expand all vertices to the full required format and return
//             vertex buffer.
//
//-----------------------------------------------------------------------------
pub fn EndBuilding(&mut self) -> HRESULT
{
    let hr = S_OK;

    IFC!(self.EndBuildingOutside());
    
//Cleanup:
    RRETURN!(hr);
}

}

[Dauer der Verarbeitung: 0.50 Sekunden, vorverarbeitet 2026-04-25]