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