|
|
|
@ -2,6 +2,7 @@ |
|
|
|
|
#include "amt/texture.hpp" |
|
|
|
|
#include "amt/pixel.hpp" |
|
|
|
|
#include "constants.hpp" |
|
|
|
|
#include "thread.hpp" |
|
|
|
|
|
|
|
|
|
#define AMT_LIGHT |
|
|
|
|
|
|
|
|
@ -11,14 +12,14 @@ using namespace fmt; |
|
|
|
|
#ifdef AMT_LIGHT |
|
|
|
|
static constexpr auto room_brightness = 0.3f; // increse this to increase the room brightness. Higher value means brighter room.
|
|
|
|
|
|
|
|
|
|
inline static constexpr amt::RGBA dumb_lighting(amt::RGBA pixel, double distance, double distance_from_center) { |
|
|
|
|
inline static constexpr amt::RGBA dumb_lighting(amt::RGBA pixel, float distance, float distance_from_center) { |
|
|
|
|
auto const dim_pixel = pixel * room_brightness; |
|
|
|
|
if (distance_from_center >= 0) { |
|
|
|
|
auto const min_brightness = 1. / std::max(distance_from_center, 0.5); // farther away from the center darker it gets
|
|
|
|
|
auto const max_brightness = 1.; // brighness should not exceed 1
|
|
|
|
|
auto const min_brightness = 1.f / std::max(distance_from_center, 0.5f); // farther away from the center darker it gets
|
|
|
|
|
auto const max_brightness = 1.f; // brighness should not exceed 1
|
|
|
|
|
auto const pixel_brightness = std::max(min_brightness, std::min(max_brightness, distance)); |
|
|
|
|
auto const yellow_brightness = float(distance_from_center * 60); |
|
|
|
|
|
|
|
|
|
auto const yellow_brightness = float(distance_from_center * 60); |
|
|
|
|
amt::RGBA const yellow = amt::HSLA(40, 20, yellow_brightness); |
|
|
|
|
|
|
|
|
|
auto temp = (pixel / pixel_brightness).blend<amt::BlendMode::softLight>(yellow); |
|
|
|
@ -29,6 +30,7 @@ inline static constexpr amt::RGBA dumb_lighting(amt::RGBA pixel, double distance |
|
|
|
|
} |
|
|
|
|
#else |
|
|
|
|
inline static constexpr amt::RGBA dumb_lighting(amt::RGBA pixel, double distance, double distance_from_center) { |
|
|
|
|
(void)distance_from_center; |
|
|
|
|
if(distance < 0.9) return pixel; |
|
|
|
|
return pixel / distance; |
|
|
|
|
} |
|
|
|
@ -45,7 +47,9 @@ Raycaster::Raycaster(sf::RenderWindow& window, Matrix &map, unsigned width, unsi |
|
|
|
|
$map(map), |
|
|
|
|
spriteOrder(textures.NUM_SPRITES), |
|
|
|
|
spriteDistance(textures.NUM_SPRITES), |
|
|
|
|
ZBuffer(width) |
|
|
|
|
ZBuffer(width), |
|
|
|
|
$radius(std::min($height, $width) / 2), |
|
|
|
|
$r_sq($radius * $radius) |
|
|
|
|
{ |
|
|
|
|
$window.setVerticalSyncEnabled(VSYNC); |
|
|
|
|
view_sprite.setPosition({0, 0}); |
|
|
|
@ -74,9 +78,6 @@ void Raycaster::clear() { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void Raycaster::sprite_casting() { |
|
|
|
|
const int textureWidth = textures.TEXTURE_WIDTH; |
|
|
|
|
const int textureHeight = textures.TEXTURE_HEIGHT; |
|
|
|
|
|
|
|
|
|
// sort sprites from far to close
|
|
|
|
|
for(int i = 0; i < textures.NUM_SPRITES; i++) { |
|
|
|
|
auto& sprite = textures.get_sprite(i); |
|
|
|
@ -90,8 +91,10 @@ void Raycaster::sprite_casting() { |
|
|
|
|
|
|
|
|
|
sort_sprites(spriteOrder, spriteDistance, textures.NUM_SPRITES); |
|
|
|
|
|
|
|
|
|
/*for(int i = 0; i < textures.NUM_SPRITES; i++) {*/ |
|
|
|
|
// after sorting the sprites, do the projection
|
|
|
|
|
for(int i = 0; i < textures.NUM_SPRITES; i++) { |
|
|
|
|
// Be careful about capturing stack variables.
|
|
|
|
|
amt::parallel_for<1>(pool, 0, textures.NUM_SPRITES, [this, textureWidth = textures.TEXTURE_WIDTH, textureHeight = textures.TEXTURE_HEIGHT](size_t i){ |
|
|
|
|
int sprite_index = spriteOrder[i]; |
|
|
|
|
Sprite& sprite_rec = textures.get_sprite(sprite_index); |
|
|
|
|
auto& sprite_texture = textures.get_texture(sprite_rec.texture); |
|
|
|
@ -139,33 +142,39 @@ void Raycaster::sprite_casting() { |
|
|
|
|
// the conditions in the if are:
|
|
|
|
|
// 1) it's in front of the camera plane so you don't see things behind you
|
|
|
|
|
// 2) ZBuffer, with perpendicular distance
|
|
|
|
|
if (texX < 0) continue; |
|
|
|
|
if(transformY > 0 && transformY < ZBuffer[stripe]) { |
|
|
|
|
for(int y = drawStartY; y < drawEndY; y++) { |
|
|
|
|
//256 and 128 factors to avoid floats
|
|
|
|
|
int d = (y - vMoveScreen) * 256 - $height * 128 + spriteHeight * 128; |
|
|
|
|
int texY = ((d * textureHeight) / spriteHeight) / 256; |
|
|
|
|
if ((size_t)texY >= sprite_texture.rows()) continue; |
|
|
|
|
//get current color from the texture
|
|
|
|
|
// BUG: this crashes sometimes when the math goes out of bounds
|
|
|
|
|
if(texY < 0 || texY >= (int)sprite_texture.rows()) continue; |
|
|
|
|
auto color = sprite_texture[texY][texX]; |
|
|
|
|
// poor person's transparency, get current color from the texture
|
|
|
|
|
pixels[y][stripe] = (color.to_hex() & 0xffffff00) ? color: pixels[y][stripe]; |
|
|
|
|
if (!(color.to_hex() & 0xffffff00)) continue; |
|
|
|
|
auto dist = get_distance_from_center(stripe, y); |
|
|
|
|
pixels[y][stripe] = dumb_lighting(color, d, dist); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void Raycaster::cast_rays() { |
|
|
|
|
double perpWallDist = 0; |
|
|
|
|
float Raycaster::get_distance_from_center(int x, int y) const noexcept { |
|
|
|
|
float cx = $width / 2; |
|
|
|
|
float cy = $height / 2; |
|
|
|
|
auto dx = cx - x; |
|
|
|
|
auto dy = cy - y; |
|
|
|
|
return ($r_sq - dx * dx - dy * dy) / $r_sq; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
auto const cx = $width / 2; |
|
|
|
|
auto const cy = $height / 2; |
|
|
|
|
double const radius = std::min($height, $width) / 2; |
|
|
|
|
double const r_sq = radius * radius; |
|
|
|
|
void Raycaster::cast_rays() { |
|
|
|
|
|
|
|
|
|
// WALL CASTING
|
|
|
|
|
for(int x = 0; x < $width; x++) { |
|
|
|
|
/*for(int x = 0; x < $width; x++) {*/ |
|
|
|
|
amt::parallel_for<32>(pool, 0, static_cast<std::size_t>($width), [this](size_t x){ |
|
|
|
|
double perpWallDist = 0; |
|
|
|
|
// calculate ray position and direction
|
|
|
|
|
double cameraX = 2 * x / double($width) - 1; // x-coord in camera space
|
|
|
|
|
double rayDirX = dirX + planeX * cameraX; |
|
|
|
@ -260,23 +269,24 @@ void Raycaster::cast_rays() { |
|
|
|
|
for(int y = drawStart; y < drawEnd; y++) { |
|
|
|
|
int texY = (int)texPos & (textures.TEXTURE_HEIGHT - 1); |
|
|
|
|
texPos += step; |
|
|
|
|
auto const dx = cx - x; |
|
|
|
|
auto const dy = cy - y; |
|
|
|
|
double const dist = dx * dx + dy * dy; |
|
|
|
|
auto color = dumb_lighting(texture[texY][texX], perpWallDist, (r_sq - dist) / r_sq); |
|
|
|
|
auto dist = get_distance_from_center(x, y); |
|
|
|
|
auto color = dumb_lighting(texture[texY][texX], perpWallDist, dist); |
|
|
|
|
pixels[y][x] = color; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// SET THE ZBUFFER FOR THE SPRITE CASTING
|
|
|
|
|
ZBuffer[x] = perpWallDist; |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void Raycaster::draw_ceiling_floor() { |
|
|
|
|
const size_t textureWidth = textures.TEXTURE_WIDTH; |
|
|
|
|
const size_t textureHeight = textures.TEXTURE_HEIGHT; |
|
|
|
|
|
|
|
|
|
for(int y = $height / 2 + 1; y < $height; ++y) { |
|
|
|
|
/*for(int y = $height / 2 + 1; y < $height; ++y) {*/ |
|
|
|
|
|
|
|
|
|
auto const h = static_cast<size_t>($height); |
|
|
|
|
amt::parallel_for<32>(pool, h / 2, h, [this, $height=h](size_t y){ |
|
|
|
|
const size_t textureWidth = textures.TEXTURE_WIDTH; |
|
|
|
|
const size_t textureHeight = textures.TEXTURE_HEIGHT; |
|
|
|
|
// rayDir for leftmost ray (x=0) and rightmost (x = w)
|
|
|
|
|
float rayDirX0 = dirX - planeX; |
|
|
|
|
float rayDirY0 = dirY - planeY; |
|
|
|
@ -327,10 +337,12 @@ void Raycaster::draw_ceiling_floor() { |
|
|
|
|
|
|
|
|
|
#ifdef AMT_LIGHT |
|
|
|
|
// FLOOR
|
|
|
|
|
pixels[y][x] = textures.floor[ty][tx] * room_brightness; |
|
|
|
|
auto dist_floor = get_distance_from_center(x, y); |
|
|
|
|
pixels[y][x] = dumb_lighting(textures.floor[ty][tx], p, dist_floor); |
|
|
|
|
|
|
|
|
|
// CEILING
|
|
|
|
|
pixels[$height - y - 1][x] = textures.ceiling[ty][tx] * room_brightness; |
|
|
|
|
auto dist_ceiling = get_distance_from_center(x, $height - y - 1); |
|
|
|
|
pixels[$height - y - 1][x] = dumb_lighting(textures.ceiling[ty][tx], p, dist_ceiling); |
|
|
|
|
#else |
|
|
|
|
// FLOOR
|
|
|
|
|
pixels[y][x] = textures.floor[ty][tx]; |
|
|
|
@ -340,14 +352,18 @@ void Raycaster::draw_ceiling_floor() { |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void Raycaster::render() { |
|
|
|
|
draw_ceiling_floor(); |
|
|
|
|
// This wait to prevent data-race
|
|
|
|
|
pool.wait(); // Try to remove this to see unbelievable performance
|
|
|
|
|
cast_rays(); |
|
|
|
|
pool.wait(); // Try to remove this too
|
|
|
|
|
sprite_casting(); |
|
|
|
|
pool.wait(); |
|
|
|
|
draw_pixel_buffer(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|