aboutsummaryrefslogtreecommitdiff
path: root/src/libparsec/utl_cull.cpp
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@gmail.com>2026-08-24 11:16:07 +0200
committerFelix Morgner <felix.morgner@gmail.com>2026-08-24 11:16:07 +0200
commitc068f22329d5cc722622a2183bbb22eef2093df7 (patch)
tree12d56c1aede67988a55e241364606bfbb4dba933 /src/libparsec/utl_cull.cpp
downloadopenparsec-main.tar.xz
openparsec-main.zip
initial importHEADmain
Diffstat (limited to 'src/libparsec/utl_cull.cpp')
-rw-r--r--src/libparsec/utl_cull.cpp278
1 files changed, 278 insertions, 0 deletions
diff --git a/src/libparsec/utl_cull.cpp b/src/libparsec/utl_cull.cpp
new file mode 100644
index 0000000..893d82f
--- /dev/null
+++ b/src/libparsec/utl_cull.cpp
@@ -0,0 +1,278 @@
+/*
+ * PARSEC - Culling Code
+ *
+ * $Author: uberlinuxguy $ - $Date: 2004/09/15 12:25:43 $
+ *
+ * Orginally written by:
+ * Copyright (c) Markus Hadwiger <msh@parsec.org> 1998
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+// C library
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+// compilation flags/debug support
+#include "config.h"
+#include "debug.h"
+
+// general definitions
+#include "general.h"
+#include "objstruc.h"
+
+// global externals
+#include "globals.h"
+
+// mathematics header
+#include "utl_math.h"
+
+// model header
+#include "utl_model.h"
+
+// local module header
+#include "utl_cull.h"
+
+
+
+// determine indexes of reject and accept points with respect to a plane ------
+//
+void CULL_ReAcIndexBox3( ReAcIndexBox3 *reac, Plane3 *plane )
+{
+ ASSERT( reac != NULL );
+ ASSERT( plane != NULL );
+
+ //NOTE:
+ // reac->reject will be the point with the
+ // greatest signed distance to the plane.
+ // reac->accept will be the point with the
+ // least signed distance to the plane.
+
+ if ( GEOMV_NEGATIVE( plane->X ) ) {
+ reac->reject[ 0 ] = 0;
+ reac->accept[ 0 ] = 3;
+ } else {
+ reac->reject[ 0 ] = 3;
+ reac->accept[ 0 ] = 0;
+ }
+
+ if ( GEOMV_NEGATIVE( plane->Y ) ) {
+ reac->reject[ 1 ] = 1;
+ reac->accept[ 1 ] = 4;
+ } else {
+ reac->reject[ 1 ] = 4;
+ reac->accept[ 1 ] = 1;
+ }
+
+ if ( GEOMV_NEGATIVE( plane->Z ) ) {
+ reac->reject[ 2 ] = 2;
+ reac->accept[ 2 ] = 5;
+ } else {
+ reac->reject[ 2 ] = 5;
+ reac->accept[ 2 ] = 2;
+ }
+}
+
+
+// determine coordinates of reject and accept points with respect to a plane --
+//
+void CULL_ReAcPointBox3( ReAcPointBox3 *reac, CullBox3 *cullbox, Plane3 *plane )
+{
+ ASSERT( reac != NULL );
+ ASSERT( cullbox != NULL );
+ ASSERT( plane != NULL );
+
+ //NOTE:
+ // reac->reject will be the point with the
+ // greatest signed distance to the plane.
+ // reac->accept will be the point with the
+ // least signed distance to the plane.
+
+ if ( GEOMV_NEGATIVE( plane->X ) ) {
+ reac->reject.X = cullbox->minmax[ 0 ];
+ reac->accept.X = cullbox->minmax[ 3 ];
+ } else {
+ reac->reject.X = cullbox->minmax[ 3 ];
+ reac->accept.X = cullbox->minmax[ 0 ];
+ }
+
+ if ( GEOMV_NEGATIVE( plane->Y ) ) {
+ reac->reject.Y = cullbox->minmax[ 1 ];
+ reac->accept.Y = cullbox->minmax[ 4 ];
+ } else {
+ reac->reject.Y = cullbox->minmax[ 4 ];
+ reac->accept.Y = cullbox->minmax[ 1 ];
+ }
+
+ if ( GEOMV_NEGATIVE( plane->Z ) ) {
+ reac->reject.Z = cullbox->minmax[ 2 ];
+ reac->accept.Z = cullbox->minmax[ 5 ];
+ } else {
+ reac->reject.Z = cullbox->minmax[ 5 ];
+ reac->accept.Z = cullbox->minmax[ 2 ];
+ }
+}
+
+
+// augment set of planes by reject/accept points for culling ------------------
+//
+void CULL_MakeVolumeCullVolume( Plane3 *volume, CullPlane3 *cullvolume, dword cullmask )
+{
+ ASSERT( volume != NULL );
+ ASSERT( cullvolume != NULL );
+
+ for ( ; cullmask != 0x00; cullmask >>= 1, volume++, cullvolume++ ) {
+
+ if ( cullmask & 0x01 ) {
+
+ // copy plane
+ cullvolume->plane = *volume;
+
+ // calc reac indexes
+ CULL_ReAcIndexBox3( &cullvolume->reacx, &cullvolume->plane );
+ }
+ }
+}
+
+
+// cull an axial bounding box against a cull volume (set of cull planes) ------
+//
+int CULL_BoxAgainstCullVolume( CullBox3 *cullbox, CullPlane3 *volume, dword *cullmask )
+{
+ //NOTE:
+ // this function returns:
+ // - TRUE if the box is trivial reject
+ // - FALSE if the box is not trivial reject
+ // - if ( *cullmask == 0x00 ) afterwards the box is trivial accept
+ // - if ( *cullmask != 0x00 ) afterwards the box needs to be clipped
+
+ ASSERT( cullbox != NULL );
+ ASSERT( volume != NULL );
+ ASSERT( cullmask != NULL );
+
+ dword curmask = *cullmask;
+ CullPlane3* cullplane = volume;
+
+ for ( int curplane = 0; curmask != 0x00; curmask >>= 1, curplane++ ) {
+
+ if ( curmask & 0x01 ) {
+
+ // one plane rejects: whole status is trivial reject
+ geomv_t dist = PLANEDIST_REJECTPOINT( cullplane, cullbox );
+ if ( GEOMV_NEGATIVE( dist ) ) {
+ return TRUE;
+ }
+
+ // mask plane if trivial accept
+ dist = PLANEDIST_ACCEPTPOINT( cullplane, cullbox );
+ if ( GEOMV_POSITIVE( dist ) ) {
+ *cullmask &= ~( 1 << curplane );
+ }
+ }
+
+ // sizeof( CullPlane3 ) is no power of two
+ cullplane = (CullPlane3 *)( (char *)cullplane + sizeof( cullplane[ 0 ] ) );
+ }
+
+ return FALSE;
+}
+
+
+// cull an axial bounding box against a volume (set of planes) ----------------
+//
+int CULL_BoxAgainstVolume( CullBox3 *cullbox, Plane3 *volume, dword *cullmask )
+{
+ //NOTE:
+ // this function returns:
+ // - TRUE if the box is trivial reject
+ // - FALSE if the box is not trivial reject
+ // - if ( *cullmask == 0x00 ) afterwards the box is trivial accept
+ // - if ( *cullmask != 0x00 ) afterwards the box needs to be clipped
+
+ ASSERT( cullbox != NULL );
+ ASSERT( volume != NULL );
+ ASSERT( cullmask != NULL );
+
+ dword curmask = *cullmask;
+
+ for ( int curplane = 0; curmask != 0x00; curmask >>= 1, curplane++ ) {
+
+ if ( curmask & 0x01 ) {
+
+ Plane3 *plane = &volume[ curplane ];
+
+ // determine reject/accept points
+ ReAcPointBox3 reac;
+ CULL_ReAcPointBox3( &reac, cullbox, plane );
+
+ // one plane rejects: whole status is trivial reject
+ if ( PLANE_DOT( plane, &reac.reject ) <= PLANE_OFFSET( plane ) ) {
+ return TRUE;
+ }
+
+ // mask plane if trivial accept
+ if ( PLANE_DOT( plane, &reac.accept ) >= PLANE_OFFSET( plane ) ) {
+ *cullmask &= ~( 1 << curplane );
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+
+// cull a bounding sphere against a volume (set of planes) --------------------
+//
+int CULL_SphereAgainstVolume( Sphere3 *sphere, Plane3 *volume, dword *cullmask )
+{
+ //NOTE:
+ // this function returns:
+ // - TRUE if the sphere is trivial reject
+ // - FALSE if the sphere is not trivial reject
+ // - if ( *cullmask == 0x00 ) afterwards the sphere is trivial accept
+ // - if ( *cullmask != 0x00 ) afterwards the sphere needs to be clipped
+
+ ASSERT( sphere != NULL );
+ ASSERT( volume != NULL );
+ ASSERT( cullmask != NULL );
+
+ dword curmask = *cullmask;
+
+ for ( int curplane = 0; curmask != 0x00; curmask >>= 1, curplane++ ) {
+
+ if ( curmask & 0x01 ) {
+
+ Plane3 *plane = &volume[ curplane ];
+ geomv_t dist = PLANE_DOT( plane, sphere ) - PLANE_OFFSET( plane );
+
+ // one plane rejects: whole status is trivial reject
+ if ( dist < -sphere->R ) {
+ return TRUE;
+ }
+
+ // mask plane if trivial accept
+ if ( dist > sphere->R ) {
+ *cullmask &= ~( 1 << curplane );
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+
+