brender-1997/d3drend/onscreen.c
2022-05-03 14:31:40 -07:00

159 lines
3.6 KiB
C

/*
* Copyright (c) 1993-1995 Argonaut Technologies Limited. All rights reserved.
*
* $Id: onscreen.c 1.1 1997/07/11 16:14:26 jon Exp JON $
* $Locker: JON $
*
*/
#include "drv.h"
#include "shortcut.h"
BR_RCS_ID("$Id: onscreen.c 1.1 1997/07/11 16:14:26 jon Exp JON $")
/*
* Check a bounding box against the view volume and return
* one of:
*
* BRT_REJECT - Model is completely off screen
* BRT_PARTIAL - Model is partially on screen
* BRT_ACCEPT - Model is completely on screen
*
* Works by transforming the 6 planes that bound the view volume into
* model space. We have the model_to_screen transfrom. To transform a
* plane (screen to model), use the inverse of the transpose, ie: transpose
* of model_to_screen. Since the view plane equations are just zero's
* and ones, the transformed plane equation can be generated by adds/subs
* of specific rows of the transform.
*
* To test the (axis aligned) box against the view plane, only two vertices
* need testing - those that lie along the diagonal corresponding to the
* direction of the plane's normal.
*
* The components of these test vertices are selected from min/max
* by looking at the sign of the X,Y,Z components of the normal
*
* XXX Could probably write a mean version of this is assembler
*/
#define MAKE_EQN(sign,row) {\
eqn.v[X] = model_to_screen->m[0][3] sign model_to_screen->m[0][row];\
eqn.v[Y] = model_to_screen->m[1][3] sign model_to_screen->m[1][row];\
eqn.v[Z] = model_to_screen->m[2][3] sign model_to_screen->m[2][row];\
eqn.v[W] =-(model_to_screen->m[3][3] sign model_to_screen->m[3][row]);\
}
#define TEST_NOT_IN\
(BR_MAC3(\
eqn.v[X],((eqn.v[X]>0)?(bounds->min.v[X]):(bounds->max.v[X])),\
eqn.v[Y],((eqn.v[Y]>0)?(bounds->min.v[Y]):(bounds->max.v[Y])),\
eqn.v[Z],((eqn.v[Z]>0)?(bounds->min.v[Z]):(bounds->max.v[Z]))) <\
eqn.v[W])
#define TEST_OUT\
(BR_MAC3(\
eqn.v[X],((eqn.v[X]>0)?(bounds->max.v[X]):(bounds->min.v[X])),\
eqn.v[Y],((eqn.v[Y]>0)?(bounds->max.v[Y]):(bounds->min.v[Y])),\
eqn.v[Z],((eqn.v[Z]>0)?(bounds->max.v[Z]):(bounds->min.v[Z]))) <\
eqn.v[W])
br_token OnScreenCheck(br_renderer *self, br_matrix4 *model_to_screen, br_bounds3 *bounds)
{
int accept = 1;
br_vector4 eqn;
int c;
/*
* Left - screen space plane eqn. = ( 1, 0, 0, 1)
*/
MAKE_EQN(+,0);
if(TEST_OUT)
return BRT_REJECT;
if(TEST_NOT_IN)
accept = 0;
/*
* Right - screen space plane eqn. = (-1, 0, 0, 1)
*/
MAKE_EQN(-,0);
if(TEST_OUT)
return BRT_REJECT;
if(accept && TEST_NOT_IN)
accept = 0;
/*
* Bottom - screen space plane eqn. = ( 0, 1, 0, 1)
*/
MAKE_EQN(+,1);
if(TEST_OUT)
return BRT_REJECT;
if(accept && TEST_NOT_IN)
accept = 0;
/*
* Top - screen space plane eqn. = ( 0,-1, 0, 1)
*/
MAKE_EQN(-,1);
if(TEST_OUT)
return BRT_REJECT;
if(accept && TEST_NOT_IN)
accept = 0;
/*
* Yon - screen space plane eqn. = ( 0, 0, 1, 1)
*/
MAKE_EQN(+,2);
if(TEST_OUT)
return BRT_REJECT;
if(accept && TEST_NOT_IN)
accept = 0;
/*
* Hither - screen space plane eqn. = ( 0, 0,-1, 1)
*/
MAKE_EQN(-,2);
if(TEST_OUT)
return BRT_REJECT;
if(accept && TEST_NOT_IN)
accept = 0;
/*
* Any user clip planes
*
* XXX - user_clip_active needs checking - getting
* astale version here
*/
// if(scache.user_clip_active) {
for(c = 0; c < MAX_STATE_CLIP_PLANES; c++) {
if(self->state.clip[c].type != BRT_PLANE)
continue;
BrMatrix4TApply(&eqn,
&self->state.clip[c].plane,
model_to_screen);
eqn.v[W] = -eqn.v[W];
if(TEST_OUT)
return BRT_REJECT;
if(accept && TEST_NOT_IN)
accept = 0;
}
// }
return accept?BRT_ACCEPT:BRT_PARTIAL;
}