windows-nt/Source/XPSP1/NT/drivers/video/matrox/mga/disp/mcdprim.c
2020-09-26 16:20:57 +08:00

697 lines
17 KiB
C

/******************************Module*Header*******************************\
* Module Name: mcdprim.c
*
* These routines process the OpenGL rendering commands that appear in an
* MCDrvDraw() batch. Note that the only OpenGL primitive which is invalid
* is LineLoop. This gets decomposed by the caller into a LineStrip command.
*
* Copyright (c) 1996 Microsoft Corporation
\**************************************************************************/
#include "precomp.h"
#include "mcdhw.h"
#include "mcdutil.h"
#define MEMCHECK_VERTEX(p)\
if (((UCHAR *)p < pRc->pMemMin) ||\
((UCHAR *)p > pRc->pMemMax)) {\
MCDBG_PRINT("Invalid MCD vertex pointer!");\
return NULL;\
}
////////////////////////////////////////////////////////////////////////
//
// The functions below are local rendering-helper functions which call
// the real rendering routines in the driver.
//
////////////////////////////////////////////////////////////////////////
VOID static FASTCALL __MCDRenderPoint(DEVRC *pRc, MCDVERTEX *v)
{
if (v->clipCode == 0)
(*pRc->renderPoint)(pRc, v);
}
VOID static FASTCALL __MCDRenderLine(DEVRC *pRc, MCDVERTEX *v0,
MCDVERTEX *v1, BOOL bResetLine)
{
if (v0->clipCode | v1->clipCode)
{
/*
* The line must be clipped more carefully. Cannot
* trivially accept the lines.
*
* If anding the codes is non-zero then every vertex
* in the line is outside of the same set of clipping
* planes (at least one). Trivially reject the line.
*/
if ((v0->clipCode & v1->clipCode) == 0)
(*pRc->clipLine)(pRc, v0, v1, bResetLine);
}
else
{
// Line is trivially accepted so render it
(*pRc->renderLine)(pRc, v0, v1, bResetLine);
}
}
VOID static FASTCALL __MCDRenderTriangle(DEVRC *pRc, MCDVERTEX *v0,
MCDVERTEX *v1, MCDVERTEX *v2)
{
ULONG orCodes;
/* Clip check */
orCodes = v0->clipCode | v1->clipCode | v2->clipCode;
if (orCodes)
{
/* Some kind of clipping is needed.
*
* If anding the codes is non-zero then every vertex
* in the triangle is outside of the same set of
* clipping planes (at least one). Trivially reject
* the triangle.
*/
if (!(v0->clipCode & v1->clipCode & v2->clipCode))
(*pRc->clipTri)(pRc, v0, v1, v2, orCodes);
}
else
{
(*pRc->renderTri)(pRc, v0, v1, v2);
}
}
VOID static FASTCALL __MCDRenderQuad(DEVRC *pRc, MCDVERTEX *v0,
MCDVERTEX *v1, MCDVERTEX *v2, MCDVERTEX *v3)
{
// Vertex ordering is important. Line stippling uses it.
ULONG savedTag;
/* Render the quad as two triangles */
savedTag = v2->flags & MCDVERTEX_EDGEFLAG;
v2->flags &= ~MCDVERTEX_EDGEFLAG;
(*pRc->renderTri)(pRc, v0, v1, v2);
v2->flags |= savedTag;
savedTag = v0->flags & MCDVERTEX_EDGEFLAG;
v0->flags &= ~MCDVERTEX_EDGEFLAG;
(*pRc->renderTri)(pRc, v2, v3, v0);
v0->flags |= savedTag;
}
VOID static FASTCALL __MCDRenderClippedQuad(DEVRC *pRc, MCDVERTEX *v0,
MCDVERTEX *v1, MCDVERTEX *v2, MCDVERTEX *v3)
{
ULONG orCodes;
orCodes = v0->clipCode | v1->clipCode | v2->clipCode | v3->clipCode;
if (orCodes)
{
/* Some kind of clipping is needed.
*
* If anding the codes is non-zero then every vertex
* in the quad is outside of the same set of
* clipping planes (at least one). Trivially reject
* the quad.
*/
if (!(v0->clipCode & v1->clipCode & v2->clipCode & v3->clipCode))
{
/* Clip the quad as a polygon */
MCDVERTEX *iv[4];
iv[0] = v0;
iv[1] = v1;
iv[2] = v2;
iv[3] = v3;
(pRc->doClippedPoly)(pRc, &iv[0], 4, orCodes);
}
}
else
{
__MCDRenderQuad(pRc, v0, v1, v2, v3);
}
}
////////////////////////////////////////////////////////////////////////
//
// The functions below handle the processing of all of the primitives
// which may appear in an MCDCOMMAND. This includes all of the OpenGL
// primitives, with the exception of line loops which are handled as
// line strips.
//
////////////////////////////////////////////////////////////////////////
MCDCOMMAND * FASTCALL __MCDPrimDrawPoints(DEVRC *pRc, MCDCOMMAND *pCmd)
{
LONG i, nIndices;
MCDVERTEX *pv;
VOID (FASTCALL *rp)(DEVRC *pRc, MCDVERTEX *v);
// Index mapping is always identity in Points.
// ASSERTOPENGL(!pa->aIndices, "Index mapping must be identity\n");
if (pCmd->clipCodes)
rp = __MCDRenderPoint;
else
rp = pRc->renderPoint;
(*pRc->beginPointDrawing)(pRc);
// Render the points:
pv = pCmd->pStartVertex;
MEMCHECK_VERTEX(pv);
i = pCmd->numIndices;
MEMCHECK_VERTEX(pv + (i - 1));
for (; i > 0; i--, pv++)
(*rp)(pRc, pv);
return pCmd->pNextCmd;
}
MCDCOMMAND * FASTCALL __MCDPrimDrawLines(DEVRC *pRc, MCDCOMMAND *pCmd)
{
LONG i, iLast2;
UCHAR *pIndices;
MCDVERTEX *pv, *pv0, *pv1;
VOID (FASTCALL *rl)(DEVRC *pRc, MCDVERTEX *pv1, MCDVERTEX *pv2, BOOL bResetLine);
iLast2 = pCmd->numIndices - 2;
pv = pCmd->pStartVertex;
rl = pCmd->clipCodes ? __MCDRenderLine : pRc->renderLine;
(*pRc->beginLineDrawing)(pRc);
if (!(pIndices = pCmd->pIndices))
{
// Identity mapping
MEMCHECK_VERTEX(pv);
MEMCHECK_VERTEX(pv + (iLast2 + 1));
for (i = 0; i <= iLast2; i += 2)
{
/* setup for rendering this line */
pRc->resetLineStipple = TRUE;
(*rl)(pRc, &pv[i], &pv[i+1], TRUE);
}
}
else
{
for (i = 0; i <= iLast2; i += 2)
{
pv0 = &pv[pIndices[i]];
pv1 = &pv[pIndices[i+1]];
MEMCHECK_VERTEX(pv0);
MEMCHECK_VERTEX(pv1);
/* setup for rendering this line */
pRc->resetLineStipple = TRUE;
(*rl)(pRc, pv0, pv1, TRUE);
}
}
(*pRc->endLineDrawing)(pRc);
return pCmd->pNextCmd;
}
MCDCOMMAND * FASTCALL __MCDPrimDrawLineLoop(DEVRC *pRc, MCDCOMMAND *pCmd)
{
// NOTE:
// Line loops are always converted tp line strips at the OpenGL
// API level. This routine is currently not used.
MCDBG_PRINT("MCDPrimLineLoop: Invalid MCD command!");
return pCmd->pNextCmd;
}
MCDCOMMAND * FASTCALL __MCDPrimDrawLineStrip(DEVRC *pRc, MCDCOMMAND *pCmd)
{
LONG i, iLast;
UCHAR *pIndices;
MCDVERTEX *pv, *pv0, *pv1;
MCDVERTEX *vOld;
VOID (FASTCALL *rl)(DEVRC *pRc, MCDVERTEX *pv1, MCDVERTEX *pv2, BOOL bResetLine);
iLast = pCmd->numIndices - 1;
pv = pCmd->pStartVertex;
rl = pCmd->clipCodes ? __MCDRenderLine : pRc->renderLine;
if (iLast <= 0)
return pCmd->pNextCmd;
if (pCmd->flags & MCDCOMMAND_RESET_STIPPLE)
pRc->resetLineStipple = TRUE;
(*pRc->beginLineDrawing)(pRc);
if (!(pIndices = pCmd->pIndices))
{
// Identity mapping
// Add first line segment (NOTE: 0, 1)
MEMCHECK_VERTEX(pv);
MEMCHECK_VERTEX(pv + iLast);
(*rl)(pRc, &pv[0], &pv[1], TRUE);
// Add subsequent line segments (NOTE: i, i+1)
for (i = 1; i < iLast; i++) {
(*rl)(pRc, &pv[i], &pv[i+1], FALSE);
}
}
else
{
// Add first line segment (NOTE: 0, 1)
pv0 = &pv[pIndices[0]];
pv1 = &pv[pIndices[1]];
(*rl)(pRc, pv0, pv1, TRUE);
// Add subsequent line segments (NOTE: i, i+1)
for (i = 1; i < iLast; i++) {
pv0 = pv1;
pv1 = &pv[pIndices[i+1]];
MEMCHECK_VERTEX(pv1);
(*rl)(pRc, pv0, pv1, FALSE);
}
}
(*pRc->endLineDrawing)(pRc);
return pCmd->pNextCmd;
}
MCDCOMMAND * FASTCALL __MCDPrimDrawTriangles(DEVRC *pRc, MCDCOMMAND *pCmd)
{
LONG i, iLast3;
UCHAR *pIndices;
MCDVERTEX *pv, *pv0, *pv1, *pv2;
VOID (FASTCALL *rt)(DEVRC *pRc, MCDVERTEX *v0, MCDVERTEX *v1, MCDVERTEX *v2);
iLast3 = pCmd->numIndices - 3;
pv = pCmd->pStartVertex;
if (pCmd->clipCodes)
rt = __MCDRenderTriangle;
else
rt = pRc->renderTri;
if (!(pIndices = pCmd->pIndices))
{
// Identity mapping
MEMCHECK_VERTEX(pv);
MEMCHECK_VERTEX(pv + (iLast3 + 2));
for (i = 0; i <= iLast3; i += 3)
{
/* setup for rendering this triangle */
pRc->resetLineStipple = TRUE;
pRc->pvProvoking = &pv[i+2];
/* Render the triangle (NOTE: i, i+1, i+2) */
(*rt)(pRc, &pv[i], &pv[i+1], &pv[i+2]);
}
}
else
{
for (i = 0; i <= iLast3; i += 3)
{
/* setup for rendering this triangle */
pv0 = &pv[pIndices[i ]];
pv1 = &pv[pIndices[i+1]];
pv2 = &pv[pIndices[i+2]];
MEMCHECK_VERTEX(pv0);
MEMCHECK_VERTEX(pv1);
MEMCHECK_VERTEX(pv2);
pRc->resetLineStipple = TRUE;
pRc->pvProvoking = pv2;
/* Render the triangle (NOTE: i, i+1, i+2) */
(*rt)(pRc, pv0, pv1, pv2);
}
}
return pCmd->pNextCmd;
}
MCDCOMMAND * FASTCALL __MCDPrimDrawTriangleStrip(DEVRC *pRc, MCDCOMMAND *pCmd)
{
LONG i, iLast3;
UCHAR *pIndices;
MCDVERTEX *pv, *pv0, *pv1, *pv2;
VOID (FASTCALL *rt)(DEVRC *pRc, MCDVERTEX *v0, MCDVERTEX *v1, MCDVERTEX *v2);
iLast3 = pCmd->numIndices - 3;
pv = pCmd->pStartVertex;
if (pCmd->clipCodes)
rt = __MCDRenderTriangle;
else
rt = pRc->renderTri;
if (iLast3 < 0)
return pCmd->pNextCmd;
if (!(pIndices = pCmd->pIndices))
{
// Identity mapping
MEMCHECK_VERTEX(pv);
MEMCHECK_VERTEX(pv + (iLast3 + 2));
pv[0].flags |= MCDVERTEX_EDGEFLAG;
pv[1].flags |= MCDVERTEX_EDGEFLAG;
for (i = 0; i <= iLast3; i++)
{
/* setup for rendering this triangle */
pRc->resetLineStipple = TRUE;
pRc->pvProvoking = &pv[i+2];
pv[i+2].flags |= MCDVERTEX_EDGEFLAG;
/* Render the triangle (NOTE: i, i+1, i+2) */
(*rt)(pRc, &pv[i], &pv[i+1], &pv[i+2]);
if (++i > iLast3)
break;
pRc->resetLineStipple = TRUE;
pRc->pvProvoking = &pv[i+2];
pv[i+2].flags |= MCDVERTEX_EDGEFLAG;
/* Render the triangle (NOTE: i+1, i, i+2) */
(*rt)(pRc, &pv[i+1], &pv[i], &pv[i+2]);
}
}
else
{
pv1 = &pv[pIndices[0]];
MEMCHECK_VERTEX(pv1);
pv1->flags |= MCDVERTEX_EDGEFLAG;
pv2 = &pv[pIndices[1]];
MEMCHECK_VERTEX(pv2);
pv2->flags |= MCDVERTEX_EDGEFLAG;
for (i = 0; i <= iLast3; i++)
{
/* setup for rendering this triangle */
pRc->resetLineStipple = TRUE;
pv0 = pv1;
pv1 = pv2;
pv2 = &pv[pIndices[i+2]];
MEMCHECK_VERTEX(pv2);
pv2->flags |= MCDVERTEX_EDGEFLAG;
pRc->resetLineStipple = TRUE;
pRc->pvProvoking = pv2;
/* Render the triangle (NOTE: i, i+1, i+2) */
(*rt)(pRc, pv0, pv1, pv2);
if (++i > iLast3)
break;
pv0 = pv1;
pv1 = pv2;
pv2 = &pv[pIndices[i+2]];
MEMCHECK_VERTEX(pv2);
pv2->flags |= MCDVERTEX_EDGEFLAG;
/* setup for rendering this triangle */
pRc->resetLineStipple = TRUE;
pRc->pvProvoking = pv2;
/* Render the triangle (NOTE: i+1, i, i+2) */
(*rt)(pRc, pv1, pv0, pv2);
}
}
return pCmd->pNextCmd;
}
MCDCOMMAND * FASTCALL __MCDPrimDrawTriangleFan(DEVRC *pRc, MCDCOMMAND *pCmd)
{
LONG i, iLast2;
UCHAR *pIndices;
MCDVERTEX *pv, *pv0, *pv1, *pv2;
VOID (FASTCALL *rt)(DEVRC *pRc, MCDVERTEX *v0, MCDVERTEX *v1, MCDVERTEX *v2);
iLast2 = pCmd->numIndices - 2;
pv = pCmd->pStartVertex;
if (pCmd->clipCodes)
rt = __MCDRenderTriangle;
else
rt = pRc->renderTri;
if (iLast2 <= 0)
return pCmd->pNextCmd;
if (!(pIndices = pCmd->pIndices))
{
// Identity mapping
MEMCHECK_VERTEX(pv);
MEMCHECK_VERTEX(pv + (iLast2 + 1));
pv[0].flags |= MCDVERTEX_EDGEFLAG;
pv[1].flags |= MCDVERTEX_EDGEFLAG;
for (i = 1; i <= iLast2; i++)
{
/* setup for rendering this triangle */
pRc->resetLineStipple = TRUE;
pRc->pvProvoking = &pv[i+1];
pv[i+1].flags |= MCDVERTEX_EDGEFLAG;
/* Render the triangle (NOTE: 0, i, i+1) */
(*rt)(pRc, &pv[0], &pv[i], &pv[i+1]);
}
}
else
{
// Initialize first 2 vertices so we can start rendering the tfan
// below. The edge flags are not modified by our lower level routines.
pv0 = &pv[pIndices[0]];
MEMCHECK_VERTEX(pv0);
pv0->flags |= MCDVERTEX_EDGEFLAG;
pv2 = &pv[pIndices[1]];
MEMCHECK_VERTEX(pv2);
pv2->flags |= MCDVERTEX_EDGEFLAG;
for (i = 1; i <= iLast2; i++)
{
pv1 = pv2;
pv2 = &pv[pIndices[i+1]];
MEMCHECK_VERTEX(pv2);
pv2->flags |= MCDVERTEX_EDGEFLAG;
/* setup for rendering this triangle */
pRc->resetLineStipple = TRUE;
pRc->pvProvoking = pv2;
/* Render the triangle (NOTE: 0, i, i+1) */
(*rt)(pRc, pv0, pv1, pv2);
}
}
return pCmd->pNextCmd;
}
MCDCOMMAND * FASTCALL __MCDPrimDrawQuads(DEVRC *pRc, MCDCOMMAND *pCmd)
{
LONG i, iLast4;
UCHAR *pIndices;
MCDVERTEX *pv, *pv0, *pv1, *pv2, *pv3;
VOID (FASTCALL *rq)(DEVRC *pRc, MCDVERTEX *v0, MCDVERTEX *v1, MCDVERTEX *v2,
MCDVERTEX *v3);
iLast4 = pCmd->numIndices - 4;
pv = pCmd->pStartVertex;
if (pCmd->clipCodes)
rq = __MCDRenderClippedQuad;
else
rq = __MCDRenderQuad;
if (!(pIndices = pCmd->pIndices))
{
MEMCHECK_VERTEX(pv);
MEMCHECK_VERTEX(pv + (iLast4 + 3));
// Identity mapping
for (i = 0; i <= iLast4; i += 4)
{
pRc->resetLineStipple = TRUE;
pRc->pvProvoking = &pv[i+3];
/* Render the quad (NOTE: i, i+1, i+2, i+3) */
(*rq)(pRc, &pv[i], &pv[i+1], &pv[i+2], &pv[i+3]);
}
}
else
{
for (i = 0; i <= iLast4; i += 4)
{
pv0 = &pv[pIndices[i ]];
pv1 = &pv[pIndices[i+1]];
pv2 = &pv[pIndices[i+2]];
pv3 = &pv[pIndices[i+3]];
MEMCHECK_VERTEX(pv0);
MEMCHECK_VERTEX(pv1);
MEMCHECK_VERTEX(pv2);
MEMCHECK_VERTEX(pv3);
pRc->resetLineStipple = TRUE;
pRc->pvProvoking = pv3;
/* Render the quad (NOTE: i, i+1, i+2, i+3) */
(*rq)(pRc, pv0, pv1, pv2, pv3);
}
}
return pCmd->pNextCmd;
}
MCDCOMMAND * FASTCALL __MCDPrimDrawQuadStrip(DEVRC *pRc, MCDCOMMAND *pCmd)
{
ULONG i, iLast4;
UCHAR *pIndices;
MCDVERTEX *pv, *pv0, *pv1, *pv2, *pv3;
VOID (FASTCALL *rq)(DEVRC *pRc, MCDVERTEX *v0, MCDVERTEX *v1, MCDVERTEX *v2,
MCDVERTEX *v3);
iLast4 = pCmd->numIndices - 4;
pv = pCmd->pStartVertex;
if (pCmd->clipCodes)
rq = __MCDRenderClippedQuad;
else
rq = __MCDRenderQuad;
// Vertex ordering is important. Line stippling uses it.
if (!(pIndices = pCmd->pIndices))
{
// Identity mapping
MEMCHECK_VERTEX(pv);
MEMCHECK_VERTEX(pv + (iLast4 + 3));
pv[0].flags |= MCDVERTEX_EDGEFLAG;
pv[1].flags |= MCDVERTEX_EDGEFLAG;
for (i = 0; i <= iLast4; i += 2)
{
pv[i+2].flags |= MCDVERTEX_EDGEFLAG;
pv[i+3].flags |= MCDVERTEX_EDGEFLAG;
/* setup for rendering this quad */
pRc->pvProvoking = &pv[i+3];
pRc->resetLineStipple = TRUE;
/* Render the quad (NOTE: i, i+1, i+3, i+2) */
(*rq)(pRc, &pv[i], &pv[i+1], &pv[i+3], &pv[i+2]);
}
}
else
{
// Initialize first 2 vertices so we can start rendering the quad
// below. The edge flags are not modified by our lower level routines.
pv2 = &pv[pIndices[0]];
MEMCHECK_VERTEX(pv2);
pv2->flags |= MCDVERTEX_EDGEFLAG;
pv3 = &pv[pIndices[1]];
MEMCHECK_VERTEX(pv3);
pv3->flags |= MCDVERTEX_EDGEFLAG;
for (i = 0; i <= iLast4; i += 2)
{
pv0 = pv2;
pv1 = pv3;
pv2 = &pv[pIndices[i+2]];
MEMCHECK_VERTEX(pv2);
pv2->flags |= MCDVERTEX_EDGEFLAG;
pv3 = &pv[pIndices[i+3]];
MEMCHECK_VERTEX(pv3);
pv3->flags |= MCDVERTEX_EDGEFLAG;
/* setup for rendering this quad */
pRc->resetLineStipple = TRUE;
pRc->pvProvoking = pv3;
/* Render the quad (NOTE: i, i+1, i+3, i+2) */
(*rq)(pRc, pv0, pv1, pv3, pv2);
}
}
return pCmd->pNextCmd;
}
MCDCOMMAND * FASTCALL __MCDPrimDrawPolygon(DEVRC *pRc, MCDCOMMAND *pCmd)
{
// ASSERTOPENGL(!pCmd->pIndices, "Index mapping must be identity\n");
// Reset the line stipple if this is a new polygon:
if (pCmd->flags & MCDCOMMAND_RESET_STIPPLE)
pRc->resetLineStipple = TRUE;
// Note that the provoking vertex is set in clipPolygon:
MEMCHECK_VERTEX(pCmd->pStartVertex);
MEMCHECK_VERTEX(pCmd->pStartVertex + (pCmd->numIndices-1));
(*pRc->clipPoly)(pRc, pCmd->pStartVertex, pCmd->numIndices);
return pCmd->pNextCmd;
}