/*****************************************************************************
* 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)]);
}