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

405 lines
12 KiB
C

/*
** Copyright 1991, 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
/*
** The following is a discussion of the math used to do edge clipping against
** a clipping plane.
**
** P1 is an end point of the edge
** P2 is the other end point of the edge
**
** Q = t*P1 + (1 - t)*P2
** That is, Q lies somewhere on the line formed by P1 and P2.
**
** 0 <= t <= 1
** This constrains Q to lie between P1 and P2.
**
** C is the plane equation for the clipping plane
**
** D1 = P1 dot C
** D1 is the distance between P1 and C. If P1 lies on the plane
** then D1 will be zero. The sign of D1 will determine which side
** of the plane that P1 is on, with negative being outside.
**
** D2 = P2 dot C
** D2 is the distance between P2 and C. If P2 lies on the plane
** then D2 will be zero. The sign of D2 will determine which side
** of the plane that P2 is on, with negative being outside.
**
** Because we are trying to find the intersection of the P1 P2 line
** segment with the clipping plane we require that:
**
** Q dot C = 0
**
** Therefore
**
** (t*P1 + (1 - t)*P2) dot C = 0
**
** (t*P1 + P2 - t*P2) dot C = 0
**
** t*P1 dot C + P2 dot C - t*P2 dot C = 0
**
** Substituting D1 and D2 in
**
** t*D1 + D2 - t*D2 = 0
**
** Solving for t
**
** t = -D2 / (D1 - D2)
**
** t = D2 / (D2 - D1)
*/
/*
** Clip a line against the frustum clip planes and any user clipping planes.
** If an edge remains after clipping then compute the window coordinates
** and invoke the renderer.
**
** Notice: This algorithim is an example of an implementation that is
** different than what the spec says. This is equivalent in functionality
** and meets the spec, but doesn't clip in eye space. This clipper clips
** in NTVP (clip) space.
**
** Trivial accept/reject has already been dealt with.
*/
#ifdef NT
void FASTCALL __glClipLine(__GLcontext *gc, __GLvertex *a, __GLvertex *b,
GLuint flags)
#else
void __glClipLine(__GLcontext *gc, __GLvertex *a, __GLvertex *b)
#endif
{
#ifdef NT
__GLvertex *provokingA = a;
__GLvertex *provokingB = b;
#else
__GLvertex *provoking = b;
#endif
__GLvertex np1, np2;
__GLcoord *plane;
GLuint needs, allClipCodes, clipCodes;
PFN_VERTEX_CLIP_PROC clip;
__GLfloat zero;
__GLfloat winx, winy;
__GLfloat vpXCenter, vpYCenter, vpZCenter;
__GLfloat vpXScale, vpYScale, vpZScale;
__GLviewport *vp;
__GLfloat x, y, z, wInv;
GLint i;
// We have to turn rounding on. Otherwise, the fast FP-comparison
// routines below can fail:
FPU_SAVE_MODE();
FPU_ROUND_ON_PREC_HI();
/* Check for trivial pass of the line */
allClipCodes = a->clipCode | b->clipCode;
/*
** For each clippling plane that something is out on, clip
** check the verticies. Note that no bits will be set in
** allClipCodes for clip planes that are not enabled.
*/
zero = __glZero;
clip = gc->procs.lineClipParam;
/*
** Do user clip planes first, because we will maintain eye coordinates
** only while doing user clip planes. They are ignored for the
** frustum clipping planes.
*/
clipCodes = allClipCodes >> 6;
if (clipCodes) {
plane = &gc->state.transform.eyeClipPlanes[0];
do {
/*
** See if this clip plane has anything out of it. If not,
** press onward to check the next plane. Note that we
** shift this mask to the right at the bottom of the loop.
*/
if (clipCodes & 1) {
__GLfloat t, d1, d2;
d1 = (plane->x * ((POLYDATA *)a)->eye.x) +
(plane->y * ((POLYDATA *)a)->eye.y) +
(plane->z * ((POLYDATA *)a)->eye.z) +
(plane->w * ((POLYDATA *)a)->eye.w);
d2 = (plane->x * ((POLYDATA *)b)->eye.x) +
(plane->y * ((POLYDATA *)b)->eye.y) +
(plane->z * ((POLYDATA *)b)->eye.z) +
(plane->w * ((POLYDATA *)b)->eye.w);
if (__GL_FLOAT_LTZ(d1)) {
/* a is out */
if (__GL_FLOAT_LTZ(d2)) {
/* a & b are out */
FPU_RESTORE_MODE();
return;
}
/*
** A is out and B is in. Compute new A coordinate
** clipped to the plane.
*/
t = d2 / (d2 - d1);
(*clip)(&np1, a, b, t);
((POLYDATA *)&np1)->eye.x =
t*(((POLYDATA *)a)->eye.x - ((POLYDATA *)b)->eye.x) +
((POLYDATA *)b)->eye.x;
((POLYDATA *)&np1)->eye.y =
t*(((POLYDATA *)a)->eye.y - ((POLYDATA *)b)->eye.y) +
((POLYDATA *)b)->eye.y;
((POLYDATA *)&np1)->eye.z =
t*(((POLYDATA *)a)->eye.z - ((POLYDATA *)b)->eye.z) +
((POLYDATA *)b)->eye.z;
((POLYDATA *)&np1)->eye.w =
t*(((POLYDATA *)a)->eye.w - ((POLYDATA *)b)->eye.w) +
((POLYDATA *)b)->eye.w;
a = &np1;
a->has = b->has;
ASSERTOPENGL(!(a->has & __GL_HAS_FIXEDPT), "clear __GL_HAS_FIXEDPT flag!\n");
} else {
/* a is in */
if (__GL_FLOAT_LTZ(d2)) {
/*
** A is in and B is out. Compute new B
** coordinate clipped to the plane.
**
** NOTE: To avoid cracking in polygons with
** shared clipped edges we always compute "t"
** from the out vertex to the in vertex. The
** above clipping code gets this for free (b is
** in and a is out). In this code b is out and a
** is in, so we reverse the t computation and the
** argument order to (*clip).
*/
t = d1 / (d1 - d2);
(*clip)(&np2, b, a, t);
((POLYDATA *)&np2)->eye.x =
t*(((POLYDATA *)b)->eye.x - ((POLYDATA *)a)->eye.x)+
((POLYDATA *)a)->eye.x;
((POLYDATA *)&np2)->eye.y =
t*(((POLYDATA *)b)->eye.y - ((POLYDATA *)a)->eye.y)+
((POLYDATA *)a)->eye.y;
((POLYDATA *)&np2)->eye.z =
t*(((POLYDATA *)b)->eye.z - ((POLYDATA *)a)->eye.z)+
((POLYDATA *)a)->eye.z;
((POLYDATA *)&np2)->eye.w =
t*(((POLYDATA *)b)->eye.w - ((POLYDATA *)a)->eye.w)+
((POLYDATA *)a)->eye.w;
b = &np2;
b->has = a->has;
ASSERTOPENGL(!(b->has & __GL_HAS_FIXEDPT), "clear __GL_HAS_FIXEDPT flag!\n");
} else {
/* A and B are in */
}
}
}
plane++;
clipCodes >>= 1;
} while (clipCodes);
}
allClipCodes &= __GL_FRUSTUM_CLIP_MASK;
if (allClipCodes) {
i = 0;
do {
/*
** See if this clip plane has anything out of it. If not,
** press onward to check the next plane. Note that we
** shift this mask to the right at the bottom of the loop.
*/
if (allClipCodes & 1) {
__GLfloat t, d1, d2;
if (i & 1)
{
d1 = a->clip.w -
*(__GLfloat *)((GLubyte *)a + __glFrustumOffsets[i]);
d2 = b->clip.w -
*(__GLfloat *)((GLubyte *)b + __glFrustumOffsets[i]);
}
else
{
d1 = *(__GLfloat *)((GLubyte *)a + __glFrustumOffsets[i]) +
a->clip.w;
d2 = *(__GLfloat *)((GLubyte *)b + __glFrustumOffsets[i]) +
b->clip.w;
}
if (__GL_FLOAT_LTZ(d1)) {
/* a is out */
if (__GL_FLOAT_LTZ(d2)) {
/* a & b are out */
FPU_RESTORE_MODE();
return;
}
/*
** A is out and B is in. Compute new A coordinate
** clipped to the plane.
*/
t = d2 / (d2 - d1);
(*clip)(&np1, a, b, t);
a = &np1;
a->has = b->has;
ASSERTOPENGL(!(a->has & __GL_HAS_FIXEDPT), "clear __GL_HAS_FIXEDPT flag!\n");
} else {
/* a is in */
if (__GL_FLOAT_LTZ(d2)) {
/*
** A is in and B is out. Compute new B
** coordinate clipped to the plane.
**
** NOTE: To avoid cracking in polygons with
** shared clipped edges we always compute "t"
** from the out vertex to the in vertex. The
** above clipping code gets this for free (b is
** in and a is out). In this code b is out and a
** is in, so we reverse the t computation and the
** argument order to (*clip).
*/
t = d1 / (d1 - d2);
(*clip)(&np2, b, a, t);
b = &np2;
b->has = a->has;
ASSERTOPENGL(!(b->has & __GL_HAS_FIXEDPT), "clear __GL_HAS_FIXEDPT flag!\n");
} else {
/* A and B are in */
}
}
}
i++;
allClipCodes >>= 1;
} while (allClipCodes);
}
vp = &gc->state.viewport;
vpXCenter = vp->xCenter;
vpYCenter = vp->yCenter;
vpZCenter = vp->zCenter;
vpXScale = vp->xScale;
vpYScale = vp->yScale;
vpZScale = vp->zScale;
/* Compute window coordinates for vertices generated by clipping */
if (provokingA->clipCode != 0)
{
wInv = __glOne / a->clip.w;
x = a->clip.x;
y = a->clip.y;
z = a->clip.z;
winx = x * vpXScale * wInv + vpXCenter;
winy = y * vpYScale * wInv + vpYCenter;
if (winx < gc->transform.fminx)
winx = gc->transform.fminx;
else if (winx >= gc->transform.fmaxx)
winx = gc->transform.fmaxx - gc->constants.viewportEpsilon;
if (winy < gc->transform.fminy)
winy = gc->transform.fminy;
else if (winy >= gc->transform.fmaxy)
winy = gc->transform.fmaxy - gc->constants.viewportEpsilon;
a->window.z = z * vpZScale * wInv + vpZCenter;
a->window.w = wInv;
a->window.x = winx;
a->window.y = winy;
// Update color pointer since this vertex is a new one
// generated by clipping
if (gc->state.light.shadingModel == GL_FLAT)
{
a->color = &provokingA->colors[__GL_FRONTFACE];
}
else
{
a->color = &a->colors[__GL_FRONTFACE];
}
}
if (provokingB->clipCode != 0)
{
wInv = __glOne / b->clip.w;
x = b->clip.x;
y = b->clip.y;
z = b->clip.z;
winx = x * vpXScale * wInv + vpXCenter;
winy = y * vpYScale * wInv + vpYCenter;
if (winx < gc->transform.fminx)
winx = gc->transform.fminx;
else if (winx >= gc->transform.fmaxx)
winx = gc->transform.fmaxx - gc->constants.viewportEpsilon;
if (winy < gc->transform.fminy)
winy = gc->transform.fminy;
else if (winy >= gc->transform.fmaxy)
winy = gc->transform.fmaxy - gc->constants.viewportEpsilon;
b->window.z = z * vpZScale * wInv + vpZCenter;
b->window.w = wInv;
b->window.x = winx;
b->window.y = winy;
if (gc->state.light.shadingModel == GL_FLAT)
{
b->color = &provokingB->colors[__GL_FRONTFACE];
}
else
{
b->color = &b->colors[__GL_FRONTFACE];
}
}
// Restore the floating-point mode for rendering:
FPU_RESTORE_MODE();
/* Validate line state */
if (gc->state.light.shadingModel == GL_FLAT) {
// Add the vertices then restore the b color pointer
//
// Note that although b is the only new vertex, up
// to two vertices can be added because each new vertex
// generated by clipping must be added. For a line where
// both endpoints are out of the clipping region, both
// an entry and an exit vertex must be added
if (provokingA->clipCode != 0)
{
// a was out so a new vertex was added at the point of
// entry
flags |= __GL_LVERT_FIRST;
}
// b is always added since either:
// b was in and is new so it needs to be added
// b was out so a new vertex was added at the exit point
(*gc->procs.renderLine)(gc, a, b, flags);
#ifndef NT
b->color = &b->colors[__GL_FRONTFACE];
#endif
} else {
if (provokingA->clipCode != 0)
{
flags |= __GL_LVERT_FIRST;
}
(*gc->procs.renderLine)(gc, a, b, flags);
}
}