brender-1997/v1db/custsupt.c

514 lines
16 KiB
C
Raw Normal View History

2022-05-03 16:30:35 -05:00
/*
* Copyright (c) 1993-1995 Argonaut Technologies Limited. All rights reserved.
*
* $Id: custsupt.c 2.7 1996/10/02 16:31:12 NEELA Exp $
* $Locker: $
*
* Support routines for application
*/
#include "v1db.h"
#include "shortcut.h"
#include "brassert.h"
BR_RCS_ID("$Id: custsupt.c 2.7 1996/10/02 16:31:12 NEELA Exp $")
#define BR_FIXED_SIGN 0x80000000UL
/*
* Perspective divide for Z component of vertices
*/
#if BASED_FLOAT
#define PERSP_DIV_Z(a,b) (-32767.0 * (a)/(b))
#endif
#if BASED_FIXED
#define PERSP_DIV_Z(a,b) ((long)((unsigned long)_FixedDivP(a,b)^BR_FIXED_SIGN))
#endif
#define OUTCODE_POINT(outcode,screen)\
{ \
/* \
* The 6 planes of the view volume... \
*/ \
if((screen)->v[X] >= (screen)->v[W]) \
(outcode) ^= (OUTCODE_RIGHT | OUTCODE_N_RIGHT); \
if((screen)->v[X] < -(screen)->v[W]) \
(outcode) ^= (OUTCODE_LEFT | OUTCODE_N_LEFT); \
\
if((screen)->v[Y] >= (screen)->v[W]) \
(outcode) ^= (OUTCODE_TOP | OUTCODE_N_TOP); \
if((screen)->v[Y] < -(screen)->v[W]) \
(outcode) ^= (OUTCODE_BOTTOM | OUTCODE_N_BOTTOM); \
\
if((screen)->v[Z] >= (screen)->v[W]) \
(outcode) ^= (OUTCODE_HITHER | OUTCODE_N_HITHER); \
if((screen)->v[Z] < -(screen)->v[W]) \
(outcode) ^= (OUTCODE_YON | OUTCODE_N_YON); \
}
/*
* Fetches the current model_to_screen transform
*/
void BR_PUBLIC_ENTRY BrModelToScreenQuery(br_matrix4 *dest)
{
br_uint_32 dummy;
br_matrix4 v2s;
br_matrix34 m2v;
UASSERT(v1db.rendering);
ASSERT(v1db.renderer);
UASSERT_MESSAGE("BrModelToScreenQuery NULL pointer to the destination matrix that holds the current model_to_screen transform", dest != NULL);
RendererPartQueryBuffer(v1db.renderer, BRT_MATRIX, 0, &dummy,
(void *)&v2s, sizeof(v2s), BRT_AS_MATRIX4_SCALAR(VIEW_TO_SCREEN));
RendererPartQueryBuffer(v1db.renderer, BRT_MATRIX, 0, &dummy,
(void *)&m2v, sizeof(m2v), BRT_AS_MATRIX34_SCALAR(MODEL_TO_VIEW));
BrMatrix4Mul34(dest, &m2v, &v2s);
}
/*
* Fetches the current model_to_view transform
*/
void BR_PUBLIC_ENTRY BrModelToViewQuery(br_matrix34 *dest)
{
br_uint_32 dummy;
UASSERT(v1db.rendering);
ASSERT(v1db.renderer);
UASSERT_MESSAGE("BrModelToViewQuery NULL pointer to the destination matrix that holds the current model_to_view transform", dest != NULL);
RendererPartQueryBuffer(v1db.renderer, BRT_MATRIX, 0, &dummy,
(void *)dest, sizeof(*dest), BRT_AS_MATRIX34_SCALAR(MODEL_TO_VIEW));
}
/*
* Transform and project 0,0,0 into screen space
*
* Return 1 if point is behind eye
*/
br_uint_8 BR_PUBLIC_ENTRY BrOriginToScreenXY(br_vector2 *screen)
{
UASSERT(v1db.rendering);
UASSERT_MESSAGE("BrOriginToScreenXY NULL pointer to the destination vector to receive the coords.in projected screen space", screen != NULL);
if(!v1db.model_to_screen_valid) {
BrModelToScreenQuery(&v1db.model_to_screen);
v1db.model_to_screen_valid = BR_TRUE;
}
UASSERT_MESSAGE("BrOriginToScreenXY - Divide by zero error", v1db.model_to_screen.m[3][3] != 0 );
screen->v[X] = v1db.vp_ox + BR_MULDIV(v1db.vp_width,v1db.model_to_screen.m[3][0],v1db.model_to_screen.m[3][3]);
screen->v[Y] = v1db.vp_oy + BR_MULDIV(v1db.vp_height,v1db.model_to_screen.m[3][1],v1db.model_to_screen.m[3][3]);
return (v1db.model_to_screen.m[3][2] > BR_SCALAR(0.0));
}
/*
* Transform and project 0,0,0 into screen space, generate X,Y,Z and return outcode
*
* If the point is offscreen, it will not be projected
*/
br_uint_32 BR_PUBLIC_ENTRY BrOriginToScreenXYZO(br_vector3 *screen)
{
br_uint_32 outcode = OUTCODES_NOT;
UASSERT(v1db.rendering);
UASSERT_MESSAGE("BrOriginToScreenXYZO NULL pointer to the destination vector to receive the coords.in projected screen space", screen != NULL);
if(!v1db.model_to_screen_valid) {
BrModelToScreenQuery(&v1db.model_to_screen);
v1db.model_to_screen_valid = BR_TRUE;
}
OUTCODE_POINT(outcode,((br_vector4 *)(v1db.model_to_screen.m[3])));
UASSERT_MESSAGE("BrOriginToScreenXYZO - Divide by zero error", v1db.model_to_screen.m[3][3] != 0 );
if(!(outcode & OUTCODES_ALL)) {
screen->v[X] = v1db.vp_ox + BR_MULDIV(v1db.vp_width,v1db.model_to_screen.m[3][0],v1db.model_to_screen.m[3][3]);
screen->v[Y] = v1db.vp_oy + BR_MULDIV(v1db.vp_height,v1db.model_to_screen.m[3][1],v1db.model_to_screen.m[3][3]);
screen->v[Z] = PERSP_DIV_Z(v1db.model_to_screen.m[3][2],v1db.model_to_screen.m[3][3]);
}
return outcode;
}
/*
* Transform and project a single point into screen space
*
* Return 1 if point is behind eye
*/
br_uint_8 BR_PUBLIC_ENTRY BrPointToScreenXY(br_vector2 *screen, br_vector3 *point)
{
br_vector4 sp;
UASSERT(v1db.rendering);
UASSERT_MESSAGE("BrPointToScreenXY NULL pointer to the destination vector to receive the coords.in projected screen space", screen != NULL);
UASSERT_MESSAGE("BrPointToScreenXY NULL pointer to the source vector containing the coords of the point to project", point != NULL);
if(!v1db.model_to_screen_valid) {
BrModelToScreenQuery(&v1db.model_to_screen);
v1db.model_to_screen_valid = BR_TRUE;
}
BrMatrix4ApplyP(&sp,point,&v1db.model_to_screen);
UASSERT_MESSAGE("BrPointToScreenXY - Divide by zero error", sp.v[3] != 0 );
screen->v[X] = v1db.vp_ox + BR_MULDIV(v1db.vp_width,sp.v[0],sp.v[3]);
screen->v[Y] = v1db.vp_oy + BR_MULDIV(v1db.vp_height,sp.v[1],sp.v[3]);
return (sp.v[2] > BR_SCALAR(0.0));
}
/*
* Transform and project a single point into screen space
*
* Return 1 if point is behind eye
*/
br_uint_32 BR_PUBLIC_ENTRY BrPointToScreenXYZO(br_vector3 *screen, br_vector3 *point)
{
br_vector4 sp;
br_uint_32 outcode = OUTCODES_NOT;
UASSERT(v1db.rendering);
UASSERT_MESSAGE("BrPointToScreenXYZO NULL pointer to the destination vector to receive the coords.in projected screen space", screen != NULL);
UASSERT_MESSAGE("BrPointToScreenXYZO NULL pointer to the source vector containing the coords of the point to project", point != NULL);
if(!v1db.model_to_screen_valid) {
BrModelToScreenQuery(&v1db.model_to_screen);
v1db.model_to_screen_valid = BR_TRUE;
}
BrMatrix4ApplyP(&sp,point,&v1db.model_to_screen);
OUTCODE_POINT(outcode,&sp);
UASSERT_MESSAGE("BrPointToScreenXYZO - Divide by zero error", sp.v[3] != 0 );
if(!(outcode & OUTCODES_ALL)) {
screen->v[X] = v1db.vp_ox + BR_MULDIV(v1db.vp_width,sp.v[0],sp.v[3]);
screen->v[Y] = v1db.vp_oy + BR_MULDIV(v1db.vp_height,sp.v[1],sp.v[3]);
screen->v[Z] = PERSP_DIV_Z(sp.v[2],sp.v[3]);
}
return outcode;
}
/*
* Transform and project many points into screen space
*/
void BR_PUBLIC_ENTRY BrPointToScreenXYMany(br_vector2 *screens, br_vector3 *points, br_uint_32 npoints)
{
br_vector4 sp;
br_uint_32 i;
UASSERT(v1db.rendering);
UASSERT_MESSAGE("BrPointToScreenXYMany NULL pointer to an array of destination vectors", screens != NULL);
UASSERT_MESSAGE("BrPointToScreenXYMany NULL pointer to an array of source vectors containing the coords of the points in model space", points != NULL);
if(!v1db.model_to_screen_valid) {
BrModelToScreenQuery(&v1db.model_to_screen);
v1db.model_to_screen_valid = BR_TRUE;
}
for(i=0; i< npoints; i++, screens++, points++) {
BrMatrix4ApplyP(&sp,points,&v1db.model_to_screen);
UASSERT_MESSAGE("BrPointToScreenXYMany - Divide by zero error", sp.v[3] != 0 );
screens->v[X] = v1db.vp_ox + BR_MULDIV(v1db.vp_width,sp.v[0],sp.v[3]);
screens->v[Y] = v1db.vp_oy + BR_MULDIV(v1db.vp_height,sp.v[1],sp.v[3]);
}
}
/*
* Transform and project many points into screen space, generate X,Y,Z
*
* Outcode each point, and if it is not on screen, don't project it
*/
void BR_PUBLIC_ENTRY BrPointToScreenXYZOMany(br_vector3 *screens, br_uint_32 *outcodes, br_vector3 *points, br_uint_32 npoints)
{
br_vector4 sp;
br_uint_32 i;
br_uint_32 outcode = OUTCODES_NOT;
UASSERT(v1db.rendering);
UASSERT_MESSAGE("BrPointToScreenXYZOMany NULL pointer to an array of destination vectors", screens != NULL);
UASSERT_MESSAGE("BrPointToScreenXYZOMany NULL pointer to an array of source vectors" , points != NULL);
UASSERT_MESSAGE("BrPointToScreenXYZOMany NULL pointer to an array of outcodes for each point" , points != NULL);
if(!v1db.model_to_screen_valid) {
BrModelToScreenQuery(&v1db.model_to_screen);
v1db.model_to_screen_valid = BR_TRUE;
}
for(i=0; i< npoints; i++, screens++, points++,outcodes++) {
BrMatrix4ApplyP(&sp,points,&v1db.model_to_screen);
OUTCODE_POINT(outcode,&sp);
*outcodes = outcode;
if(outcode & OUTCODES_ALL)
continue;
UASSERT_MESSAGE("BrPointToScreenXYZOMany - Divide by zero error", sp.v[3] != 0 );
screens->v[X] = v1db.vp_ox + BR_MULDIV(v1db.vp_width,sp.v[0],sp.v[3]);
screens->v[Y] = v1db.vp_oy + BR_MULDIV(v1db.vp_height,sp.v[1],sp.v[3]);
screens->v[Z] = PERSP_DIV_Z(sp.v[2],sp.v[3]);
}
}
#if 0
/*
* Transform and project many points into screen space, generate X,Y,Z
*
*/
void BR_PUBLIC_ENTRY BrPointToScreenXYZMany(br_vector3 *screens, br_vector3 *points, br_uint_32 npoints)
{
br_vector4 sp;
int i;
br_uint_32 outcode = OUTCODES_NOT;
UASSERT(v1db.rendering);
UASSERT_MESSAGE("BrPointToScreenXYZMany NULL pointer to an array of destination vectors", screens != NULL);
UASSERT_MESSAGE("BrPointToScreenXYZMany NULL pointer to an array of source vectors" , points != NULL);
for(i=0; i< npoints; i++, screens++, points++) {
BrMatrix4ApplyP(&sp,points,&v1db.model_to_screen);
UASSERT_MESSAGE("BrPointToScreenXYZMany - Divide by zero error", sp.v[3] != 0 );
screens->v[X] = v1db.vp_ox + BR_MULDIV(v1db.vp_width,sp.v[0],sp.v[3]);
screens->v[Y] = v1db.vp_oy + BR_MULDIV(v1db.vp_height,sp.v[1],sp.v[3]);
screens->v[Z] = PERSP_DIV_Z(sp.v[2],sp.v[3]);
}
}
#endif
/*
* Convert Z-buffer depth (0,0xffffffff) to screen Z (-32,768.0 to +32,767.9)
*/
br_scalar BR_PUBLIC_ENTRY BrZbDepthToScreenZ(br_uint_32 depth_z,const br_camera* camera)
{ UASSERT_MESSAGE("BrZbDepthToScreenZ NULL pointer to camera being used for rendering", camera != NULL); // Not accessed, but should still be valid
return BrFixedToScalar((br_fixed_ls)(depth_z^BR_FIXED_SIGN));
}
/*
* Convert Screen Z (-32,768.0 to +32,767.9) to Z-buffer depth (0,0xffffffff)
*
* Clamp to view
*/
#define NEAREST (-32767.9f)
#define FARTHEST (32767.9f)
#define TOONEAR (-32768.f)
#define TOOFAR (32768.f)
br_uint_32 BR_PUBLIC_ENTRY BrZbScreenZToDepth(br_scalar sz,const br_camera* camera)
{ br_uint_32 depth=(br_uint_32)BrScalarToFixed(sz)^BR_FIXED_SIGN;
UASSERT_MESSAGE("BrZbScreenZToDepth NULL pointer to camera being used for rendering", camera != NULL); // Not accessed, but should still be valid
/* Not accessed, but should still be valid */
#if BASED_FLOAT
if (sz<=TOONEAR)
return 0UL;
else
if (sz>=TOOFAR)
return 0xffffffffUL;
#elif 0 /* Alternative that caters for border line cases - if they can occur */
if (sz<NEAREST || sz>FARTHEST) /* Only do further processing if screen z outside normal range */
{ if (sz<NEAREST)
{ if (sz<TOONEAR || depth>BR_FIXED_SIGN) /* Either a long way off or just beyond the border line */
return 0UL;
}
else
{ if (sz>TOOFAR || depth<BR_FIXED_SIGN) /* Either a long way off or just beyond the border line */
return 0xffffffffUL;
}
}
#endif
return depth;
}
#if 0
#if BASED_FIXED
#define MUL15DIV(a,b) BrFixedDivF(a,b)
#endif
#if BASED_FLOAT
#define MUL15DIV(a,b) ((a)/(b)*32768.f)
#endif
#endif
/*
* Convert Z-sort depth (-hither,+yon) to screen Z (-32,768.0 to +32,767.9)
*
* Clamp to view
*
*/
br_scalar BR_PUBLIC_ENTRY BrZsDepthToScreenZ(br_scalar depth_z,const br_camera* camera)
{ br_scalar hither,yon;
hither=camera->hither_z;
yon=camera->yon_z;
UASSERT_MESSAGE("BrZsDepthToScreenZ NULL pointer to camera being used for rendering", camera != NULL); // Not accessed, but should still be valid
if (depth_z<=hither)
return BrFixedToScalar((br_fixed_ls)0x80000000);
else
if (depth_z>=yon)
return BrFixedToScalar((br_fixed_ls)0x7fffffff);
UASSERT_MESSAGE("BrZsDepthToScreenZ - Divide by zero error", yon != hither );
return BR_CONST_MUL(BR_MULDIV(BR_SUB(BR_SUB(BR_CONST_MUL(depth_z,2),yon),hither),BR_SCALAR(16384),BR_SUB(yon,hither)),2);
}
/*
* Convert Screen Z (-32,768.0 to +32,767.9) to Z-sort depth (-hither,+yon)
*
* Clamp to view
*/
br_scalar BR_PUBLIC_ENTRY BrZsScreenZToDepth(br_scalar sz,const br_camera* camera)
{ br_scalar hither,yon,depth;
hither=camera->hither_z;
yon=camera->yon_z;
UASSERT_MESSAGE("BrZsScreenZToDepth NULL pointer to camera being used for rendering", camera != NULL); // Not accessed, but should still be valid
/* depth=BR_CONST_DIV(BR_MULDIV(sz,yon+hither,BR_SCALAR(-32768.f))-yon+hither,2); Not so good */
depth=BR_CONST_DIV(BR_ADD(BR_MULDIV(BR_CONST_DIV(sz,2),BR_SUB(yon,hither),BR_SCALAR(16384)),BR_ADD(yon,hither)),2);
#if BASED_FLOAT
if (sz<=TOONEAR)
return hither;
else
if (sz>=TOOFAR)
return yon;
#endif
return depth;
}
/*
* Convert z ordinate in screen space to view space
*/
br_scalar BR_PUBLIC_ENTRY BrScreenZToCamera(const br_actor* camera, br_scalar sz)
{ const br_camera* data;
br_scalar hither,yon;
UASSERT_MESSAGE("BrScreenZToCamera NULL pointer to camera actor", camera != NULL);
UASSERT_MESSAGE("BrScreenZToCamera - invalid camera data", camera->type_data != NULL);
data=camera->type_data;
hither=data->hither_z;
yon=data->yon_z;
UASSERT(data->type==BR_CAMERA_PARALLEL || data->type==BR_CAMERA_PERSPECTIVE);
#if BASED_FLOAT
if (sz<=TOONEAR)
return BR_NEG(hither);
else
if (sz>=TOOFAR)
return BR_NEG(yon);
#endif
switch (data->type)
{
case BR_CAMERA_PARALLEL:
return BR_SUB(
BR_MULDIV(
BR_CONST_DIV(sz,2),
BR_CONST_DIV(BR_SUB(hither,yon),2),
BR_SCALAR(16384))
, BR_CONST_DIV(BR_ADD(hither,yon),2)
);
case BR_CAMERA_PERSPECTIVE:
UASSERT_MESSAGE("BrScreenZToCamera - Divide by zero error",BR_SUB(
BR_MULDIV(
BR_CONST_DIV(sz,2)
, BR_SUB(yon,hither)
, BR_SCALAR(16384)
)
, BR_ADD(hither,yon)
) != 0);
return BR_CONST_MUL(
BR_MULDIV(
hither
, yon
, BR_SUB(
BR_MULDIV(
BR_CONST_DIV(sz,2)
, BR_SUB(yon,hither)
, BR_SCALAR(16384)
)
, BR_ADD(hither,yon)
)
)
, 2
);
default:
UASSERT(0);
return BR_SCALAR(0);
}
}
void BR_PUBLIC_ENTRY BrScreenXYZToCamera(br_vector3* point,const br_actor* camera,
const br_pixelmap* screen_buffer, br_int_16 x, br_int_16 y,br_scalar sz)
{ br_scalar hx,hy;
br_scalar vz;
const br_camera* data;
br_angle fov;
br_scalar scale;
UASSERT_MESSAGE("BrScreenXYZToCamera NULL pointer to vector to hold the converted point in camera space", point != NULL);
UASSERT_MESSAGE("BrScreenXYZToCamera NULL pointer to camera actor", camera != NULL);
UASSERT_MESSAGE("BrScreenXYZToCamera - invalid camera data", camera->type_data != NULL);
UASSERT_MESSAGE("BrScreenXYZToCamera NULL pointer to the screen buffer", screen_buffer != NULL);
data=camera->type_data;
vz=BrScreenZToCamera(camera,sz); // Get the original view Z
UASSERT_MESSAGE("BrScreenXYZToCamera - Divide by zero error", BrIntToScalar(screen_buffer->width) != 0);
UASSERT_MESSAGE("BrScreenXYZToCamera - Divide by zero error", BrIntToScalar(screen_buffer->height) != 0);
hx=BR_DIV(BrIntToScalar(screen_buffer->width-2*(x+screen_buffer->origin_x)),BrIntToScalar(screen_buffer->width)); // homogenous -x [ hx=2(sx+ox)/sw-1, -hx=(sw-2(sx+ox))/sw ]
hy=BR_DIV(BrIntToScalar(2*(y+screen_buffer->origin_y)-screen_buffer->height),BrIntToScalar(screen_buffer->height)); // homogenous -y [ hy=1-2(sy+oy)/sh, -hy=(2(sy+oy)-sh)/sh ]
switch (data->type)
{
case BR_CAMERA_PARALLEL:
point->v[0]=BR_CONST_DIV(BR_MUL(BR_NEG(hx),BR_MUL(data->width,data->aspect)),2); // Vx=-hx*cw*ca/2
point->v[1]=BR_CONST_DIV(BR_MUL(BR_NEG(hy),data->height),2); // Vy=-hy*ch/2
point->v[2]=vz; // Vz
break;
case BR_CAMERA_PERSPECTIVE:
fov=(br_angle)(data->field_of_view/2);
UASSERT_MESSAGE("BrScreenXYZToCamera - Divide by zero error", BR_SIN(fov) != 0);
scale=BR_DIV(BR_COS(fov),BR_SIN(fov)); // Refer to BrMatrix4Perspective() - we are using its terms in reverse
UASSERT_MESSAGE("BrScreenXYZToCamera - Divide by zero error", scale != 0);
point->v[0]=BR_MULDIV(BR_MUL(hx,data->aspect),vz,scale); // View x
point->v[1]=BR_MULDIV(hy,vz,scale); // View y
point->v[2]=vz; // View z
break;
default:
UASSERT(0);
break;
}
}