diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/wpf-gpu-raster/src/hwvertexbuffer.rs | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/wpf-gpu-raster/src/hwvertexbuffer.rs')
-rw-r--r-- | third_party/rust/wpf-gpu-raster/src/hwvertexbuffer.rs | 3075 |
1 files changed, 3075 insertions, 0 deletions
diff --git a/third_party/rust/wpf-gpu-raster/src/hwvertexbuffer.rs b/third_party/rust/wpf-gpu-raster/src/hwvertexbuffer.rs new file mode 100644 index 0000000000..6b01b5fdb2 --- /dev/null +++ b/third_party/rust/wpf-gpu-raster/src/hwvertexbuffer.rs @@ -0,0 +1,3075 @@ +// 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); +} + +} |