summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2014-12-05 11:24:10 -0600
committerGregory Nutt <gnutt@nuttx.org>2014-12-05 11:24:10 -0600
commit6805d79e0e3b9db70c88d0ccae4d2446159b4009 (patch)
tree502652ad9515bf57be9fe8625b8492db6e6357bb /apps
parent94809c57e5ec9a9441df03014857b737b4b02bda (diff)
downloadnuttx-6805d79e0e3b9db70c88d0ccae4d2446159b4009.tar.gz
nuttx-6805d79e0e3b9db70c88d0ccae4d2446159b4009.tar.bz2
nuttx-6805d79e0e3b9db70c88d0ccae4d2446159b4009.zip
Add second of several ray cast/rendering files
Diffstat (limited to 'apps')
-rw-r--r--apps/graphics/traveler/Makefile2
-rw-r--r--apps/graphics/traveler/include/trv_plane.h16
-rw-r--r--apps/graphics/traveler/include/trv_rayavoid.h12
-rwxr-xr-xapps/graphics/traveler/src/trv_doors.c8
-rwxr-xr-xapps/graphics/traveler/src/trv_rayavoid.c624
5 files changed, 651 insertions, 11 deletions
diff --git a/apps/graphics/traveler/Makefile b/apps/graphics/traveler/Makefile
index c9c4c096e..6e1c49d58 100644
--- a/apps/graphics/traveler/Makefile
+++ b/apps/graphics/traveler/Makefile
@@ -47,7 +47,7 @@ STACKSIZE = 2048
ASRCS =
CSRCS = trv_color.c trv_doors.c trv_graphics.c trv_input.c trv_mem.c trv_pov.c
-CSRCS += trv_rayrend.c trv_trigtbl.c
+CSRCS += trv_rayavoid.c trv_rayrend.c trv_trigtbl.c
MAINSRC = trv_main.c
ifeq ($(CONFIG_NX),y)
diff --git a/apps/graphics/traveler/include/trv_plane.h b/apps/graphics/traveler/include/trv_plane.h
index 60da752d7..b6f718bf9 100644
--- a/apps/graphics/traveler/include/trv_plane.h
+++ b/apps/graphics/traveler/include/trv_plane.h
@@ -119,6 +119,22 @@ struct trv_planefile_header_s
#define SIZEOF_TRVPLANEFILEHEADER_T 6
/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/* The is the world!!! The world is described by lists of rectangles, one
+ * for each of the X, Y, and Z planes.
+ */
+
+extern struct trv_rect_head_s g_xplane; /* list of X=plane rectangles */
+extern struct trv_rect_head_s g_yplane; /* list of Y=plane rectangles */
+extern struct trv_rect_head_s g_zplane; /* list of Z=plane rectangles */
+
+/* "Deallocated" planes are retained in a free list */
+
+extern struct trv_rect_list_s *g_rect_freelist;
+
+/****************************************************************************
* Public Function Prototypes
****************************************************************************/
diff --git a/apps/graphics/traveler/include/trv_rayavoid.h b/apps/graphics/traveler/include/trv_rayavoid.h
index 7993cd111..08214cbc8 100644
--- a/apps/graphics/traveler/include/trv_rayavoid.h
+++ b/apps/graphics/traveler/include/trv_rayavoid.h
@@ -63,11 +63,11 @@ trv_coord_t trv_rayclip_player_ymotion(FAR struct trv_camera_s *pov,
trv_coord_t height);
trv_coord_t trv_ray_adjust_zpos(FAR struct trv_camera_s *pov,
trv_coord_t height);
-FAR struct trv_rect_data_s *trv_test_xplane(FAR struct trv_camera_s *pov,
- trv_coord_t dist, int16_t yaw,
- trv_coord_t height);
-FAR struct trv_rect_data_s *trv_test_yplane(FAR struct trv_camera_s *pov,
- trv_coord_t dist, int16_t yaw,
- trv_coord_t height);
+FAR struct trv_rect_data_s *trv_ray_test_xplane(FAR struct trv_camera_s *pov,
+ trv_coord_t dist, int16_t yaw,
+ trv_coord_t height);
+FAR struct trv_rect_data_s *trv_ray_test_yplane(FAR struct trv_camera_s *pov,
+ trv_coord_t dist, int16_t yaw,
+ trv_coord_t height);
#endif /* __APPS_GRAPHICS_TRAVELER_INCLUDE_TRV_RAYAVOID_H */
diff --git a/apps/graphics/traveler/src/trv_doors.c b/apps/graphics/traveler/src/trv_doors.c
index 7ae726ba7..75a11c538 100755
--- a/apps/graphics/traveler/src/trv_doors.c
+++ b/apps/graphics/traveler/src/trv_doors.c
@@ -124,8 +124,8 @@ static void trv_door_startopen (void)
/* Test if there is a door within three steps in front of the player */
/* Try the X planes first */
- rect = trv_test_xplane(&g_trv_player, 3*STEP_DISTANCE,
- g_trv_player.yaw, g_player_height);
+ rect = trv_ray_test_xplane(&g_trv_player, 3*STEP_DISTANCE,
+ g_trv_player.yaw, g_player_height);
/* If there is no X door in front of the player, then try the Y Planes
* (it is assumed that there would not be doors this close in both
@@ -134,8 +134,8 @@ static void trv_door_startopen (void)
if (!rect || !IS_DOOR(rect))
{
- rect = trv_test_yplane(&g_trv_player, 3*STEP_DISTANCE,
- g_trv_player.yaw, g_player_height);
+ rect = trv_ray_test_yplane(&g_trv_player, 3*STEP_DISTANCE,
+ g_trv_player.yaw, g_player_height);
}
/* Check if we found a door in either the X or Y plane. */
diff --git a/apps/graphics/traveler/src/trv_rayavoid.c b/apps/graphics/traveler/src/trv_rayavoid.c
new file mode 100755
index 000000000..6fc04ddf2
--- /dev/null
+++ b/apps/graphics/traveler/src/trv_rayavoid.c
@@ -0,0 +1,624 @@
+/*******************************************************************************
+ * apps/graphics/traveler/src/trv_rayavoid.c
+ * This file contains the logic which determines if the desired player motion
+ * would cause a collision with various walls or if the motion would cause
+ * the player to change his vertical position in the world. This collision
+ * avoidance logic is also used to determine if there is a door in front of
+ * the player.
+ *
+ * Copyright (C) 2014 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/*****************************************************************************
+ * Included files
+ ****************************************************************************/
+
+#include "trv_types.h"
+#include "trv_trigtbl.h"
+#include "trv_plane.h"
+#include "trv_world.h"
+#include "trv_rayavoid.h"
+
+/*****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* This is the closest that we will allow the player to approach a wall */
+
+#define MIN_APPROACH_DISTANCE (64/4) /* One quarter cell */
+
+/*****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* The rayClipPlayX/YMotion functions have the side effect of saving the
+ * pointer to the wall with which the player collided in the following
+ * private variable. This gives a "back door" mechanism which is used
+ * to handle door processing.
+ */
+
+static struct trv_rect_data_s *g_clip_rect;
+
+/*****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/*****************************************************************************
+ * Name: trv_ray_test_xplane
+ *
+ * Description:
+ *
+ * This function tests if there is an X plane within the supplied distance
+ * from the player at the supplied angle. This function is used to
+ * determine in there is a door in front of the player. NOTE: This
+ * function exploits the normal collision detection logic in
+ * trv_rayclip_player_xmotion and depends on the side-effect setting of
+ * g_clip_rect.
+ *
+ *****************************************************************************/
+
+FAR struct trv_rect_data_s *trv_ray_test_xplane(FAR struct trv_camera_s *pov,
+ trv_coord_t dist, int16_t yaw,
+ trv_coord_t height)
+{
+ (void) trv_rayclip_player_xmotion(pov, dist, yaw, height);
+ return g_clip_rect;
+}
+
+/*****************************************************************************
+ * Name: trv_rayclip_player_xmotion
+ *
+ * Description:
+ * This function calculates the acceptable change in the player's position
+ * along the X component of the specified yaw angle which would not cause
+ * a collision with an X plane. This logic is essentially a modified X
+ * ray cast.
+ *
+ *****************************************************************************/
+
+trv_coord_t trv_rayclip_player_xmotion(FAR struct trv_camera_s *pov,
+ trv_coord_t dist, int16_t yaw,
+ trv_coord_t height)
+{
+ FAR struct trv_rect_list_s *list; /* Points to the current X plane rectangle */
+ FAR struct trv_rect_data_s *rect; /* Points to the rectangle data */
+ trv_coord_t reqdeltax;
+ trv_coord_t standoff;
+ trv_coord_t footlevel;
+ trv_coord_t relx; /* Relative position of the X plane */
+ trv_coord_t absy; /* Absolute Y position at relx given yaw */
+ trv_coord_t lastrelx = -1; /* Last relative X position processed */
+
+ /* Decompose the desired move distance into its X component */
+
+ reqdeltax = tTOs(g_cos_table[ yaw ] * dist);
+
+ /* Assume that no clipping will be performed */
+
+ g_clip_rect = NULL;
+
+ /* Perform X raycasting based on the quadrant of the yaw angle */
+ /* The first and fourth quadrants correspond to the positive X
+ * direction (excluding angles 90 and 270).
+ */
+
+ if (yaw < ANGLE_90 || yaw > ANGLE_270)
+ {
+ /* Calculate the requested distance along the (positive) X axis (adding
+ * a little to how close the play can come to a wall
+ */
+
+ standoff = reqdeltax + MIN_APPROACH_DISTANCE;
+
+ /* This is the position of the player's feet */
+
+ footlevel = pov->z - height;
+
+ /* Look at every rectangle lying in the X plane */
+
+ for (list = g_xplane.head; list; list = list->flink)
+ {
+ rect = &list->d;
+
+ /* Search for a rectangle which lies "beyond" the current camera
+ * position
+ */
+
+ if (rect->plane > pov->x)
+ {
+ /* Get the X distance to the plane. This is an order list: if
+ * the distance to the plane is larger then the requested step
+ * then the requested step is acceptable.
+ */
+
+ relx = rect->plane - pov->x;
+ if (relx >= standoff)
+ {
+ return reqdeltax;
+ }
+
+ /* The distance to the plane is smaller that the requested step.
+ * It may be possible to collide with the plane. Check if a
+ * collision due to the height of the player is possible first
+ * (its easier to compute)
+ */
+
+ if (footlevel >= rect->vstart && pov->z <= rect->vend)
+ {
+ /* A collision is possible based on the players height.
+ * Now, we'll have to check if a collision is possible
+ * due to the player's Y position. We can skip this
+ * step if we are processing another rectangle at the
+ * same relx distance.
+ */
+
+ if (relx != lastrelx)
+ {
+ int32_t deltay; /* Scale == "triple" */
+
+ /* The tangent is equal to the rate of change of Y with
+ * respect to the X-axis. The tangent is stored at
+ * double the the "normal" scaling -- so deltay is
+ * "triple" precision
+ */
+
+ deltay = TAN(yaw) * ((int32_t)relx);
+ absy = tTOs(deltay) + pov->y; /* back to "single" */
+ lastrelx = relx;
+ }
+
+ /* Check if this Y position intersects the rectangle */
+
+ if (absy >= rect->hstart && absy <= rect->hend)
+ {
+ /* It collides -- Check, maybe we can walk through
+ * this wall
+ */
+
+ if (!IS_PASSABLE(rect))
+ {
+ /* Nope... return a clipped value for the new
+ * player position (which includes the a stand-off
+ * constant)
+ * NOTE: This returned value could be negative!
+ */
+
+ g_clip_rect = rect;
+ return relx - MIN_APPROACH_DISTANCE;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* The second and third quadrants correspond to the negative X
+ * direction (excluding angles 90 and 270).
+ */
+
+ else if (yaw > ANGLE_90 && yaw < ANGLE_270)
+ {
+ /* Calculate the requested distance along the (negative) X axis
+ * (adding a little to how close the play can come to a wall)
+ */
+
+ standoff = MIN_APPROACH_DISTANCE - reqdeltax;
+
+ /* This is the position of the player's feet */
+
+ footlevel = pov->z - height;
+
+ /* Look at every rectangle lying in the X plane */
+
+ for (list = g_xplane.tail; list; list = list->blink)
+ {
+ rect = &list->d;
+
+ /* Search for a rectangle which lies "before" the current camera
+ * position
+ */
+
+ if (rect->plane < pov->x)
+ {
+ /* Get the X distance to the plane. This is an order list:
+ * if the distance to the plane is larger then the requested
+ * step then the requested step is acceptable.
+ */
+
+ relx = pov->x - rect->plane;
+ if (relx >= standoff)
+ {
+ return reqdeltax;
+ }
+
+ /* The distance to the plane is smaller that the requested
+ * step. It may be possible to collide with the plane. Check
+ * if a collision due to the height of the player is possible
+ * first (its easier to compute)
+ */
+
+ if (footlevel >= rect->vstart && pov->z <= rect->vend)
+ {
+ /* A collision is possible based on the players height.
+ * Now, we'll have to check if a collision is possible due
+ * to the player's Y position. We can skip this step if
+ * we are processing another rectangle at the same relx
+ * distance.
+ */
+
+ if (relx != lastrelx)
+ {
+ int32_t deltay; /* Scale == "triple" */
+
+ /* The negative tangent is equal to the rate of change
+ * of Y with respect to the X-axis.The tangent is
+ * stored at double the the "normal" scaling -- so
+ * deltay is "triple" precision
+ */
+
+ deltay = -TAN(yaw) * ((int32_t)relx);
+ absy = tTOs(deltay) + pov->y; /* back to "single" */
+ lastrelx = relx;
+ }
+
+ /* Check if this Y position intersects the rectangle */
+
+ if (absy >= rect->hstart && absy <= rect->hend)
+ {
+ /* It collides -- Check, maybe we can walk through
+ * this wall?
+ */
+
+ if (!IS_PASSABLE(rect))
+ {
+ /* Nope -- return a clipped value for the new
+ * player position (which includes the a stand-off
+ * constant)
+ * NOTE: This returned value could be positive!
+ */
+
+ g_clip_rect = rect;
+ return MIN_APPROACH_DISTANCE - relx;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* If we got there, then no collisions were found. Just return the
+ * requested step value
+ */
+
+ return reqdeltax;
+}
+
+/*****************************************************************************
+ * Name: trv_ray_test_yplane
+ *
+ * Description:
+ * This function tests if there is an Y plane within the supplied distance
+ * from the player at the supplied angle. This function is used to
+ * determine in there is a door in front of the player. NOTE: This
+ * function exploits the normal collision detection logic in
+ * trv_rayclip_player_ymotion and depends on the side-effect setting of
+ * g_clip_rect.
+ *
+ ****************************************************************************/
+
+FAR struct trv_rect_data_s *trv_ray_test_yplane(FAR struct trv_camera_s *pov,
+ trv_coord_t dist, int16_t yaw,
+ trv_coord_t height)
+{
+ (void)trv_rayclip_player_ymotion(pov, dist, yaw, height);
+ return g_clip_rect;
+}
+
+/*****************************************************************************
+ * Name: trv_rayclip_player_ymotion
+ *
+ * Description:
+ * This function calculates the acceptable change in the player's position
+ * along the Y component of the specified yaw angle which would not cause
+ * a collision with a Y plane. This logic is essentially a modified X
+ * ray cast.
+ *
+ ****************************************************************************/
+
+trv_coord_t trv_rayclip_player_ymotion(FAR struct trv_camera_s *pov,
+ trv_coord_t dist, int16_t yaw,
+ trv_coord_t height)
+{
+ FAR struct trv_rect_list_s *list; /* Points to the current Y plane rectangle */
+ FAR struct trv_rect_data_s *rect; /* Points to the rectangle data */
+ trv_coord_t reqdeltay;
+ trv_coord_t standoff;
+ trv_coord_t footlevel;
+ trv_coord_t rely; /* Relative position of the Y plane */
+ trv_coord_t absx; /* Absolute X position at rely given yaw */
+ trv_coord_t lastrely = -1; /* Last relative Y position processed */
+
+ /* Decompose the desired move distance into its Y component */
+
+ reqdeltay = tTOs(g_sin_table[ yaw ] * dist);
+
+ /* Assume that no clipping will be performed */
+
+ g_clip_rect = NULL;
+
+ /* Perform Y raycasting based on the quadrant of the yaw angle */
+ /* The first and second quadrants correspond to the positive Y
+ * direction (excluding angles 0 and 180).
+ */
+
+ if (yaw > ANGLE_0 && yaw < ANGLE_180)
+ {
+ /* Calculate the requested distance along the (positive) X axis
+ * (adding a little to how close the play can come to a wall)
+ */
+
+ standoff = reqdeltay + MIN_APPROACH_DISTANCE;
+
+ /* This is the position of the player's feet */
+
+ footlevel = pov->z - height;
+
+ /* Look at every rectangle lying in a Y plane */
+
+ for (list = g_yplane.head; list; list = list->flink)
+ {
+ rect = &list->d;
+
+ /* Search for a rectangle which lies "beyond" the current camera
+ * position
+ */
+
+ if (rect->plane > pov->y)
+ {
+ /* Get the Y distance to the plane. This is an order list:
+ * If the distance to the plane is larger then the requested
+ * step then the requested step is acceptable.
+ */
+
+ rely = rect->plane - pov->y;
+ if (rely >= standoff)
+ {
+ return reqdeltay;
+ }
+
+ /* The distance to the plane is smaller that the requested
+ * step. It may be possible to collide with the plane.
+ * Check if a collision due to the height of the player is
+ * possible first (its easier to compute)
+ */
+
+ if (footlevel >= rect->vstart && pov->z <= rect->vend)
+ {
+ /* A collision is possible based on the players height.
+ * Now, we'll have to check if a collision is possible
+ * due to the player's X position. We can skip this
+ * step if we are processing another rectangle at the
+ * same relx distance.
+ */
+
+ if (rely != lastrely)
+ {
+ int32_t deltax; /* Scale == "triple" */
+
+ /* The inverted tangent is equal to the rate of change
+ * of X with respect to the Y-axis. The cotangent is
+ * stored at double the the "normal" scaling -- so
+ * deltax is "triple" precision
+ */
+
+ deltax = g_cot_table(yaw) * ((int32_t)rely);
+ absx = tTOs(deltax) + pov->x; /* back to "single" */
+ lastrely = rely;
+ }
+
+ /* Check if this X position intersects the rectangle */
+
+ if (absx >= rect->hstart && absx <= rect->hend)
+ {
+ /* It collides -- Check, maybe we can walk through
+ * this wall?
+ */
+
+ if (!IS_PASSABLE(rect))
+ {
+ /* Nope -- return a clipped value for the new
+ * player position (which includes the a stand-off
+ * constant)
+ * NOTE: This returned value could be negative!
+ */
+
+ g_clip_rect = rect;
+ return rely - MIN_APPROACH_DISTANCE;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* The third and fourth quadrants correspond to the negative Y
+ * direction (excluding angles 0 and 180).
+ */
+
+ else if (yaw > ANGLE_180)
+ {
+ /* Calculate the requested distance along the (negative) X axis
+ * (adding a little to how close the play can come to a wall)
+ */
+
+ standoff = MIN_APPROACH_DISTANCE - reqdeltay;
+
+ /* This is the position of the player's feet */
+
+ footlevel = pov->z - height;
+
+ /* Look at every rectangle lying in the X plane */
+
+ for (list = g_yplane.tail; list; list = list->blink)
+ {
+ rect = &list->d;
+
+ /* Search for a rectangle which lies "before" the current camera
+ * position
+ */
+
+ if (rect->plane < pov->y)
+ {
+ /* Get the X distance to the plane. This is an order list: if
+ * the distance to the plane is larger then the requested step
+ * then the requested step is acceptable.
+ */
+
+ rely = pov->y - rect->plane;
+ if (rely >= standoff)
+ {
+ return reqdeltay;
+ }
+
+ /* The distance to the plane is smaller that the requested
+ * step. It may be possible to collide with the plane. Check
+ * if a collision due to the height of the player is possible
+ * first (its easier to compute)
+ */
+
+ if (footlevel >= rect->vstart && pov->z <= rect->vend)
+ {
+ /* A collision is possible based on the players height.
+ * Now, we'll have to check if a collision is possible due
+ * to the player's X position. We can skip this step if
+ * we are processing another rectangle at the same relx
+ * distance.
+ */
+
+ if (rely != lastrely)
+ {
+ int32_t deltax; /* Scale == "triple" */
+
+ /* The negative inverted tangent is equal to the rate
+ * of change of X with respect to the Y-axis. The
+ * cotangent is stored at double the the "normal"
+ * scaling -- so deltax is "triple" precision
+ */
+
+ deltax = -g_cot_table(yaw - ANGLE_180) * ((int32_t)rely);
+ absx = tTOs(deltax) + pov->x; /* back to "single" */
+ lastrely = rely;
+ }
+
+ /* Check if this X position intersects the rectangle */
+
+ if (absx >= rect->hstart && absx <= rect->hend)
+ {
+ /* It collides -- Check, maybe we can walk through
+ * this wall
+ */
+
+ if (!IS_PASSABLE(rect))
+ {
+ /* It collides -- return a clipped value for the
+ * new player position (which includes the a
+ * stand-off constant)
+ * NOTE: This returned value could be positive!
+ */
+
+ g_clip_rect = rect;
+ return MIN_APPROACH_DISTANCE - rely;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Return the clipped value */
+
+ return reqdeltay;
+}
+
+/*****************************************************************************
+ * Name: trv_ray_adjust_zpos
+ *
+ * Description:
+ * Make sure that the player is standing on something!
+ *
+ ****************************************************************************/
+
+trv_coord_t trv_ray_adjust_zpos(FAR struct trv_camera_s *pov,
+ trv_coord_t height)
+{
+ struct trv_rect_list_s *list; /* Points to the current Z plane rectangle */
+ struct trv_rect_data_s *rect; /* Points to the rectangle data */
+
+ /* We will place the player's feet at the largest Z plane
+ * which is lower the the player's eye level. We traverse
+ * the the g_zplane list in order of increase Z values
+ */
+
+ for (list = g_zplane.head; list; list = list->flink)
+ {
+ rect = &list->d;
+
+ /* The Z plane list is an ordered list. If the next
+ * plane is over the player's head, then the player
+ * must be standing at "ground zero."
+ */
+
+ if (rect->plane >= pov->z)
+ {
+ return height - pov->z;
+ }
+
+ /* Check if this plane if under the player */
+
+ if (pov->x >= rect->hstart && pov->x <= rect->hend &&
+ pov->y >= rect->vstart && pov->y <= rect->vend)
+ {
+ /* We have the the smallest Z plane under the player
+ * which is below the player's eye level (pov->z).
+ * Determine the approach delta Z value to return
+ */
+
+ return height + rect->plane - pov->z;
+ }
+ }
+
+ /* No plane was found under the player. Set him at his
+ * height above the "bottom" of the world
+ */
+
+ return height - pov->z;
+}