// 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 // // 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, // Dynamic array of indices //m_pBuilder: Rc>, /* #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 // // 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 // // 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, // Indexed triangle list vertices //m_rgVerticesNonIndexedTriList: DynArray, // Non-indexed triangle list vertices m_rgVerticesTriList: DynArray, // Triangle strip vertices //m_rgVerticesLineList: DynArray, // 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:: { 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 { if self.m_rgVerticesBuffer.is_some() { Some(self.m_rgVerticesBufferOffset) } else { None } } } //+---------------------------------------------------------------------------- // // Class: CHwTVertexMappings // // 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 {/* 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 CHwTVertexBuffer<'_, TVertex> { pub fn Reset(&mut self, /*pVBB: &mut CHwTVertexBufferBuilder*/ ) { #[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::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 *pVertexBuffer, MilVertexFormat mvfIn, MilVertexFormat mvfOut, MilVertexFormatAttribute mvfaAntiAliasScaleLocation, __inout_ecount(1) CBufferDispenser *pBufferDispenser, __deref_out_ecount(1) typename CHwTVertexBuffer::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::Builder, Mt(CHwTVertexBuffer_Builder)); Builder( __in_ecount(1) CHwTVertexBuffer *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::Builder::FN_ExpandVertices)( UINT uCount, TVertex *pVertex );*/ // error C2143: syntax error : missing ';' before '*' // typedef FN_ExpandVertices *PFN_ExpandVertices; typedef void (CHwTVertexBuffer::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 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::FN_ExpandVertices' : missing storage-class or type specifiers // FN_ExpandVertices ExpandVerticesGeneral // typename FN_ExpandVertices ExpandVerticesGeneral // error C4346: 'CHwTVertexBufferBuilder::FN_ExpandVertices' : dependent name is not a type // CHwTVertexBufferBuilder::FN_ExpandVertices ExpandVerticesGeneral // Can't define methos here (unless not parameters are used). // typename CHwTVertexBufferBuilder::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(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 __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 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, // 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(m_rcOutsideBounds.left); } float OutsideRight() const { return static_cast(m_rcOutsideBounds.right); } float OutsideTop() const { return static_cast(m_rcOutsideBounds.top); } float OutsideBottom() const { return static_cast(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::AddTriangle // // Synopsis: Add a triangle using given three points to the list // //----------------------------------------------------------------------------- template HRESULT CHwTVertexBuffer::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(v0.a); pVertices[1].ptPt.X = v1.x; pVertices[1].ptPt.Y = v1.y; pVertices[1].Diffuse = reinterpret_cast(v1.a); pVertices[2].ptPt.X = v2.x; pVertices[2].ptPt.Y = v2.y; pVertices[2].Diffuse = reinterpret_cast(v2.a); Cleanup: RRETURN(hr); } */ impl CHwVertexBuffer<'_> { //+---------------------------------------------------------------------------- // // Member: CHwTVertexBuffer::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::AddTriListVertices // // Synopsis: Reserve space for consecutive vertices and return start index // template MIL_FORCEINLINE HRESULT CHwTVertexBuffer::AddTriListVertices( UINT uDelta, __deref_ecount(uDelta) TVertex **ppVertices, __out_ecount(1) WORD *pwIndexStart ) { HRESULT hr = S_OK; Assert(ppVertices); UINT uCount = static_cast(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(uCount); *ppVertices = &m_rgVerticesTriList[uCount]; Cleanup: RRETURN(hr); } */ impl 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::AddNonIndexedTriListVertices // // Synopsis: Reserve space for triangle list vertices. // template MIL_FORCEINLINE HRESULT CHwTVertexBuffer::AddNonIndexedTriListVertices( UINT uCount, __deref_ecount(uCount) TVertex **ppVertices ) { HRESULT hr = S_OK; UINT Count = static_cast(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::AddLineListVertices // // Synopsis: Reserve space for consecutive vertices // template MIL_FORCEINLINE HRESULT CHwTVertexBuffer::AddLineListVertices( UINT uCount, __deref_ecount(uCount) TVertex **ppVertices ) { HRESULT hr = S_OK; Assert(ppVertices); UINT Count = static_cast(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::Builder::GetOutVertexFormat // // Synopsis: Return MIL vertex format covered by specific builders // //----------------------------------------------------------------------------- template <> MilVertexFormat CHwTVertexBuffer::Builder::GetOutVertexFormat() { return (MILVFAttrXYZ | MILVFAttrDiffuse | MILVFAttrUV2); } template <> MilVertexFormat CHwTVertexBuffer::Builder::GetOutVertexFormat() { return (MILVFAttrXYZ | MILVFAttrDiffuse | MILVFAttrUV8); } template <> MilVertexFormat CHwTVertexBuffer::Builder::GetOutVertexFormat() { return (MILVFAttrXYZ | MILVFAttrDiffuse | MILVFAttrUV6); } template <> MilVertexFormat CHwTVertexBuffer::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::Builder::GetOutVertexFormat())) { CHwTVertexBuffer *pVB = pDevice->GetVB_XYZDUV2(); CHwTVertexBuffer::Builder *pVBB = NULL; IFC(CHwTVertexBuffer::Builder::Create( pVB, vfIn, vfOut, mvfaAntiAliasScaleLocation, pBufferDispenser, &pVBB )); *ppVertexBufferBuilder = pVBB; } else if (!(vfOut & ~CHwTVertexBuffer::Builder::GetOutVertexFormat())) { CHwTVertexBuffer *pVB = pDevice->GetVB_XYZRHWDUV8(); CHwTVertexBuffer::Builder *pVBB = NULL; IFC(CHwTVertexBuffer::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 // //----------------------------------------------------------------------------- //+---------------------------------------------------------------------------- // // Member: THwTVertexMappings::THwTVertexMappings // // Synopsis: ctor // //----------------------------------------------------------------------------- /* template CHwTVertexMappings::CHwTVertexMappings() : m_mvfMapped(MILVFAttrNone) { for (int i = 0; i < ARRAY_SIZE(m_rgWaffleMode); ++i) { m_rgWaffleMode[i] = WaffleModeNone; } m_matPos2DTransform.SetIdentity(); } //+---------------------------------------------------------------------------- // // Member: THwTVertexMappings::SetPositionTransform // // Synopsis: Sets the position transform that needs to be applied. // //----------------------------------------------------------------------------- template void CHwTVertexMappings::SetPositionTransform( __in_ecount(1) const MILMatrix3x2 &matPositionTransform ) { m_matPos2DTransform = matPositionTransform; } //+---------------------------------------------------------------------------- // // Member: CHwTVertexMappings::SetConstantMapping // // Synopsis: Remember the static color for the given vertex field // template HRESULT CHwTVertexMappings::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::PointToUV // // Synopsis: Helper function to populate the texture coordinates at the given // index using the given point // template MIL_FORCEINLINE void CHwTVertexMappings::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::Builder // //----------------------------------------------------------------------------- */ impl<'y, 'z, TVertex: Default> CHwTVertexBufferBuilder<'y, 'z, TVertex> { //+---------------------------------------------------------------------------- // // Member: CHwTVertexBuffer::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::::new(pVertexBuffer); IFC!(pVertexBufferBuilder.SetupConverter( mvfIn, mvfOut, mvfaAntiAliasScaleLocation )); return pVertexBufferBuilder; } //+---------------------------------------------------------------------------- // // Member: CHwTVertexBuffer::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::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::Builder::SetTransformMapping // // Synopsis: Delegate mapping sets to CHwTVertexMappings // //----------------------------------------------------------------------------- template void CHwTVertexBuffer::Builder::SetTransformMapping( __in_ecount(1) const MILMatrix3x2 &mat2DPositionTransform ) { m_map.SetPositionTransform(mat2DPositionTransform); } template HRESULT CHwTVertexBuffer::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::Builder::FinalizeMappings // // Synopsis: Complete setup of vertex mappings // template HRESULT CHwTVertexBuffer::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 CHwTVertexBufferBuilder<'_, '_, TVertex> { //+---------------------------------------------------------------------------- // // Member: CHwTVertexBuffer::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::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::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 HRESULT CHwTVertexBuffer::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::Builder::AddIndexedVertices, IGeometrySink // // Synopsis: Add a fully computed, indexed vertex to the vertex buffer // template HRESULT CHwTVertexBuffer::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(pVertexBufferNoRef); m_cPrecomputedTriListVertices = cVertices; m_rguPrecomputedTriListIndices = puIndexBuffer; m_cPrecomputedTriListIndices = cIndices; return S_OK; } //+---------------------------------------------------------------------------- // // Member: CHwTVertexBuffer::Builder::AddTriangle // // Synopsis: Add a triangle to the vertex buffer // template HRESULT CHwTVertexBuffer::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 wafflers[NUM_OF_VERTEX_TEXTURE_COORDS(TVertex) * 2]; TriangleWaffler::ISink *pWaffleSinkNoRef = BuildWafflePipeline(wafflers); IFC(pWaffleSinkNoRef->AddTriangle(rgPoints[0], rgPoints[1], rgPoints[2])); } else { IFC(m_pVB->AddTriangle( static_cast(i1), static_cast(i2), static_cast(i3) )); } Cleanup: RRETURN(hr); } */ //+---------------------------------------------------------------------------- // // Member: CHwTVertexBuffer::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 // 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 wafflers[NUM_OF_VERTEX_TEXTURE_COORDS(TVertex) * 2]; // Use sink for waffling & the first line fix up (aka the complicated cases.) //ILineSink *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::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::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 HRESULT CHwTVertexBuffer::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 wafflers[NUM_OF_VERTEX_TEXTURE_COORDS(TVertex) * 2]; TriangleWaffler::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::Builder::BuildWafflePipeline // // 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 template __out_ecount(1) typename TWaffler::ISink * CHwTVertexBuffer::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::Builder::IsEmpty // // Synopsis: Does our VB have any triangles/lines? // //----------------------------------------------------------------------------- template BOOL CHwTVertexBuffer::Builder::IsEmpty() { return m_pVB->IsEmpty(); } */ //+---------------------------------------------------------------------------- // // Member: CHwTVertexBuffer::Builder::AddTrapezoid // // Synopsis: Add a trapezoid to the vertex buffer // // // left edge right edge // ___+_________________+___ <<< top edge // / + / \ + \ // / + / \ + \ // / + / \ + \ // /__+__/___________________\__+__\ <<< bottom edge // + ^^ + // delta // impl CHwVertexBufferBuilder<'_, '_> { //+---------------------------------------------------------------------------- // // Member: CHwTVertexBuffer::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::Builder::AddTrapezoidWaffle // // Synopsis: See AddTrapezoid. This adds a waffled trapezoid. // //----------------------------------------------------------------------------- template HRESULT CHwTVertexBuffer::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 wafflers[NUM_OF_VERTEX_TEXTURE_COORDS(TVertex) * 2]; bool fWafflersUsed = false; TriangleWaffler::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::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::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::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::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); } }