//=================================================================
//
// Copyright (c) Microsoft Corporation 1999 - All Rights Reserved.
//
//=================================================================

#define MIN(a, b)                               \
    ((a) < (b)) ? (a) : (b)                           

#define MAX(a, b)                               \
    ((a) > (b)) ? (a) : (b)                           

#define UPDATE(c, v)                            \
    c.minx = MIN(c.minx, v.sx);                 \
    c.maxx = MAX(c.maxx, v.sx);                 \
    c.miny = MIN(c.miny, v.sy);                 \
    c.maxy = MAX(c.maxy, v.sy) 

{
    unsigned int i, i0, i1, i2;

#if defined(_CLIP_)
    DWORD dwClipped, dwRejected;
#endif

    switch (_TYPE_)
    {

    case D3DPT_TRIANGLELIST:
        for (i = 0; (int)i < (int)_NUM_VERTECIES_ - 2; i += 3)
        {

#if defined(_INDEX_)
            i0 = _INDEX_[i+0];
            i1 = _INDEX_[i+1];
            i2 = _INDEX_[i+2];
#else
            i0 = i+0;
            i1 = i+1;
            i2 = i+2;
#endif

#if defined(_CLIP_)
            dwRejected = (_VERTECIES_[i0].dwFlags & _VERTECIES_[i1].dwFlags &
						  _VERTECIES_[i2].dwFlags) & CLIP_SIDE_MASK;

            if (!dwRejected)
            {
                dwClipped = (_VERTECIES_[i0].dwFlags | _VERTECIES_[i1].dwFlags |
                             _VERTECIES_[i2].dwFlags) & CLIP_SIDE_MASK;

                if (dwClipped)
                {
                    ClipAndDrawTriangle(&_VERTECIES_[i0],
                                        &_VERTECIES_[i1],
                                        &_VERTECIES_[i2],
                                        dwClipped);
                }
                else
                {
                    DrawTriangle((D3DTLVERTEX *) &_VERTECIES_[i0],
                                 (D3DTLVERTEX *) &_VERTECIES_[i1],
                                 (D3DTLVERTEX *) &_VERTECIES_[i2]);
                }
            }
#else
            DrawTriangle((D3DTLVERTEX *) &_VERTECIES_[i0],
                         (D3DTLVERTEX *) &_VERTECIES_[i1],
                         (D3DTLVERTEX *) &_VERTECIES_[i2]);
#endif

#if defined(_EXTENTS_)
            UPDATE(m_csClipStatus, _VERTECIES_[i0]);
            UPDATE(m_csClipStatus, _VERTECIES_[i1]);
            UPDATE(m_csClipStatus, _VERTECIES_[i2]);
#endif

        }

        break;
    
    case D3DPT_TRIANGLEFAN:

#if defined(_EXTENTS_)
        if (_NUM_VERTECIES_ > 0)
        {
#if defined(_INDEX_)
            UPDATE(m_csClipStatus, _VERTECIES_[_INDEX_[0]]);
#else
            UPDATE(m_csClipStatus, _VERTECIES_[0]);
#endif
        }
#endif

        for (i = 0; (int)i < (int)_NUM_VERTECIES_ - 2; i++)
        {

#if defined(_INDEX_)
            i2 = _INDEX_[0];
            i0 = _INDEX_[i+1];
            i1 = _INDEX_[i+2];
#else
            i2 = 0;
            i0 = i+1;
            i1 = i+2;
#endif

#if defined(_CLIP_)
            dwRejected = (_VERTECIES_[i0].dwFlags & _VERTECIES_[i1].dwFlags &
                          _VERTECIES_[i2].dwFlags) & CLIP_SIDE_MASK;

            if (!dwRejected)
            {
                dwClipped = (_VERTECIES_[i0].dwFlags | _VERTECIES_[i1].dwFlags |
                             _VERTECIES_[i2].dwFlags) & CLIP_SIDE_MASK;

                if (dwClipped)
                {
                    ClipAndDrawTriangle(&_VERTECIES_[i0],
                                        &_VERTECIES_[i1],
                                        &_VERTECIES_[i2],
                                        dwClipped);
                }
                else
                {
                    DrawTriangle((D3DTLVERTEX *) &_VERTECIES_[i0],
                                 (D3DTLVERTEX *) &_VERTECIES_[i1],
                                 (D3DTLVERTEX *) &_VERTECIES_[i2]);
                }
            }
#else
            DrawTriangle((D3DTLVERTEX *) &_VERTECIES_[i0],
                         (D3DTLVERTEX *) &_VERTECIES_[i1],
                         (D3DTLVERTEX *) &_VERTECIES_[i2]);
#endif

#if defined(_EXTENTS_)
            UPDATE(m_csClipStatus, _VERTECIES_[i1]);
#endif

        }

#if defined(_EXTENTS_)
        if (_NUM_VERTECIES_ > 1)
        {
#if defined(_INDEX_)
            UPDATE(m_csClipStatus, _VERTECIES_[_INDEX_[_NUM_VERTECIES_-1]]);
#else
            UPDATE(m_csClipStatus, _VERTECIES_[_NUM_VERTECIES_-1]);
#endif
        }
#endif

        break;

    
    case D3DPT_TRIANGLESTRIP:
        for (i = 0; (int)i < (int)_NUM_VERTECIES_ - 3; i+=2)
        {
			unsigned i3;

#if defined(_INDEX_)
            i0 = _INDEX_[i+0];
            i1 = _INDEX_[i+1];
            i2 = _INDEX_[i+2];
			i3 = _INDEX_[i+3];
#else
            i0 = i+0;
            i1 = i+1;
            i2 = i+2;
			i3 = i+3;
#endif

#if defined(_CLIP_)
            dwRejected = (_VERTECIES_[i0].dwFlags & _VERTECIES_[i1].dwFlags &
                          _VERTECIES_[i2].dwFlags) & CLIP_SIDE_MASK;

            if (!dwRejected)
            {
                dwClipped = (_VERTECIES_[i0].dwFlags | _VERTECIES_[i1].dwFlags |
                             _VERTECIES_[i2].dwFlags) & CLIP_SIDE_MASK;

                if (dwClipped)
                {
                    ClipAndDrawTriangle(&_VERTECIES_[i0],
                                        &_VERTECIES_[i1],
                                        &_VERTECIES_[i2],
                                        dwClipped);
                }
                else
                {
                    DrawTriangle((D3DTLVERTEX *) &_VERTECIES_[i0],
                                 (D3DTLVERTEX *) &_VERTECIES_[i1],
                                 (D3DTLVERTEX *) &_VERTECIES_[i2]);
                }
            }

            dwRejected = (_VERTECIES_[i1].dwFlags & _VERTECIES_[i3].dwFlags &
                          _VERTECIES_[i2].dwFlags) & CLIP_SIDE_MASK;

            if (!dwRejected)
            {
                dwClipped = (_VERTECIES_[i1].dwFlags | _VERTECIES_[i3].dwFlags |
                             _VERTECIES_[i2].dwFlags) & CLIP_SIDE_MASK;

                if (dwClipped)
                {
                    ClipAndDrawTriangle(&_VERTECIES_[i1],
                                        &_VERTECIES_[i3],
                                        &_VERTECIES_[i2],
                                        dwClipped);
                }
                else
                {
                    DrawTriangle((D3DTLVERTEX *) &_VERTECIES_[i1],
                                 (D3DTLVERTEX *) &_VERTECIES_[i3],
                                 (D3DTLVERTEX *) &_VERTECIES_[i2]);
                }
            }
#else
            DrawTriangle((D3DTLVERTEX *) &_VERTECIES_[i0],
                         (D3DTLVERTEX *) &_VERTECIES_[i1],
                         (D3DTLVERTEX *) &_VERTECIES_[i2]);

            DrawTriangle((D3DTLVERTEX *) &_VERTECIES_[i1],
                         (D3DTLVERTEX *) &_VERTECIES_[i3],
                         (D3DTLVERTEX *) &_VERTECIES_[i2]);
#endif

#if defined(_EXTENTS_)
            UPDATE(m_csClipStatus, _VERTECIES_[i0]);
            UPDATE(m_csClipStatus, _VERTECIES_[i1]);
#endif
        }
		// Finish "odd" triangle if necessary
		if ((int) i + 3 == (int) _NUM_VERTECIES_)
		{
#if defined(_INDEX_)
            i0 = _INDEX_[i+0];
            i1 = _INDEX_[i+1];
            i2 = _INDEX_[i+2];
#else
            i0 = i+0;
            i1 = i+1;
            i2 = i+2;
#endif

#if defined(_CLIP_)
            dwRejected = (_VERTECIES_[i0].dwFlags & _VERTECIES_[i1].dwFlags &
                          _VERTECIES_[i2].dwFlags) & CLIP_SIDE_MASK;

            if (!dwRejected)
            {
                dwClipped = (_VERTECIES_[i0].dwFlags | _VERTECIES_[i1].dwFlags |
                             _VERTECIES_[i2].dwFlags) & CLIP_SIDE_MASK;

                if (dwClipped)
                {
                    ClipAndDrawTriangle(&_VERTECIES_[i0],
                                        &_VERTECIES_[i1],
                                        &_VERTECIES_[i2],
                                        dwClipped);
                }
                else
                {
                    DrawTriangle((D3DTLVERTEX *) &_VERTECIES_[i0],
                                 (D3DTLVERTEX *) &_VERTECIES_[i1],
                                 (D3DTLVERTEX *) &_VERTECIES_[i2]);
                }
            }
#else
            DrawTriangle((D3DTLVERTEX *) &_VERTECIES_[i0],
                         (D3DTLVERTEX *) &_VERTECIES_[i1],
                         (D3DTLVERTEX *) &_VERTECIES_[i2]);
#endif

#if defined(_EXTENTS_)
            UPDATE(m_csClipStatus, _VERTECIES_[i0]);
#endif
		}

#if defined(_EXTENTS_)
        if (_NUM_VERTECIES_ > 2)
        {
#if defined(_INDEX_)
            UPDATE(m_csClipStatus, _VERTECIES_[_INDEX_[_NUM_VERTECIES_-2]]);
            UPDATE(m_csClipStatus, _VERTECIES_[_INDEX_[_NUM_VERTECIES_-1]]);
#else
            UPDATE(m_csClipStatus, _VERTECIES_[_NUM_VERTECIES_-2]);
            UPDATE(m_csClipStatus, _VERTECIES_[_NUM_VERTECIES_-1]);
#endif
        }
#endif

        break;

	case D3DPT_LINELIST:
        for (i = 0; (int)i < (int)_NUM_VERTECIES_ - 1; i += 2)
        {
#if defined(_INDEX_)
            i0 = _INDEX_[i+0];
            i1 = _INDEX_[i+1];
#else
            i0 = i+0;
            i1 = i+1;
#endif

#if defined(_CLIP_)
            dwRejected = (_VERTECIES_[i0].dwFlags & _VERTECIES_[i1].dwFlags) & CLIP_SIDE_MASK;

            if (!dwRejected)
            {
                dwClipped = (_VERTECIES_[i0].dwFlags | _VERTECIES_[i1].dwFlags) & CLIP_SIDE_MASK;

                if (dwClipped)
                {
                    ClipAndDrawLine(&_VERTECIES_[i0],
                                    &_VERTECIES_[i1],
                                    dwClipped);
                }
                else
                {
                    DrawLine((D3DTLVERTEX *) &_VERTECIES_[i0],
                             (D3DTLVERTEX *) &_VERTECIES_[i1]);
                }
            }
#else
            DrawLine((D3DTLVERTEX *) &_VERTECIES_[i0],
                     (D3DTLVERTEX *) &_VERTECIES_[i1]);
#endif

#if defined(_EXTENTS_)
            UPDATE(m_csClipStatus, _VERTECIES_[i0]);
            UPDATE(m_csClipStatus, _VERTECIES_[i1]);
#endif

		}

		break;

    case D3DPT_LINESTRIP:
        for (i = 0; (int)i < (int)_NUM_VERTECIES_ - 1; i++)
        {
#if defined(_INDEX_)
            i0 = _INDEX_[i+0];
            i1 = _INDEX_[i+1];
#else
            i0 = i+0;
            i1 = i+1;
#endif

#if defined(_CLIP_)
            dwRejected = (_VERTECIES_[i0].dwFlags & _VERTECIES_[i1].dwFlags) & CLIP_SIDE_MASK;

            if (!dwRejected)
            {
                dwClipped = (_VERTECIES_[i0].dwFlags | _VERTECIES_[i1].dwFlags) & CLIP_SIDE_MASK;

                if (dwClipped)
                {
                    ClipAndDrawLine(&_VERTECIES_[i0],
                                    &_VERTECIES_[i1],
                                    dwClipped);
                }
                else
                {
                    DrawLine((D3DTLVERTEX *) &_VERTECIES_[i0],
                             (D3DTLVERTEX *) &_VERTECIES_[i1]);
                }
            }
#else
            DrawLine((D3DTLVERTEX *) &_VERTECIES_[i0],
                     (D3DTLVERTEX *) &_VERTECIES_[i1]);
#endif

#if defined(_EXTENTS_)
            UPDATE(m_csClipStatus, _VERTECIES_[i0]);
#endif

		}

#if defined(_EXTENTS_)
        if (_NUM_VERTECIES_ > 1)
        {
#if defined(_INDEX_)
            UPDATE(m_csClipStatus, _VERTECIES_[_INDEX_[_NUM_VERTECIES_-1]]);
#else
            UPDATE(m_csClipStatus, _VERTECIES_[_NUM_VERTECIES_-1]);
#endif
        }
#endif

		break;

    case D3DPT_POINTLIST:
        for (i = 0; (int)i < (int)_NUM_VERTECIES_ ; i ++ )
        {
#if defined(_INDEX_)
            i0 = _INDEX_[i+0];
#else
            i0 = i+0;
#endif

#if defined(_CLIP_)
            dwRejected = _VERTECIES_[i0].dwFlags & CLIP_SIDE_MASK;

            if (!dwRejected)
            {
                DrawPoint((D3DTLVERTEX *) &_VERTECIES_[i0]);
            }
#else
            DrawPoint((D3DTLVERTEX *) &_VERTECIES_[i0]);
#endif

#if defined(_EXTENTS_)
            UPDATE(m_csClipStatus, _VERTECIES_[i0]);
#endif
		}
		break;

    default:
        retval = E_NOTIMPL;
        goto Exit;
    }

#if defined(_EXTENTS_)

    if (m_csClipStatus.minx < m_vdViewportData.dwX)
    {
        m_csClipStatus.minx = (float)m_vdViewportData.dwX;
    }
    else if (m_csClipStatus.maxx > m_vdViewportData.dwX + m_vdViewportData.dwWidth)
    {
        m_csClipStatus.maxx = (float)(m_vdViewportData.dwX + m_vdViewportData.dwWidth);
    }

    if (m_csClipStatus.miny < m_vdViewportData.dwY)
    {
        m_csClipStatus.miny = (float)m_vdViewportData.dwY;
    }
    else if (m_csClipStatus.maxy > m_vdViewportData.dwY + m_vdViewportData.dwHeight)
    {
        m_csClipStatus.maxy = (float)(m_vdViewportData.dwY + m_vdViewportData.dwHeight);
    }

#endif

    goto Exit;
}

#undef MIN
#undef MAX
#undef UPDATE
