summaryrefslogtreecommitdiff
path: root/apps/graphics/traveler/src/trv_rayrend.c
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2014-12-05 08:44:55 -0600
committerGregory Nutt <gnutt@nuttx.org>2014-12-05 08:44:55 -0600
commitd2b407f9f9272b8f7dbc97c494d11f2468157363 (patch)
treeba1c4b3164a826bb440266d48b82031b9c0f4d5c /apps/graphics/traveler/src/trv_rayrend.c
parent86e5c3a5b0792e9234f98e4aeb1c0721b56352b2 (diff)
downloadnuttx-d2b407f9f9272b8f7dbc97c494d11f2468157363.tar.gz
nuttx-d2b407f9f9272b8f7dbc97c494d11f2468157363.tar.bz2
nuttx-d2b407f9f9272b8f7dbc97c494d11f2468157363.zip
Add first of several ray cast/rendering files
Diffstat (limited to 'apps/graphics/traveler/src/trv_rayrend.c')
-rwxr-xr-xapps/graphics/traveler/src/trv_rayrend.c1337
1 files changed, 1337 insertions, 0 deletions
diff --git a/apps/graphics/traveler/src/trv_rayrend.c b/apps/graphics/traveler/src/trv_rayrend.c
new file mode 100755
index 000000000..f9c45c3ad
--- /dev/null
+++ b/apps/graphics/traveler/src/trv_rayrend.c
@@ -0,0 +1,1337 @@
+/*****************************************************************************
+ * apps/graphics/traveler/src/trv_rayrend.c
+ * This file contains the functions needed to render a screen.
+ *
+ * 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_debug.h"
+#include "trv_world.h"
+#include "trv_plane.h"
+#include "trv_bitmaps.h"
+#include "trv_graphics.h"
+#include "trv_paltable.h"
+#include "trv_trigtbl.h"
+#include "trv_raycntl.h"
+#include "trv_raycast.h"
+#include "trv_rayrend.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+/* These are sometimes useful during debug */
+
+#define DISABLE_WALL_RENDING 0
+#define DISABLE_FLOOR_RENDING 0
+
+/* The following macros perform division (using g_invsize[]) and then a
+ * rescaling by the approprate constants so that the texture index is
+ * byte aligned
+ */
+
+#define TDIV(num,den,s) (((num) * g_invsize[den]) >> (s))
+
+/* This macro just performs the division and leaves the result with eight
+ * (more) bits of fraction
+ */
+
+#define DIV8(num,den) ((num) * g_invsize[den])
+
+/* The following macro aligns a SMALL precision number to that the texture
+ * index is byte aligned
+ */
+
+#define TALIGN(x,s) ((x) << (8-(s)))
+
+/****************************************************************************
+ * Private Type Declarations
+ ****************************************************************************/
+
+/* This union is used to manage texture indices */
+
+union tex_ndx_u
+{
+ struct
+ {
+ uint8_t f;
+ uint8_t i;
+ } s;
+ int16_t w;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void trv_rend_zcell(uint8_t row, uint8_t col, uint8_t height,
+ uint8_t width);
+static void trv_rend_zrow(uint8_t row, uint8_t col, uint8_t width);
+static void trv_rend_zcol(uint8_t row, uint8_t col, uint8_t height);
+static void trv_rend_zpixel(uint8_t row, uint8_t col);
+
+static void trv_rend_wall(uint8_t row, uint8_t col, uint8_t height,
+ uint8_t width);
+static void trv_rend_wallrow(uint8_t row, uint8_t col, uint8_t width);
+static void trv_rend_wallcol(uint8_t row, uint8_t col, uint8_t height);
+static void trv_rend_wallpixel(uint8_t row, uint8_t col);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* The following array simply contains the inverted values of the integers
+ * from 0...VGULP_SIZE-1. The values in the table have 8 bits of fraction.
+ * The value for 0 is bogus!
+ */
+
+static const uint8_t g_invsize[VGULP_SIZE] =
+{
+ 0xff, 0xff, 0x80, 0x55, 0x40, 0x33, 0x2b, 0x25, /* 0..7 */
+ 0x20, 0x1c, 0x1a, 0x17, 0x15, 0x14, 0x12, 0x11 /* 8..15 */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: trv_rend_zcell, trv_rend_zrow, trv_rend_zcol, trv_rend_zpixel
+ *
+ * Description:
+ * After matching hits have been obtained in all four corners of a cell,
+ * this function interpolates to complete the cell then transfers the cell
+ * to the double buffer. These are the general cases where no assumptions
+ * are made concerning the relative orientation of the cell and the texture.
+ * This general case is only used to texture floors and ceilings.
+ *
+ ****************************************************************************/
+
+/* This version is for non-degenerate cell, i.e., height>1 and width>1 */
+
+static void trv_rend_zcell(uint8_t row, uint8_t col, uint8_t height, uint8_t width)
+{
+#if (!DISABLE_FLOOR_RENDING)
+ uint8_t i;
+ uint8_t j;
+ uint8_t endrow;
+ uint8_t endcol;
+ FAR uint8_t *palptr;
+ FAR uint8_t *outpixel;
+ uint8_t scale;
+ FAR trv_pixel_t *texture;
+ FAR struct trv_bitmap_s *bmp;
+ union tex_ndx_u xpos;
+ union tex_ndx_u ypos;
+ uint16_t tmask;
+ uint16_t tsize;
+ int16_t zone;
+ int16_t endzone;
+ int16_t zonestep;
+ int16_t hstart;
+ int16_t hrowstep;
+ int16_t hcolstep;
+ int16_t hstepincr;
+ int16_t vstart;
+ int16_t vrowstep;
+ int16_t vcolstep;
+ int16_t vstepincr;
+ int16_t tmpcolstep;
+
+ /* Displace the double buffer pointer */
+
+ outpixel = &g_buffer_row[row][g_cell_column];
+
+ /* Point to the bitmap associated with the upper left pixel. Since
+ * all of the pixels in this cell are the same "hit," we don't have
+ * to recalculate this
+ */
+
+ if (IS_FRONT_HIT(&g_ray_hit[row][col]))
+ {
+ bmp = g_even_bitmaps[g_ray_hit[row][col].rect->texture];
+ }
+ else
+ {
+ bmp = g_odd_bitmaps[g_ray_hit[row][col].rect->texture];
+ }
+
+ /* Get parameters associated with the size of the bitmap texture */
+
+ texture = bmp->bm;
+ tsize = bmp->log2h;
+ tmask = TMASK(tsize);
+
+ /* Extract the texture scaling from the rectangle structure */
+
+ scale = g_ray_hit[row][col].rect->scale;
+
+ /* Within this function, all references to height and width are really
+ * (height-1) and (width-1)
+ */
+
+ height--;
+ width--;
+
+ /* Get the indices to the lower, right corner */
+
+ endcol = col + width;
+ endrow = row + height;
+
+ /* Calculate the horizontal interpolation values */
+ /* This is the H starting position (first row, first column) */
+
+ hstart = TALIGN(g_ray_hit[row][col].xpos, scale);
+
+ /* This is the change in xpos per column in the first row */
+
+ hcolstep =
+ TDIV((g_ray_hit[row][endcol].xpos - g_ray_hit[row][col].xpos),
+ width, scale);
+
+ /* This is the change in xpos per column in the last row */
+
+ tmpcolstep =
+ TDIV((g_ray_hit[endrow][endcol].xpos - g_ray_hit[endrow][col].xpos),
+ width, scale);
+
+ /* This is the change in hcolstep per row */
+
+ hstepincr = (TDIV((tmpcolstep - hcolstep), height, scale) >> 8);
+
+ /* This is the change in hstart for each row */
+
+ hrowstep =
+ TDIV((g_ray_hit[endrow][col].xpos - g_ray_hit[row][col].xpos),
+ height, scale);
+
+ /* Calculate the vertical interpolation values */
+ /* This is the V starting position (first row, first column) */
+
+ vstart = TALIGN(g_ray_hit[row][col].ypos, scale);
+
+ /* This is the change in ypos per column in the first row */
+
+ vcolstep =
+ TDIV((g_ray_hit[row][endcol].ypos - g_ray_hit[row][col].ypos),
+ width, scale);
+
+ /* This is the change in ypos per column in the last row */
+
+ tmpcolstep =
+ TDIV((g_ray_hit[endrow][endcol].ypos - g_ray_hit[endrow][col].ypos),
+ width, scale);
+
+ /* This is the change in vcolstep per row */
+
+ vstepincr = (TDIV((tmpcolstep - vcolstep), height, scale) >> 8);
+
+ /* This is the change in vstart for each row */
+
+ vrowstep =
+ TDIV((g_ray_hit[endrow][col].ypos - g_ray_hit[row][col].ypos),
+ height, scale);
+
+ /* Determine the palette mapping table zone for each row */
+
+ if (IS_SHADED(g_ray_hit[row][col].rect))
+ {
+ zone = GET_FZONE(g_ray_hit[row][col].xdist, g_ray_hit[row][col].ydist, 8);
+ endzone = GET_FZONE(g_ray_hit[endrow][col].xdist, g_ray_hit[endrow][col].ydist, 8);
+ zonestep = (DIV8((endzone - zone), height) >> 8);
+ }
+ else
+ {
+ zone = 0;
+ zonestep = 0;
+ }
+
+ /* Now, interpolate to texture each row (vertical component) */
+
+ for (i = row; i <= endrow; i++)
+ {
+ /* Set the initial horizontal & vertical offset */
+
+ xpos.w = hstart;
+ ypos.w = vstart;
+
+ /* Get the palette map to use on this row */
+
+ palptr = GET_PALPTR((zone >> 8));
+
+ /* Interpolate to texture each column in the row */
+
+ for (j = col; j <= endcol; j++)
+ {
+ /* Transfer the pixel at this interpolated position */
+
+ outpixel[j] = palptr[texture[TNDX(xpos.s.i, ypos.s.i, tsize, tmask)]];
+
+ /* Now Calculate the horizontal position for the next step */
+
+ xpos.w += hcolstep;
+ ypos.w += vcolstep;
+ }
+
+ /* Point to the next row */
+
+ outpixel += TRV_SCREEN_WIDTH;
+
+ /* Calculate the vertical position for the next step */
+
+ hstart += hrowstep;
+ vstart += vrowstep;
+
+ /* Adjust the step sizes to use on the next row */
+
+ hcolstep += hstepincr;
+ vcolstep += vstepincr;
+
+ /* Get the zone to use on the next row */
+
+ zone += zonestep;
+ }
+#endif
+}
+
+/* This version is for horizontal lines, i.e., height==1 and width>1 */
+
+static void trv_rend_zrow(uint8_t row, uint8_t col, uint8_t width)
+{
+#if (!DISABLE_FLOOR_RENDING)
+ uint8_t j;
+ uint8_t endcol;
+ FAR uint8_t *palptr;
+ FAR uint8_t *outpixel;
+ uint8_t scale;
+ FAR trv_pixel_t *texture;
+ FAR struct trv_bitmap_s *bmp;
+ union tex_ndx_u xpos;
+ union tex_ndx_u ypos;
+ uint16_t tmask;
+ uint16_t tsize;
+ int16_t zone;
+ int16_t hcolstep;
+ int16_t vcolstep;
+
+ /* Displace the double buffer pointer */
+
+ outpixel = &g_buffer_row[row][g_cell_column];
+
+ /* Point to the bitmap associated with the left pixel. Since
+ * all of the pixels in this row are the same "hit," we don't have
+ * to recalculate this
+ */
+
+ if (IS_FRONT_HIT(&g_ray_hit[row][col]))
+ {
+ bmp = g_even_bitmaps[g_ray_hit[row][col].rect->texture];
+ }
+ else
+ {
+ bmp = g_odd_bitmaps[g_ray_hit[row][col].rect->texture];
+ }
+
+ /* Get parameters associated with the size of the bitmap texture */
+
+ texture = bmp->bm;
+ tsize = bmp->log2h;
+ tmask = TMASK(tsize);
+
+ /* Extract the texture scaling from the rectangle structure */
+
+ scale = g_ray_hit[row][col].rect->scale;
+
+ /* Get the a pointer to the palette mapping table */
+
+ if (IS_SHADED(g_ray_hit[row][col].rect))
+ {
+ zone = GET_ZONE(g_ray_hit[row][col].xdist, g_ray_hit[row][col].ydist);
+ palptr = GET_PALPTR(zone);
+ }
+ else
+ {
+ palptr = GET_PALPTR(0);
+ }
+
+ /* Within this function, all references to width are really
+ * (width-1)
+ */
+
+ width--;
+
+ /* Get the index to the right side */
+
+ endcol = col + width;
+
+ /* Calculate the horizontal interpolation values */
+ /* This is the H starting position (first column) */
+
+ xpos.w = TALIGN(g_ray_hit[row][col].xpos, scale);
+
+ /* This is the change in xpos per column */
+
+ hcolstep =
+ TDIV((g_ray_hit[row][endcol].xpos - g_ray_hit[row][col].xpos),
+ width, scale);
+
+ /* Calculate the vertical interpolation values */
+ /* This is the V starting position (first column) */
+
+ ypos.w = TALIGN(g_ray_hit[row][col].ypos, scale);
+
+ /* This is the change in ypos per column */
+
+ vcolstep =
+ TDIV((g_ray_hit[row][endcol].ypos - g_ray_hit[row][col].ypos),
+ width, scale);
+
+ /* Interpolate to texture each column in the row */
+
+ for (j = col; j <= endcol; j++)
+ {
+ /* Transfer the pixel at this interpolated position */
+
+ outpixel[j] = palptr[texture[TNDX(xpos.s.i, ypos.s.i, tsize, tmask)]];
+
+ /* Now Calculate the horizontal position for the next step */
+
+ xpos.w += hcolstep;
+ ypos.w += vcolstep;
+ }
+#endif
+}
+
+/* This version is for vertical lines, i.e., height>1 and width==1 */
+
+static void trv_rend_zcol(uint8_t row, uint8_t col, uint8_t height)
+{
+#if (!DISABLE_FLOOR_RENDING)
+ uint8_t i, endrow;
+ FAR uint8_t *palptr;
+ FAR uint8_t *outpixel;
+ uint8_t scale;
+ FAR trv_pixel_t *texture;
+ FAR struct trv_bitmap_s *bmp;
+ union tex_ndx_u xpos;
+ union tex_ndx_u ypos;
+ uint16_t tmask;
+ uint16_t tsize;
+ int16_t zone;
+ int16_t hrowstep;
+ int16_t vrowstep;
+
+ /* Displace the double buffer pointer */
+
+ outpixel = &g_buffer_row[row][g_cell_column+col];
+
+ /* Point to the bitmap associated with the upper pixel. Since
+ * all of the pixels in this column are the same "hit," we don't have
+ * to recalculate this
+ */
+
+ if (IS_FRONT_HIT(&g_ray_hit[row][col]))
+ {
+ bmp = g_even_bitmaps[g_ray_hit[row][col].rect->texture];
+ }
+ else
+ {
+ bmp = g_odd_bitmaps[g_ray_hit[row][col].rect->texture];
+ }
+
+ /* Get parameters associated with the size of the bitmap texture */
+
+ texture = bmp->bm;
+ tsize = bmp->log2h;
+ tmask = TMASK(tsize);
+
+ /* Extract the texture scaling from the rectangle structure */
+
+ scale = g_ray_hit[row][col].rect->scale;
+
+ /* Get the a pointer to the palette mapping table */
+
+ if (IS_SHADED(g_ray_hit[row][col].rect))
+ {
+ zone = GET_ZONE(g_ray_hit[row][col].xdist, g_ray_hit[row][col].ydist);
+ palptr = GET_PALPTR(zone);
+ }
+ else
+ {
+ palptr = GET_PALPTR(0);
+ }
+
+ /* Within this function, all references to height are really
+ * (height-1)
+ */
+
+ height--;
+
+ /* Get the indices to the lower end */
+
+ endrow = row + height;
+
+ /* Calculate the horizontal interpolation values */
+ /* This is the H starting position (first row) */
+
+ xpos.w = TALIGN(g_ray_hit[row][col].xpos, scale);
+
+ /* This is the change in xpos for each row */
+
+ hrowstep =
+ TDIV((g_ray_hit[endrow][col].xpos - g_ray_hit[row][col].xpos),
+ height, scale);
+
+ /* Calculate the vertical interpolation values */
+ /* This is the V starting position (first row) */
+
+ ypos.w = TALIGN(g_ray_hit[row][col].ypos, scale);
+
+ /* This is the change in ypos for each row */
+
+ vrowstep =
+ TDIV((g_ray_hit[endrow][col].ypos - g_ray_hit[row][col].ypos),
+ height, scale);
+
+ /* Now, interpolate to texture each row (vertical component) */
+
+ for (i = row; i <= endrow; i++)
+ {
+ /* Transfer the pixel at this interpolated position */
+
+ *outpixel = palptr[texture[TNDX(xpos.s.i, ypos.s.i, tsize, tmask)]];
+
+ /* Point to the next row */
+
+ outpixel += TRV_SCREEN_WIDTH;
+
+ /* Calculate the vertical position for the next step */
+
+ xpos.w += hrowstep;
+ ypos.w += vrowstep;
+ }
+#endif
+}
+
+/* This version is for a single pixel, i.e., height==1 and width==1 */
+
+static void trv_rend_zpixel(uint8_t row, uint8_t col)
+{
+#if (!DISABLE_FLOOR_RENDING)
+ FAR uint8_t *palptr;
+ FAR trv_pixel_t *texture;
+ FAR struct trv_bitmap_s *bmp;
+ uint16_t tmask;
+ uint16_t tsize;
+ int16_t zone;
+
+ /* Get the a pointer to the palette mapping table */
+
+ if (IS_SHADED(g_ray_hit[row][col].rect))
+ {
+ zone = GET_ZONE(g_ray_hit[row][col].xdist, g_ray_hit[row][col].ydist);
+ palptr = GET_PALPTR(zone);
+ }
+ else
+ {
+ palptr = GET_PALPTR(0);
+ }
+
+ /* Point to the bitmap associated with the upper left pixel. */
+
+ if (IS_FRONT_HIT(&g_ray_hit[row][col]))
+ {
+ bmp = g_even_bitmaps[g_ray_hit[row][col].rect->texture];
+ }
+ else
+ {
+ bmp = g_odd_bitmaps[g_ray_hit[row][col].rect->texture];
+ }
+
+ /* Get parameters associated with the size of the bitmap texture */
+
+ texture = bmp->bm;
+ tsize = bmp->log2h;
+ tmask = TMASK(tsize);
+
+ g_buffer_row[row][g_cell_column+col] =
+ palptr[texture[TNDX(g_ray_hit[row][col].xpos, g_ray_hit[row][col].ypos,
+ tsize, tmask)]];
+#endif
+}
+
+/****************************************************************************
+ * Name: trv_rend_wall, trv_rend_wallrow, trv_rend_wallcol, diplayWallPixel
+ *
+ * Description:
+ * After matching hits have been obtained in all four corners of a cell,
+ * this function interpolates to complete the cell then transfers the cell
+ * to the double buffer. These special simplifications for use on on
+ * vertical (X or Y) walls. In this case, we can assume that:
+ *
+ * g_ray_hit[row][col].xpos == g_ray_hit[row+height-1][col]
+ * g_ray_hit[row][col+width-1].xpos == g_ray_hit[row+height-1][col+width-1]
+ *
+ * In addition to these simplifications, these functions include the
+ * added complications of handling internal INVISIBLE_PIXELs which may
+ * occur within TRANSPARENT_WALLs.
+ *
+ ****************************************************************************/
+
+/* This version is for non-degenerate cell, i.e., height>1 and width>1 */
+
+static void trv_rend_wall(uint8_t row, uint8_t col,
+ uint8_t height, uint8_t width)
+{
+#if (!DISABLE_WALL_RENDING)
+ uint8_t i, j;
+ uint8_t endrow;
+ uint8_t endcol;
+ uint8_t inpixel;
+ FAR uint8_t *palptr;
+ FAR uint8_t *outpixel;
+ uint8_t scale;
+ FAR trv_pixel_t *texture;
+ FAR struct trv_bitmap_s *bmp;
+ union tex_ndx_u xpos;
+ union tex_ndx_u ypos;
+ uint16_t tmask;
+ uint16_t tsize;
+ int16_t zone;
+ int16_t hstart;
+ int16_t hcolstep;
+ int16_t vstart;
+ int16_t vrowstep;
+ int16_t vcolstep;
+ int16_t vstepincr;
+ int16_t tmpcolstep;
+
+ /* Displace the double buffer pointer */
+
+ outpixel = &g_buffer_row[row][g_cell_column];
+
+ /* Point to the bitmap associated with the upper left pixel. Since
+ * all of the pixels in this cell are the same "hit," we don't have
+ * to recalculate this
+ */
+
+ if (IS_FRONT_HIT(&g_ray_hit[row][col]))
+ {
+ bmp = g_even_bitmaps[g_ray_hit[row][col].rect->texture];
+ }
+ else
+ {
+ bmp = g_odd_bitmaps[g_ray_hit[row][col].rect->texture];
+ }
+
+ /* Get parameters associated with the size of the bitmap texture */
+
+ texture = bmp->bm;
+ tsize = bmp->log2h;
+ tmask = TMASK(tsize);
+
+ /* Extract the texture scaling from the rectangle structure */
+
+ scale = g_ray_hit[row][col].rect->scale;
+
+ /* Get the a pointer to the palette mapping table */
+
+ if (IS_SHADED(g_ray_hit[row][col].rect))
+ {
+ zone = GET_ZONE(g_ray_hit[row][col].xdist, g_ray_hit[row][col].ydist);
+ palptr = GET_PALPTR(zone);
+ }
+ else
+ {
+ palptr = GET_PALPTR(0);
+ }
+
+ /* Within this function, all references to height and width are really
+ * (height-1) and (width-1)
+ */
+
+ height--;
+ width--;
+
+ /* Get the indices to the lower, right corner */
+
+ endcol = col + width;
+ endrow = row + height;
+
+ /* Calculate the horizontal interpolation values */
+ /* This is the H starting position (first row, first column) */
+
+ hstart = TALIGN(g_ray_hit[row][col].xpos, scale);
+
+ /* This is the change in xpos per column in the first row */
+
+ hcolstep =
+ TDIV((g_ray_hit[row][endcol].xpos - g_ray_hit[row][col].xpos),
+ width, scale);
+
+ /* Calculate the vertical interpolation values */
+ /* This is the V starting position (first row, first column) */
+
+ vstart = TALIGN(g_ray_hit[row][col].ypos, scale);
+
+ /* This is the change in ypos per column in the first row */
+
+ vcolstep =
+ TDIV((g_ray_hit[row][endcol].ypos - g_ray_hit[row][col].ypos),
+ width, scale);
+
+ /* This is the change in ypos per column in the last row */
+
+ tmpcolstep =
+ TDIV((g_ray_hit[endrow][endcol].ypos - g_ray_hit[endrow][col].ypos),
+ width, scale);
+
+ /* This is the change in vcolstep per row */
+
+ vstepincr = (TDIV((tmpcolstep - vcolstep), height, scale) >> 8);
+
+ /* This is the change in vstart for each row */
+
+ vrowstep =
+ TDIV((g_ray_hit[endrow][col].ypos - g_ray_hit[row][col].ypos),
+ height, scale);
+
+ /* Now, interpolate to texture each row (vertical component) */
+
+ for (i = row; i <= endrow; i++)
+ {
+ /* Set the initial horizontal & vertical offset */
+
+ xpos.w = hstart;
+ ypos.w = vstart;
+
+ /* Interpolate to texture each column in the row */
+
+ for (j = col; j <= endcol; j++)
+ {
+ /* Extract the pixel from the texture */
+
+ inpixel = texture[TNDX(xpos.s.i, ypos.s.i, tsize, tmask)];
+
+ /* If this is an INVISIBLE_PIXEL in a TRANSPARENT_WALL, then
+ * we will have to take some pretty extreme measures to get the
+ * correct value of the pixel
+ */
+
+ if ((inpixel == INVISIBLE_PIXEL) &&
+ (IS_TRANSPARENT(g_ray_hit[row][col].rect)))
+ {
+ /* Check if we hit anything */
+
+ if ((inpixel = trv_get_texture(i, j)) != INVISIBLE_PIXEL)
+ {
+ /* Map the normal pixel and transfer the pixel at this
+ * interpolated position
+ */
+
+ outpixel[j] = inpixel;
+ }
+ }
+ else
+ {
+ /* Map the normal pixel and transfer the pixel at this
+ * interpolated position
+ */
+
+ outpixel[j] = palptr[inpixel];
+ }
+
+ /* Now Calculate the horizontal position for the next step */
+
+ xpos.w += hcolstep;
+ ypos.w += vcolstep;
+ }
+
+ /* Point to the next row */
+
+ outpixel += TRV_SCREEN_WIDTH;
+
+ /* Calculate the vertical position for the next step */
+
+ vstart += vrowstep;
+
+ /* Adjust the step sizes to use on the next row */
+
+ vcolstep += vstepincr;
+ }
+#endif
+}
+
+/* This version is for horizontal lines, i.e., height==1 and width>1 */
+
+static void trv_rend_wallrow(uint8_t row, uint8_t col, uint8_t width)
+{
+#if (!DISABLE_WALL_RENDING)
+ uint8_t j;
+ uint8_t endcol;
+ uint8_t inpixel;
+ FAR uint8_t *palptr;
+ FAR uint8_t *outpixel;
+ uint8_t scale;
+ FAR trv_pixel_t *texture;
+ FAR struct trv_bitmap_s *bmp;
+ union tex_ndx_u xpos;
+ union tex_ndx_u ypos;
+ uint16_t tmask;
+ uint16_t tsize;
+ int16_t zone;
+ int16_t hcolstep;
+ int16_t vcolstep;
+
+ /* Displace the double buffer pointer */
+
+ outpixel = &g_buffer_row[row][g_cell_column];
+
+ /* Point to the bitmap associated with the left pixel. Since
+ * all of the pixels in this row are the same "hit," we don't have
+ * to recalculate this
+ */
+
+ if (IS_FRONT_HIT(&g_ray_hit[row][col]))
+ {
+ bmp = g_even_bitmaps[g_ray_hit[row][col].rect->texture];
+ }
+ else
+ {
+ bmp = g_odd_bitmaps[g_ray_hit[row][col].rect->texture];
+ }
+
+ /* Get parameters associated with the size of the bitmap texture */
+
+ texture = bmp->bm;
+ tsize = bmp->log2h;
+ tmask = TMASK(tsize);
+
+ /* Extract the texture scaling from the rectangle structure */
+
+ scale = g_ray_hit[row][col].rect->scale;
+
+ /* Get the a pointer to the palette mapping table */
+
+ if (IS_SHADED(g_ray_hit[row][col].rect))
+ {
+ zone = GET_ZONE(g_ray_hit[row][col].xdist, g_ray_hit[row][col].ydist);
+ palptr = GET_PALPTR(zone);
+ }
+ else
+ {
+ palptr = GET_PALPTR(0);
+ }
+
+ /* Within this function, all references to width are really
+ * (width-1)
+ */
+
+ width--;
+
+ /* Get the index to the right side */
+
+ endcol = col + width;
+
+ /* Calculate the horizontal interpolation values */
+ /* This is the H starting position (first column) */
+
+ xpos.w = TALIGN(g_ray_hit[row][col].xpos, scale);
+
+ /* This is the change in xpos per column */
+
+ hcolstep =
+ TDIV((g_ray_hit[row][endcol].xpos - g_ray_hit[row][col].xpos),
+ width, scale);
+
+ /* Calculate the vertical interpolation values */
+ /* This is the V starting position (first column) */
+
+ ypos.w = TALIGN(g_ray_hit[row][col].ypos, scale);
+
+ /* This is the change in ypos per column */
+
+ vcolstep =
+ TDIV((g_ray_hit[row][endcol].ypos - g_ray_hit[row][col].ypos),
+ width, scale);
+
+ /* Interpolate to texture each column in the row */
+
+ for (j = col; j <= endcol; j++)
+ {
+ /* Extract the pixel from the texture */
+
+ inpixel = texture[TNDX(xpos.s.i, ypos.s.i, tsize, tmask)];
+
+ /* If this is an INVISIBLE_PIXEL in a TRANSPARENT_WALL, then
+ * we will have to take some pretty extreme measures to get the
+ * correct value of the pixel
+ */
+
+ if ((inpixel == INVISIBLE_PIXEL) &&
+ (IS_TRANSPARENT(g_ray_hit[row][col].rect)))
+ {
+ /* Cast another ray and see if we hit anything */
+
+ if ((inpixel = trv_get_texture(row, j)) != INVISIBLE_PIXEL)
+ {
+ /* Map the normal pixel and transfer the pixel at this
+ * interpolated position
+ */
+
+ outpixel[j] = inpixel;
+ }
+ }
+ else
+ {
+ /* Map the normal pixel and transfer the pixel at this
+ * interpolated position
+ */
+
+ outpixel[j] = palptr[inpixel];
+ }
+
+ /* Now Calculate the horizontal position for the next step */
+
+ xpos.w += hcolstep;
+ ypos.w += vcolstep;
+ }
+#endif
+}
+
+/* This version is for vertical line, i.e., height>1 and width==1 */
+
+static void trv_rend_wallcol(uint8_t row, uint8_t col, uint8_t height)
+{
+#if (!DISABLE_WALL_RENDING)
+ uint8_t i;
+ uint8_t endrow;
+ uint8_t inpixel;
+ FAR uint8_t *palptr;
+ FAR uint8_t *outpixel;
+ uint8_t scale;
+ FAR trv_pixel_t *texture;
+ FAR struct trv_bitmap_s *bmp;
+ union tex_ndx_u ypos;
+ uint16_t tmask;
+ uint16_t tsize;
+ int16_t zone;
+ int16_t xpos;
+ int16_t vrowstep;
+
+ /* Displace the double buffer pointer */
+
+ outpixel = &g_buffer_row[row][g_cell_column+col];
+
+ /* Point to the bitmap associated with the upper pixel. Since
+ * all of the pixels in this cell are the same "hit," we don't have
+ * to recalculate this
+ */
+
+ if (IS_FRONT_HIT(&g_ray_hit[row][col]))
+ {
+ bmp = g_even_bitmaps[g_ray_hit[row][col].rect->texture];
+ }
+ else
+ {
+ bmp = g_odd_bitmaps[g_ray_hit[row][col].rect->texture];
+ }
+
+ /* Get parameters associated with the size of the bitmap texture */
+
+ texture = bmp->bm;
+ tsize = bmp->log2h;
+ tmask = TMASK(tsize);
+
+ /* Extract the texture scaling from the rectangle structure */
+
+ scale = g_ray_hit[row][col].rect->scale;
+
+ /* Get the a pointer to the palette mapping table */
+
+ if (IS_SHADED(g_ray_hit[row][col].rect))
+ {
+ zone = GET_ZONE(g_ray_hit[row][col].xdist, g_ray_hit[row][col].ydist);
+ palptr = GET_PALPTR(zone);
+ }
+ else
+ {
+ palptr = GET_PALPTR(0);
+ }
+
+ /* Within this function, all references to height are really
+ * (height-1)
+ */
+
+ height--;
+
+ /* Get the indices to the lower end */
+
+ endrow = row + height;
+
+ /* Calculate the horizontal interpolation values */
+
+ xpos = sFRAC(g_ray_hit[row][col].xpos >> scale);
+
+ /* Calculate the vertical interpolation values */
+ /* This is the V starting position (first row, first column) */
+
+ ypos.w = TALIGN(g_ray_hit[row][col].ypos, scale);
+
+ /* This is the change in ypos for each row */
+
+ vrowstep =
+ TDIV((g_ray_hit[endrow][col].ypos - g_ray_hit[row][col].ypos),
+ height, scale);
+
+ /* Now, interpolate to texture the vertical line */
+
+ for (i = row; i <= endrow; i++)
+ {
+ /* Extract the pixel from the texture */
+
+ inpixel = texture[TNDX(xpos, ypos.s.i, tsize, tmask)];
+
+ /* If this is an INVISIBLE_PIXEL in a TRANSPARENT_WALL, then
+ * we will have to take some pretty extreme measures to get the
+ * correct value of the pixel
+ */
+
+ if ((inpixel == INVISIBLE_PIXEL) &&
+ (IS_TRANSPARENT(g_ray_hit[row][col].rect)))
+ {
+ /* Check if we hit anything */
+
+ if ((inpixel = trv_get_texture(i, col)) != INVISIBLE_PIXEL)
+ {
+ /* Map the normal pixel and transfer the pixel at this
+ * interpolated position
+ */
+
+ *outpixel = inpixel;
+ }
+ }
+ else
+ {
+ /* Map the normal pixel and transfer the pixel at this
+ * interpolated position
+ */
+
+ *outpixel = palptr[inpixel];
+ }
+
+ /* Point to the next row */
+
+ outpixel += TRV_SCREEN_WIDTH;
+
+ /* Calculate the vertical position for the next step */
+
+ ypos.w += vrowstep;
+ }
+#endif
+}
+
+/* This version is for a single pixel, i.e., height==1 and width==1 */
+
+static void trv_rend_wallpixel(uint8_t row, uint8_t col)
+{
+#if (!DISABLE_WALL_RENDING)
+ uint8_t *palptr;
+ int16_t zone;
+
+ /* Get the a pointer to the palette mapping table */
+
+ if (IS_SHADED(g_ray_hit[row][col].rect))
+ {
+ zone = GET_ZONE(g_ray_hit[row][col].xdist, g_ray_hit[row][col].ydist);
+ palptr = GET_PALPTR(zone);
+ }
+ else
+ {
+ palptr = GET_PALPTR(0);
+ }
+
+ /* The map and transfer the pixel to the display buffer */
+
+ if (IS_FRONT_HIT(&g_ray_hit[row][col]))
+ {
+ g_buffer_row[row][g_cell_column+col] =
+ palptr[GET_FRONT_PIXEL(g_ray_hit[row][col].rect,
+ g_ray_hit[row][col].xpos,
+ g_ray_hit[row][col].ypos)];
+ }
+ else
+ {
+ g_buffer_row[row][g_cell_column+col] =
+ palptr[GET_BACK_PIXEL(g_ray_hit[row][col].rect,
+ g_ray_hit[row][col].xpos,
+ g_ray_hit[row][col].ypos)];
+ }
+#endif
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: trv_rend_backdrop
+ * Description:
+ *
+ * Clear the screen and draw the sky and ground using 32 bit transfers.
+ *
+ ****************************************************************************/
+
+void trv_rend_backdrop(FAR struct trv_camera_s *camera,
+ FAR struct trv_graphics_info_s *ginfo)
+{
+#ifdef ENABLE_VIDEO
+ FAR uint32_t *dest;
+ uint32_t plotpixels;
+ int32_t skyrows;
+ uint16_t buffersize;
+ uint16_t n;
+ int16_t pitchoffset;
+
+ /* The destination of the transfer is the screen buffer */
+
+ dest = (uint32_t*)ginfo->swbuffer;
+
+ /* Convert the pitch angle into signed screen offset */
+
+ if ((pitchoffset = camera->pitch) > ANGLE_90)
+ {
+ pitchoffset -= ANGLE_360;
+ }
+
+ /* Determine the size of the "sky" buffer in rows. Positive pitchoffset
+ * means we are looking up. In this case the sky gets bigger.
+ */
+
+ skyrows = WINDOW_MIDDLE + pitchoffset;
+
+ /* Handle the case where we are looking down and do not see any of the
+ * sky
+ */
+
+ if (skyrows <= 0)
+ {
+ /* No sky rows -- No sky buffersize */
+
+ skyrows = buffersize = 0;
+ }
+
+ /* Copy the sky color into the top half of the screen */
+
+ else
+ {
+ /* Handle the case where we are looking up and see only the sky */
+
+ if (skyrows > WINDOW_HEIGHT)
+ {
+ skyrows = WINDOW_HEIGHT;
+ }
+
+ /* Determine the size of the "sky" buffer in 32-bit units */
+
+ buffersize = (TRV_SCREEN_WIDTH/4) * skyrows;
+
+ /* Combine the sky color into 32-bit "quadruple pixels" */
+
+ plotpixels = (((uint32_t)g_sky_color << 24) |
+ ((uint32_t)g_sky_color << 16) |
+ ((uint32_t)g_sky_color << 8) |
+ (uint32_t)g_sky_color);
+
+ /* Then transfer the "sky" */
+
+ for (n = 0; n < buffersize; n++)
+ {
+ *dest++ = plotpixels;
+ }
+ }
+
+ /* Copy the ground color into the bottom half of the screen */
+
+ if (skyrows < WINDOW_HEIGHT)
+ {
+ /* Determine the size of the "ground" buffer in 32-bit units */
+
+ buffersize = (TRV_SCREEN_WIDTH/4) * (WINDOW_HEIGHT - skyrows);
+
+ /* Combine the ground color into 32-bit "quadruple pixels" */
+
+ plotpixels = (((uint32_t)g_ground_color << 24) |
+ ((uint32_t)g_ground_color << 16) |
+ ((uint32_t)g_ground_color << 8) |
+ (uint32_t)g_ground_color);
+
+ /* Then transfer the "ground" */
+
+ for (n = 0; n < buffersize; n++)
+ {
+ *dest++ = plotpixels;
+ }
+ }
+#endif
+}
+
+/****************************************************************************
+ * Name: trv_rend_cell, trv_rend_row, trv_rend_column, trv_rend_pixel
+ *
+ * Description:
+ * After matching hits have been obtained in all four corners of a cell,
+ * this function interpolates to complete the cell then transfers the cell
+ * to the double buffer.
+ *
+ ****************************************************************************/
+
+/* This version is for non-degenerate cell, i.e., height>1 and width>1 */
+
+void trv_rend_cell(uint8_t row, uint8_t col, uint8_t height, uint8_t width)
+{
+ /* If the cell is visible, then put it in the off-screen buffer.
+ * Otherwise, just drop it on the floor
+ */
+
+ if (g_ray_hit[row][col].rect)
+ {
+ /* Apply texturing... special case for hits on floor or ceiling */
+
+ if (IS_ZRAY_HIT(&g_ray_hit[row][col]))
+ {
+ trv_rend_zcell(row, col, height, width);
+ }
+ else
+ {
+ trv_rend_wall(row, col, height, width);
+ }
+ }
+}
+
+/* This version is for horizontal lines, i.e., height==1 and width>1 */
+
+void trv_rend_row(uint8_t row, uint8_t col, uint8_t width)
+{
+ /* If the cell is visible, then put it in the off-screen buffer.
+ * Otherwise, just drop it on the floor
+ */
+
+ if (g_ray_hit[row][col].rect)
+ {
+ /* Apply texturing... special case for hits on floor or ceiling */
+
+ if (IS_ZRAY_HIT(&g_ray_hit[row][col]))
+ {
+ trv_rend_zrow(row, col, width);
+ }
+ else
+ {
+ trv_rend_wallrow(row, col, width);
+ }
+ }
+}
+
+/* This version is for vertical lines, i.e., height>1 and width==1 */
+
+void trv_rend_column(uint8_t row, uint8_t col, uint8_t height)
+{
+ /* If the cell is visible, then put it in the off-screen buffer.
+ * Otherwise, just drop it on the floor
+ */
+
+ if (g_ray_hit[row][col].rect)
+ {
+ /* Apply texturing... special case for hits on floor or ceiling */
+
+ if (IS_ZRAY_HIT(&g_ray_hit[row][col]))
+ {
+ trv_rend_zcol(row, col, height);
+ }
+ else
+ {
+ trv_rend_wallcol(row, col, height);
+ }
+ }
+}
+
+/* This version is for a single pixel, i.e., height==1 and width==1 */
+
+void trv_rend_pixel(uint8_t row, uint8_t col)
+{
+ /* If the cell is visible, then put it in the off-screen buffer.
+ * Otherwise, just drop it on the floor
+ */
+
+ if (g_ray_hit[row][col].rect)
+ {
+ /* Apply texturing... special case for hits on floor or ceiling */
+
+ if (IS_ZRAY_HIT(&g_ray_hit[row][col]))
+ {
+ trv_rend_zpixel(row, col);
+ }
+ else
+ {
+ trv_rend_wallpixel(row, col);
+ }
+ }
+}
+
+/****************************************************************************
+ * Name: trv_get_rectpixel
+ *
+ * Description:
+ * Returns the pixel for a hit at (xpos, ypos) on rect.
+ *
+ ****************************************************************************/
+
+trv_pixel_t trv_get_rectpixel(int16_t xpos, int16_t ypos,
+ FAR struct trv_bitmap_s *bmp, uint8_t scale)
+{
+ uint16_t tmask;
+ uint16_t tsize;
+
+ /* Get parameters associated with the size of the bitmap texture */
+
+ tsize = bmp->log2h;
+ tmask = TMASK(tsize);
+
+ /* Return the texture code at this position */
+
+ return(bmp->bm[TNDX((xpos >> scale), (ypos >> scale), tsize, tmask)]);
+}
+