windows-nt/Source/XPSP1/NT/multimedia/opengl/server/soft/so_polym.c
2020-09-26 16:20:57 +08:00

582 lines
21 KiB
C

/*
** Copyright 1991, 1992, 1993, Silicon Graphics, Inc.
** All Rights Reserved.
**
** This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
** the contents of this file may not be disclosed to third parties, copied or
** duplicated in any form, in whole or in part, without the prior written
** permission of Silicon Graphics, Inc.
**
** RESTRICTED RIGHTS LEGEND:
** Use, duplication or disclosure by the Government is subject to restrictions
** as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
** and Computer Software clause at DFARS 252.227-7013, and/or in similar or
** successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
** rights reserved under the Copyright Laws of the United States.
*/
#include "precomp.h"
#pragma hdrstop
#include <fixed.h>
#if _X86_
#define SHADER __GLcontext.polygon.shader
#define GET_HALF_AREA(gc, a, b, c)\
\
__asm{ mov eax, a };\
__asm{ mov ecx, c };\
__asm{ mov ebx, b };\
__asm{ mov edx, gc };\
__asm{ fld DWORD PTR [OFFSET(__GLvertex.window.x)][eax] };\
__asm{ fsub DWORD PTR [OFFSET(__GLvertex.window.x)][ecx] /* dxAC */ };\
__asm{ fld DWORD PTR [OFFSET(__GLvertex.window.y)][ebx] };\
__asm{ fsub DWORD PTR [OFFSET(__GLvertex.window.y)][ecx] /* dyBC dxAC */ };\
__asm{ fld DWORD PTR [OFFSET(__GLvertex.window.x)][ebx] };\
__asm{ fsub DWORD PTR [OFFSET(__GLvertex.window.x)][ecx] /* dxBC dyBC dxAC */ };\
__asm{ fld DWORD PTR [OFFSET(__GLvertex.window.y)][eax] };\
__asm{ fsub DWORD PTR [OFFSET(__GLvertex.window.y)][ecx] /* dyAC dxBC dyBC dxAC */ };\
__asm{ fxch ST(2) /* dyBC dxBC dyAC dxAC */ };\
__asm{ fst DWORD PTR [OFFSET(SHADER.dyBC)][edx] };\
__asm{ fmul ST, ST(3) /* dxACdyBC dxBC dyAC dxAC */ };\
__asm{ fxch ST(2) /* dyAC dxBC dxACdyBC dxAC */ };\
__asm{ fst DWORD PTR [OFFSET(SHADER.dyAC)][edx] };\
__asm{ fmul ST, ST(1) /* dxBCdyAC dxBC dxACdyBC dxAC */};\
__asm{ fxch ST(1) /* dxBC dxBCdyAC dxACdyBC dxAC */};\
__asm{ fstp DWORD PTR [OFFSET(SHADER.dxBC)][edx] /* dxBCdyAC dxACdyBC dxAC */ };\
__asm{ fsubp ST(1), ST /* +1*/ /* area dxAC */ };\
__asm{ fxch ST(1) /* dxAC area */ };\
__asm{ fstp DWORD PTR [OFFSET(SHADER.dxAC)][edx] /* area */ };\
__asm{ fstp DWORD PTR [OFFSET(SHADER.area)][edx] /* +1*/ /* (empty) */ };
#define STORE_AREA_PARAMS
#else
#define GET_HALF_AREA(gc, a, b, c)\
/* Compute signed half-area of the triangle */ \
dxAC = a->window.x - c->window.x; \
dxBC = b->window.x - c->window.x; \
dyAC = a->window.y - c->window.y; \
dyBC = b->window.y - c->window.y; \
gc->polygon.shader.area = dxAC * dyBC - dxBC * dyAC;
#define STORE_AREA_PARAMS\
gc->polygon.shader.dxAC = dxAC; \
gc->polygon.shader.dxBC = dxBC; \
gc->polygon.shader.dyAC = dyAC; \
gc->polygon.shader.dyBC = dyBC;
#endif
#define SORT_AND_CULL_FACE(a, b, c, face, ccw)\
\
/* \
** Sort vertices in y. Keep track if a reversal of the winding \
** occurs in direction (0 means no reversal, 1 means reversal). \
** Save old vertex pointers in case we end up not doing a fill. \
*/ \
reversed = 0; \
if (__GL_VERTEX_COMPARE(a->window.y, <, b->window.y)) { \
if (__GL_VERTEX_COMPARE(b->window.y, <, c->window.y)) { \
/* Already sorted */ \
} else { \
if (__GL_VERTEX_COMPARE(a->window.y, <, c->window.y)) { \
temp=b; b=c; c=temp; \
reversed = 1; \
} else { \
temp=a; a=c; c=b; b=temp; \
} \
} \
} else { \
if (__GL_VERTEX_COMPARE(b->window.y, <, c->window.y)) { \
if (__GL_VERTEX_COMPARE(a->window.y, <, c->window.y)) { \
temp=a; a=b; b=temp; \
reversed = 1; \
} else { \
temp=a; a=b; b=c; c=temp; \
} \
} else { \
temp=a; a=c; c=temp; \
reversed = 1; \
} \
} \
\
GET_HALF_AREA(gc, a, b, c); \
ccw = !__GL_FLOAT_LTZ(gc->polygon.shader.area); \
\
/* \
** Figure out if face is culled or not. The face check needs to be \
** based on the vertex winding before sorting. This code uses the \
** reversed flag to invert the sense of ccw - an xor accomplishes \
** this conversion without an if test. \
** \
** ccw reversed xor \
** --- -------- --- \
** 0 0 0 (remain !ccw) \
** 1 0 1 (remain ccw) \
** 0 1 1 (become ccw) \
** 1 1 0 (become cw) \
*/ \
face = gc->polygon.face[ccw ^ reversed]; \
if (face == gc->polygon.cullFace) { \
/* Culled */ \
return; \
} \
\
STORE_AREA_PARAMS;
// #define NO_RENDERING
void __glTriangleOffsetZ( __GLcontext *gc, __GLvertex *a, __GLvertex *b,
__GLvertex *c)
{
__GLfloat dzAC, dzBC;
__GLfloat oneOverArea, t1, t2, t3, t4;
__GLfloat zOffset;
// Calc dzdxf, dzdyf values as in __glFillTriangle
/* Pre-compute one over polygon area */
if( gc->polygon.shader.area == 0.0f )
oneOverArea = (__GLfloat)(__glOne / __GL_PGON_OFFSET_NEAR_ZERO);
else
oneOverArea = __glOne / gc->polygon.shader.area;
/*
** Compute delta values for unit changes in x or y for each
** parameter.
*/
t1 = gc->polygon.shader.dyAC * oneOverArea;
t2 = gc->polygon.shader.dyBC * oneOverArea;
t3 = gc->polygon.shader.dxAC * oneOverArea;
t4 = gc->polygon.shader.dxBC * oneOverArea;
dzAC = a->window.z - c->window.z;
dzBC = b->window.z - c->window.z;
gc->polygon.shader.dzdxf = dzAC * t2 - dzBC * t1;
gc->polygon.shader.dzdyf = dzBC * t3 - dzAC * t4;
zOffset = __glPolygonOffsetZ(gc);
a->window.z += zOffset;
b->window.z += zOffset;
c->window.z += zOffset;
}
// Polygon offset z-munge: we modify the window.z of the vertices with the
// offset z, then restore the z after rendering, due to the possibility of the
// vertices being sent down multiple times by a higher-order primitive.
#define SAVE_WINDOW_Z \
awinz = a->window.z; bwinz = b->window.z; cwinz = c->window.z;
#define RESTORE_WINDOW_Z \
a->window.z = awinz; \
b->window.z = bwinz; \
c->window.z = cwinz;
#ifdef GL_EXT_flat_paletted_lighting
void __glPickLightingPalette(__GLcontext *gc)
{
__GLtexture *tex;
GLint loffset;
tex = gc->texture.currentTexture;
loffset = (GLint)(gc->vertex.provoking->color->r *
gc->oneOverRedVertexScale *
tex->paletteDivision) << tex->paletteDivShift;
tex->paletteData = tex->paletteTotalData+loffset;
__glGenSetPaletteOffset(gc, tex, loffset);
}
#endif GL_EXT_flat_paletted_lighting
/*
** Generic triangle handling code. This code is used when render mode
** is GL_RENDER and the polygon modes are not both fill.
*/
void FASTCALL __glRenderTriangle(__GLcontext *gc, __GLvertex *a,
__GLvertex *b, __GLvertex *c)
{
GLuint needs, modeFlags, faceNeeds;
GLint ccw, colorFace, reversed, face;
__GLfloat dxAC, dxBC, dyAC, dyBC;
__GLvertex *oa, *ob, *oc;
__GLvertex *temp;
__GLfloat awinz, bwinz, cwinz;
#ifdef NO_RENDERING
return;
#endif
oa = a; ob = b; oc = c;
SORT_AND_CULL_FACE(a, b, c, face, ccw);
/*
** Pick face to use for coloring
*/
modeFlags = gc->polygon.shader.modeFlags;
#ifdef NT
if (modeFlags & __GL_SHADE_SMOOTH_LIGHT)
{ /* Smooth shading */
if (modeFlags & __GL_SHADE_TWOSIDED && face == __GL_BACKFACE)
{
a->color++;
b->color++;
c->color++;
}
}
#ifdef GL_WIN_phong_shading
else if (modeFlags & __GL_SHADE_PHONG)
{ /* Phong shading */
if (modeFlags & __GL_SHADE_TWOSIDED && face == __GL_BACKFACE)
gc->polygon.shader.phong.face = __GL_BACKFACE;
else
gc->polygon.shader.phong.face = __GL_FRONTFACE;
}
#endif //GL_WIN_phong_shading
else
{ /* Flat shading */
__GLvertex *pv = gc->vertex.provoking;
if (modeFlags & __GL_SHADE_TWOSIDED && face == __GL_BACKFACE)
pv->color++;
a->color = pv->color;
b->color = pv->color;
c->color = pv->color;
}
#else
if (modeFlags & __GL_SHADE_TWOSIDED) {
colorFace = face;
faceNeeds = gc->vertex.faceNeeds[face];
} else {
colorFace = __GL_FRONTFACE;
faceNeeds = gc->vertex.faceNeeds[__GL_FRONTFACE];
}
/*
** Choose colors for the vertices.
*/
needs = gc->vertex.needs;
pv = gc->vertex.provoking;
if (modeFlags & __GL_SHADE_SMOOTH_LIGHT) {
/* Smooth shading */
a->color = &a->colors[colorFace];
b->color = &b->colors[colorFace];
c->color = &c->colors[colorFace];
needs |= faceNeeds;
} else {
GLuint pvneeds;
/*
** Validate the lighting (and color) information in the provoking
** vertex only. Fill routines always use gc->vertex.provoking->color
** to find the color.
*/
pv->color = &pv->colors[colorFace];
a->color = pv->color;
b->color = pv->color;
c->color = pv->color;
pvneeds = faceNeeds & (__GL_HAS_LIGHTING |
__GL_HAS_FRONT_COLOR | __GL_HAS_BACK_COLOR);
if (~pv->has & pvneeds) {
(*pv->validate)(gc, pv, pvneeds);
}
}
/* Validate vertices */
if (~a->has & needs) (*a->validate)(gc, a, needs);
if (~b->has & needs) (*b->validate)(gc, b, needs);
if (~c->has & needs) (*c->validate)(gc, c, needs);
#endif
/* Render triangle using the faces polygon mode */
switch (gc->polygon.mode[face]) {
case __GL_POLYGON_MODE_FILL:
if (__GL_FLOAT_NEZ(gc->polygon.shader.area)) {
#ifdef GL_EXT_flat_paletted_lighting
if ((gc->state.enables.general & __GL_PALETTED_LIGHTING_ENABLE) &&
(modeFlags & __GL_SHADE_SMOOTH_LIGHT) == 0 &&
gc->texture.currentTexture != NULL)
{
__glPickLightingPalette(gc);
}
#endif
(*gc->procs.fillTriangle)(gc, a, b, c, (GLboolean) ccw);
}
break;
case __GL_POLYGON_MODE_POINT:
if( gc->state.enables.general & __GL_POLYGON_OFFSET_POINT_ENABLE ) {
SAVE_WINDOW_Z;
__glTriangleOffsetZ( gc, a, b, c );
}
#ifdef NT
if (oa->has & __GL_HAS_EDGEFLAG_BOUNDARY)
(*gc->procs.renderPoint)(gc, oa);
if (ob->has & __GL_HAS_EDGEFLAG_BOUNDARY)
(*gc->procs.renderPoint)(gc, ob);
if (oc->has & __GL_HAS_EDGEFLAG_BOUNDARY)
(*gc->procs.renderPoint)(gc, oc);
if( gc->state.enables.general & __GL_POLYGON_OFFSET_POINT_ENABLE ) {
RESTORE_WINDOW_Z;
}
break;
#else
if (oa->boundaryEdge) (*gc->procs.renderPoint)(gc, oa);
if (ob->boundaryEdge) (*gc->procs.renderPoint)(gc, ob);
if (oc->boundaryEdge) (*gc->procs.renderPoint)(gc, oc);
break;
#endif
case __GL_POLYGON_MODE_LINE:
if( gc->state.enables.general & __GL_POLYGON_OFFSET_LINE_ENABLE ) {
SAVE_WINDOW_Z;
__glTriangleOffsetZ( gc, a, b, c );
}
#ifdef NT
(*gc->procs.lineBegin)(gc);
if ((oa->has & __GL_HAS_EDGEFLAG_BOUNDARY) &&
(ob->has & __GL_HAS_EDGEFLAG_BOUNDARY) &&
(oc->has & __GL_HAS_EDGEFLAG_BOUNDARY))
{
// Is this an important case to optimize?
(*gc->procs.renderLine)(gc, oa, ob, __GL_LVERT_FIRST);
(*gc->procs.renderLine)(gc, ob, oc, 0);
(*gc->procs.renderLine)(gc, oc, oa, 0);
}
else
{
if (oa->has & __GL_HAS_EDGEFLAG_BOUNDARY)
{
(*gc->procs.renderLine)(gc, oa, ob, __GL_LVERT_FIRST);
}
if (ob->has & __GL_HAS_EDGEFLAG_BOUNDARY)
{
(*gc->procs.renderLine)(gc, ob, oc, __GL_LVERT_FIRST);
}
if (oc->has & __GL_HAS_EDGEFLAG_BOUNDARY)
{
(*gc->procs.renderLine)(gc, oc, oa, __GL_LVERT_FIRST);
}
}
(*gc->procs.lineEnd)(gc);
if( gc->state.enables.general & __GL_POLYGON_OFFSET_LINE_ENABLE ) {
RESTORE_WINDOW_Z;
}
break;
#else
if (oa->boundaryEdge) {
(*gc->procs.renderLine)(gc, oa, ob);
}
if (ob->boundaryEdge) {
(*gc->procs.renderLine)(gc, ob, oc);
}
if (oc->boundaryEdge) {
(*gc->procs.renderLine)(gc, oc, oa);
}
break;
#endif
}
/* Restore color pointers */
a->color = &a->colors[__GL_FRONTFACE];
b->color = &b->colors[__GL_FRONTFACE];
c->color = &c->colors[__GL_FRONTFACE];
#ifdef NT
if (!(modeFlags & __GL_SHADE_SMOOTH_LIGHT)
#ifdef GL_WIN_phong_shading
&& !(modeFlags & __GL_SHADE_PHONG)
#endif //GL_WIN_phong_shading
)
{
__GLvertex *pv = gc->vertex.provoking;
pv->color = &pv->colors[__GL_FRONTFACE];
}
#else
pv->color = &pv->colors[__GL_FRONTFACE];
#endif
}
/************************************************************************/
/*
** Generic triangle handling code. This code is used when render mode
** is GL_RENDER and both polygon modes are FILL and the triangle is
** being flat shaded.
*/
void FASTCALL __glRenderFlatTriangle(__GLcontext *gc, __GLvertex *a, __GLvertex *b,
__GLvertex *c)
{
GLuint needs, pvneeds, modeFlags, faceNeeds;
GLint ccw, colorFace, reversed, face;
__GLfloat dxAC, dxBC, dyAC, dyBC;
__GLvertex *temp;
#ifdef NO_RENDERING
return;
#endif
SORT_AND_CULL_FACE(a, b, c, face, ccw);
if (__GL_FLOAT_EQZ(gc->polygon.shader.area))
return;
/*
** Pick face to use for coloring
*/
modeFlags = gc->polygon.shader.modeFlags;
#ifdef GL_EXT_flat_paletted_lighting
ASSERTOPENGL((modeFlags & __GL_SHADE_SMOOTH_LIGHT) == 0,
"Flat triangle with smooth shading\n");
if ((gc->state.enables.general & __GL_PALETTED_LIGHTING_ENABLE) &&
gc->texture.currentTexture != NULL)
{
__glPickLightingPalette(gc);
}
#endif
#ifdef NT
//!!! don't we need to update a,b,c color pointers if cheap fog is enabled?
if (modeFlags & __GL_SHADE_TWOSIDED && face == __GL_BACKFACE)
{
__GLvertex *pv = gc->vertex.provoking;
/* Fill triangle */
pv->color++;
(*gc->procs.fillTriangle)(gc, a, b, c, (GLboolean) ccw);
pv->color--;
}
else
{
/* Fill triangle */
(*gc->procs.fillTriangle)(gc, a, b, c, (GLboolean) ccw);
}
#else
if (modeFlags & __GL_SHADE_TWOSIDED) {
colorFace = face;
faceNeeds = gc->vertex.faceNeeds[face];
} else {
colorFace = __GL_FRONTFACE;
faceNeeds = gc->vertex.faceNeeds[__GL_FRONTFACE];
}
/*
** Choose colors for the vertices.
*/
needs = gc->vertex.needs;
pv = gc->vertex.provoking;
/*
** Validate the lighting (and color) information in the provoking
** vertex only. Fill routines always use gc->vertex.provoking->color
** to find the color.
*/
pv->color = &pv->colors[colorFace];
pvneeds = faceNeeds & (__GL_HAS_LIGHTING |
__GL_HAS_FRONT_COLOR | __GL_HAS_BACK_COLOR);
if (~pv->has & pvneeds) {
(*pv->validate)(gc, pv, pvneeds);
}
/* Validate vertices */
if (~a->has & needs) (*a->validate)(gc, a, needs);
if (~b->has & needs) (*b->validate)(gc, b, needs);
if (~c->has & needs) (*c->validate)(gc, c, needs);
/* Fill triangle */
(*gc->procs.fillTriangle)(gc, a, b, c, (GLboolean) ccw);
/* Restore color pointers */
pv->color = &pv->colors[__GL_FRONTFACE];
#endif
}
/************************************************************************/
/*
** Generic triangle handling code. This code is used when render mode
** is GL_RENDER and both polygon modes are FILL and the triangle is
** being smooth shaded.
*/
void FASTCALL __glRenderSmoothTriangle(__GLcontext *gc, __GLvertex *a, __GLvertex *b,
__GLvertex *c)
{
GLuint needs, modeFlags;
GLint ccw, colorFace, reversed, face;
__GLfloat dxAC, dxBC, dyAC, dyBC;
__GLvertex *temp;
#ifdef NO_RENDERING
return;
#endif
SORT_AND_CULL_FACE(a, b, c, face, ccw);
if (__GL_FLOAT_EQZ(gc->polygon.shader.area))
return;
/*
** Pick face to use for coloring
*/
modeFlags = gc->polygon.shader.modeFlags;
#ifdef GL_EXT_flat_paletted_lighting
// No lighting because smooth shading is always on in this routine
#endif
#ifdef NT
if (modeFlags & __GL_SHADE_TWOSIDED && face == __GL_BACKFACE)
{
/* Fill triangle */
a->color++;
b->color++;
c->color++;
(*gc->procs.fillTriangle)(gc, a, b, c, (GLboolean) ccw);
a->color--;
b->color--;
c->color--;
}
else
{
/* Fill triangle */
(*gc->procs.fillTriangle)(gc, a, b, c, (GLboolean) ccw);
}
#else
needs = gc->vertex.needs;
if (modeFlags & __GL_SHADE_TWOSIDED) {
colorFace = face;
needs |= gc->vertex.faceNeeds[face];
} else {
colorFace = __GL_FRONTFACE;
needs |= gc->vertex.faceNeeds[__GL_FRONTFACE];
}
/*
** Choose colors for the vertices.
*/
a->color = &a->colors[colorFace];
b->color = &b->colors[colorFace];
c->color = &c->colors[colorFace];
/* Validate vertices */
if (~a->has & needs) (*a->validate)(gc, a, needs);
if (~b->has & needs) (*b->validate)(gc, b, needs);
if (~c->has & needs) (*c->validate)(gc, c, needs);
/* Fill triangle */
(*gc->procs.fillTriangle)(gc, a, b, c, (GLboolean) ccw);
/* Restore color pointers */
a->color = &a->colors[__GL_FRONTFACE];
b->color = &b->colors[__GL_FRONTFACE];
c->color = &c->colors[__GL_FRONTFACE];
#endif
}
void FASTCALL __glDontRenderTriangle(__GLcontext *gc, __GLvertex *a, __GLvertex *b,
__GLvertex *c)
{
}