windows-nt/Source/XPSP1/NT/multimedia/directx/dxg/ref8/hop/bezier.cpp

363 lines
13 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*============================================================================
*
* Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
*
* File: bezier.cpp
* Content: Implementation for Beziers
*
****************************************************************************/
#include "pch.cpp"
#pragma hdrstop
//-----------------------------------------------------------------------------
// RefDev::ProcessBezier
//-----------------------------------------------------------------------------
HRESULT RefDev::ProcessBezier( DWORD dwOffW, DWORD dwOffH,
DWORD dwWidth, DWORD dwHeight,
DWORD dwStride, DWORD order,
FLOAT *pPrimSegments,
bool bDegenerate )
{
if(order == 0)
{
order = 2;
}
else
{
++order;
}
if(((dwWidth - 1) % (order - 1)) != 0 || ((dwHeight - 1) % (order - 1)) != 0)
{
DPFERR("Incorrect order specified for current width or height");
return DDERR_INVALIDPARAMS;
}
RDBezier bz(order, order);
static const unsigned M[4] = {0, 0, 0, 0}, N[4] = {0, 0, 0, 0};
unsigned u_segs, v_segs, u_start, v_start;
if(pPrimSegments != 0)
{
u_segs = unsigned(double(unsigned(pPrimSegments[0]) + unsigned(pPrimSegments[2])) / 2.0 + 0.5);
v_segs = unsigned(double(unsigned(pPrimSegments[1]) + unsigned(pPrimSegments[3])) / 2.0 + 0.5);
if(u_segs == 0)
{
u_segs = 1;
}
if(v_segs == 0)
{
v_segs = 1;
}
if(unsigned(pPrimSegments[0]) != unsigned(pPrimSegments[2]) || unsigned(pPrimSegments[1]) != unsigned(pPrimSegments[3]))
{
// First, gulp, the irregular outside
// To make life easier, we don't want to deal with the case when u_segs or v_segs is one
// This ensures that there is at least one inside point
if(u_segs == 1)
{
u_segs = 2;
}
if(v_segs == 1)
{
v_segs = 2;
}
// Start with top edge
unsigned segs = unsigned(pPrimSegments[0]);
unsigned k_outer = 0;
unsigned k_inner = 1;
unsigned outer_inc = u_segs - 2;
unsigned inner_inc = segs;
unsigned outer = 0;
unsigned inner = 0;
double u0, v0, u1, v1, u2, v2;
while(outer_inc != 0 ? (inner != inner_inc * outer_inc || outer != inner_inc * outer_inc) : (k_outer < segs))
{
bool D0, D1, D2;
if(inner < outer)
{
_ASSERT(k_inner < u_segs - 1, "Error in logic");
u0 = double(k_inner) / double(u_segs);
v0 = 1.0 / double(v_segs);
D0 = false;
u1 = double(k_outer) / double(segs);
v1 = 0.0;
D1 = bDegenerate;
u2 = double(k_inner + 1) / double(u_segs);
v2 = v0;
D2 = false;
++k_inner;
inner += inner_inc;
}
else
{
_ASSERT(k_outer < segs, "Error in logic");
u0 = double(k_inner) / double(u_segs);
v0 = 1.0 / double(v_segs);
D0 = false;
u1 = double(k_outer) / double(segs);
v1 = 0.0;
D1 = bDegenerate;
u2 = double(k_outer + 1) / double(segs);
v2 = v1;
D2 = bDegenerate;
++k_outer;
outer += outer_inc;
}
HRESULT hr = DrawTessTri(bz, dwOffW, dwOffH, dwStride, M, N, u0, v0, u1, v1, u2, v2,
bDegenerate ? u0 * v0 : u0, v0, bDegenerate ? u1 * v1 : u1, v1, bDegenerate ? u2 * v2 : u2, v2,
D0, D1, D2);
if(FAILED(hr))
{
return hr;
}
}
// bottom edge
segs = unsigned(pPrimSegments[2]);
k_outer = segs;
k_inner = u_segs - 1;
inner_inc = segs;
outer = 0;
inner = 0;
while(outer_inc != 0 ? (inner != inner_inc * outer_inc || outer != inner_inc * outer_inc) : (k_outer > 0))
{
if(inner < outer)
{
_ASSERT(k_inner > 1, "Error in logic");
u0 = double(k_inner) / double(u_segs);
v0 = double(v_segs - 1) / double(v_segs);
u1 = double(k_outer) / double(segs);
v1 = 1.0;
u2 = double(k_inner - 1) / double(u_segs);
v2 = v0;
--k_inner;
inner += inner_inc;
}
else
{
_ASSERT(k_outer > 0, "Error in logic");
u0 = double(k_inner) / double(u_segs);
v0 = double(v_segs - 1) / double(v_segs);
u1 = double(k_outer) / double(segs);
v1 = 1.0;
u2 = double(k_outer - 1) / double(segs);
v2 = v1;
--k_outer;
outer += outer_inc;
}
HRESULT hr = DrawTessTri(bz, dwOffW, dwOffH, dwStride, M, N, u0, v0, u1, v1, u2, v2,
bDegenerate ? u0 * v0 : u0, v0, bDegenerate ? u1 * v1 : u1, v1, bDegenerate ? u2 * v2 : u2, v2,
false, false, false);
if(FAILED(hr))
{
return hr;
}
}
// right edge
segs = unsigned(pPrimSegments[1]);
k_outer = 0;
k_inner = 1;
outer_inc = v_segs - 2;
inner_inc = segs;
outer = 0;
inner = 0;
while(outer_inc != 0 ? (inner != inner_inc * outer_inc || outer != inner_inc * outer_inc) : (k_outer < segs))
{
bool D1;
if(inner < outer)
{
_ASSERT(k_inner < v_segs - 1, "Error in logic");
u0 = double(u_segs - 1) / double(u_segs);
v0 = double(k_inner) / double(v_segs);
u1 = 1.0;
v1 = double(k_outer) / double(segs);
D1 = (k_outer == 0) ? bDegenerate : false;
u2 = u0;
v2 = double(k_inner + 1) / double(v_segs);
++k_inner;
inner += inner_inc;
}
else
{
_ASSERT(k_outer < segs, "Error in logic");
u0 = double(u_segs - 1) / double(u_segs);
v0 = double(k_inner) / double(v_segs);
u1 = 1.0;
v1 = double(k_outer) / double(segs);
D1 = (k_outer == 0) ? bDegenerate : false;
u2 = u1;
v2 = double(k_outer + 1) / double(segs);
++k_outer;
outer += outer_inc;
}
HRESULT hr = DrawTessTri(bz, dwOffW, dwOffH, dwStride, M, N, u0, v0, u1, v1, u2, v2,
bDegenerate ? u0 * v0 : u0, v0, bDegenerate ? u1 * v1 : u1, v1, bDegenerate ? u2 * v2 : u2, v2,
false, D1, false);
if(FAILED(hr))
{
return hr;
}
}
// left edge
segs = unsigned(pPrimSegments[3]);
k_outer = segs;
k_inner = v_segs - 1;
inner_inc = segs;
outer = 0;
inner = 0;
while(outer_inc != 0 ? (inner != inner_inc * outer_inc || outer != inner_inc * outer_inc) : (k_outer > 0))
{
bool D1, D2;
if(inner < outer)
{
_ASSERT(k_inner > 1, "Error in logic");
u0 = 1.0 / double(u_segs);
v0 = double(k_inner) / double(v_segs);
u1 = 0.0;
v1 = double(k_outer) / double(segs);
D1 = (k_outer == 0) ? bDegenerate : false;
u2 = u0;
v2 = double(k_inner - 1) / double(v_segs);
D2 = false;
--k_inner;
inner += inner_inc;
}
else
{
_ASSERT(k_outer > 0, "Error in logic");
u0 = 1.0 / double(u_segs);
v0 = double(k_inner) / double(v_segs);
u1 = 0.0;
v1 = double(k_outer) / double(segs);
D1 = false; // since k_outer always > 0
u2 = u1;
v2 = double(k_outer - 1) / double(segs);
D2 = (k_outer - 1 == 0) ? bDegenerate : false;
--k_outer;
outer += outer_inc;
}
HRESULT hr = DrawTessTri(bz, dwOffW, dwOffH, dwStride, M, N, u0, v0, u1, v1, u2, v2,
bDegenerate ? u0 * v0 : u0, v0, bDegenerate ? u1 * v1 : u1, v1, bDegenerate ? u2 * v2 : u2, v2,
false, D1, D2);
if(FAILED(hr))
{
return hr;
}
}
// Now do the regular interior
u_start = 1;
v_start = 1;
}
else
{
// It can be done regularly
u_start = 0;
v_start = 0;
}
}
else
{
unsigned segs = unsigned(GetRSf()[D3DRS_PATCHSEGMENTS]);
if(segs == 0)
{
segs = 1;
}
u_start = 0;
v_start = 0;
u_segs = segs;
v_segs = segs;
}
for(unsigned i = v_start; i < v_segs - v_start; ++i)
{
double v0 = double(i) / double(v_segs);
double v1 = double(i + 1) / double(v_segs);
for(unsigned j = u_start; j < u_segs - u_start; ++j)
{
double u0 = double(j) / double(u_segs);
double u1 = double(j + 1) / double(u_segs);
if(i == 0 && bDegenerate)
{
HRESULT hr = DrawTessTri(bz, dwOffW, dwOffH, dwStride, M, N, u0, v0, u1, v1, u0, v1, u0 * v0, v0, u1 * v1, v1, u0 * v1, v1, true, false, false);
if(FAILED(hr))
{
return hr;
}
}
else
{
HRESULT hr = DrawTessQuad(bz, dwOffW, dwOffH, dwStride, M, N, u0, v0, u1, v1, u0, v0, u1, v1, bDegenerate);
if(FAILED(hr))
{
return hr;
}
}
}
}
return S_OK;
}
//-----------------------------------------------------------------------------
// RDBezier::RDBezier
//-----------------------------------------------------------------------------
RDBezier::RDBezier(DWORD dwOrderU, DWORD dwOrderV)
: RDBSpline(dwOrderU, dwOrderV, dwOrderU - 1, dwOrderV - 1)
{
for(unsigned n = 1; n <= 12; ++n)
{
for(unsigned i = 0; i <= n; ++i)
{
m_lut[n][i] = double(factorial(n)) / (double(factorial(i)) * double(factorial(n - i)));
}
}
}
//-----------------------------------------------------------------------------
// RDBSpline::TexCoordU
//-----------------------------------------------------------------------------
double RDBezier::TexCoordU(double u) const
{
return u;
}
//-----------------------------------------------------------------------------
// RDBSpline::TexCoordV
//-----------------------------------------------------------------------------
double RDBezier::TexCoordV(double v) const
{
return v;
}
//-----------------------------------------------------------------------------
// RDBezier::Basis
//-----------------------------------------------------------------------------
double RDBezier::Basis(unsigned i, unsigned n, double t) const
{
_ASSERT(n < 13, "Order out of range");
return m_lut[n][i] * pow(t, double(i)) * pow(1.0 - t, double(n - i));
}
//-----------------------------------------------------------------------------
// RDBezier::BasisPrime
//-----------------------------------------------------------------------------
double RDBezier::BasisPrime(unsigned i, unsigned n, double t) const
{
_ASSERT(n < 13, "Order out of range");
if(i == 0)
{
return m_lut[n][i] * -double(n) * pow(1 - t, n - 1);
}
else if(i == n)
{
return m_lut[n][i] * double(n) * pow(t, n - 1);
}
else
{
return (double(i) - double(n) * t) * (m_lut[n][i] * pow(t, double(i) - 1.0) * pow(1.0 - t, double(n - i) - 1.0));
}
}