Skip to content

Commit

Permalink
Draw sprite vertical strips using integer arithmetic
Browse files Browse the repository at this point in the history
  • Loading branch information
wernsey committed Mar 6, 2023
1 parent e0f5cbb commit 8039f41
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 32 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,7 @@ The Dungeon Crawl Stone Soup graphics are from here:

# Step 2: Better vertical strips

Step 2 is to convert the code that
Step 2 is to convert the code that draws the vertical strips to use integer only arithmetic

commit e0f5cbbc6e2bb3011b210c3a2a2a779c6896769a

61 changes: 30 additions & 31 deletions raycaster_sprites.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ int main(int /*argc*/, char */*argv*/[])
if(side == 0 && rayDirX > 0) texX = texWidth - texX - 1;
if(side == 1 && rayDirY < 0) texX = texWidth - texX - 1;

#if 1
// Draw the vertical strip
int texY = 0, c = 0;
int dy = drawEnd - drawStart;

Expand Down Expand Up @@ -338,27 +338,6 @@ int main(int /*argc*/, char */*argv*/[])
}
}

#else
if(drawStart < 0) drawStart = 0;
if(drawEnd >= h) drawEnd = h - 1;
// TODO: an integer-only bresenham or DDA like algorithm could make the texture coordinate stepping faster
// How much to increase the texture coordinate per screen pixel
double step = 1.0 * texHeight / lineHeight;
// Starting texture coordinate
double texPos = (drawStart - h / 2 + lineHeight / 2) * step;
for(int y = drawStart; y < drawEnd; y++)
{
// Cast the texture coordinate to integer, and mask with (texHeight - 1) in case of overflow
int texY = (int)texPos & (texHeight - 1);
texPos += step;
Uint32 color = texture[texNum][texHeight * texY + texX];
//make color darker for y-sides: R, G and B byte each divided through two with a "shift" and an "and"
if(side == 1) color = (color >> 1) & 8355711;
buffer[y][x] = color;
}
#endif

//SET THE ZBUFFER FOR THE SPRITE CASTING
ZBuffer[x] = perpWallDist; //perpendicular distance is used
}
Expand Down Expand Up @@ -392,18 +371,18 @@ int main(int /*argc*/, char */*argv*/[])
int spriteScreenX = int((w / 2) * (1 + transformX / transformY));

//parameters for scaling and moving the sprites
#define uDiv 1
#define vDiv 1
#define vMove 0.0
#define uDiv 2
#define vDiv 2
// Note that vMove is 128 rather than 64 to get the sprites on the ground.
// It's because the textures are 32x32, rather than 64x64 as in the original.
#define vMove 128.0
int vMoveScreen = int(vMove / transformY);

//calculate height of the sprite on screen
int spriteHeight = abs(int(h / (transformY))) / vDiv; //using "transformY" instead of the real distance prevents fisheye
//calculate lowest and highest pixel to fill in current stripe
int drawStartY = -spriteHeight / 2 + h / 2 + vMoveScreen;
if(drawStartY < 0) drawStartY = 0;
int drawEndY = spriteHeight / 2 + h / 2 + vMoveScreen;
if(drawEndY >= h) drawEndY = h - 1;

//calculate width of the sprite
int spriteWidth = abs(int (h / (transformY))) / uDiv; // same as height of sprite, given that it's square
Expand All @@ -412,6 +391,21 @@ int main(int /*argc*/, char */*argv*/[])
int drawEndX = spriteWidth / 2 + spriteScreenX;
if(drawEndX > w) drawEndX = w;

// Precompute some variables for the vertical strips
int dy = drawEndY - drawStartY;
int c0 = 0, texY0 = 0;
if(drawStartY < 0) {
c0 = -drawStartY * texHeight;
if(c0 > dy) {
div_t res = div(c0, dy);
texY0 += res.quot;
c0 = res.rem;
}
drawStartY = 0;
}
if(drawEndY >= h)
drawEndY = (h-1);

//loop through every vertical stripe of the sprite on screen
for(int stripe = drawStartX; stripe < drawEndX; stripe++)
{
Expand All @@ -421,12 +415,17 @@ int main(int /*argc*/, char */*argv*/[])
//2) ZBuffer, with perpendicular distance
if(transformY > 0 && transformY < ZBuffer[stripe])
{
for(int y = drawStartY; y < drawEndY; y++) //for every pixel of the current stripe
{
int d = (y - vMoveScreen) * 256 - h * 128 + spriteHeight * 128; //256 and 128 factors to avoid floats
int texY = ((d * texHeight) / spriteHeight) / 256;
int texY = texY0, c = c0;
for(int y = drawStartY; y < drawEndY; y++) {

Uint32 color = texture[sprite[spriteOrder[i]].texture][texWidth * texY + texX]; //get current color from the texture
if((color & 0x00FFFFFF) != 0) buffer[y][stripe] = color; //paint pixel if it isn't black, black is the invisible color

c = c + texHeight;
while(c > dy) {
texY++;
c = c - dy;
}
}
}
}
Expand Down

0 comments on commit 8039f41

Please sign in to comment.