@ -1,6 +1,7 @@
# include "raycaster.hpp"
using namespace fmt ;
using std : : make_unique ;
# define rgba_color(r,g,b,a) (r<<(0*8))|(g<<(1*8))|(b<<(2*8))|(a<<(3*8))
# define gray_color(c) rgba_color(c, c, c, 255)
@ -9,54 +10,14 @@ using namespace fmt;
# define uDiv 1
# define vDiv 1
inline void RGBA_brightness ( RGBA & pixel , double distance ) {
pixel . color . r / = distance ;
pixel . color . g / = distance ;
pixel . color . b / = distance ;
}
inline size_t pixcoord ( int x , int y ) {
return ( ( y ) * RAY_VIEW_WIDTH ) + ( x ) ;
}
Raycaster : : Raycaster ( sf : : RenderWindow & window ) :
$ window ( window )
{
$ window . setVerticalSyncEnabled ( true ) ;
view_texture . create ( RAY_VIEW_WIDTH , RAY_VIEW_HEIGHT ) ;
view_sprite . setTexture ( view_texture ) ;
view_sprite . setPosition ( RAY_VIEW_X , 0 ) ;
pixels = new RGBA [ RAY_VIEW_WIDTH * RAY_VIEW_HEIGHT ] ;
SPRITE = { { 4.0 , 3.55 , 0 , 8 } } ;
MAP = { { 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 } ,
{ 8 , 0 , 2 , 0 , 0 , 0 , 0 , 0 , 8 } ,
{ 8 , 0 , 7 , 0 , 0 , 5 , 6 , 0 , 8 } ,
{ 8 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 8 } ,
{ 8 , 8 , 0 , 0 , 0 , 0 , 0 , 8 , 8 } ,
{ 8 , 0 , 0 , 1 , 3 , 4 , 0 , 0 , 8 } ,
{ 8 , 0 , 0 , 0 , 0 , 0 , 8 , 8 , 8 } ,
{ 8 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 8 } ,
{ 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 }
} ;
TILE_SIZE = RAY_VIEW_HEIGHT / matrix : : width ( MAP ) ;
// x and y start position
posX = player_x / TILE_SIZE ;
posY = player_y / TILE_SIZE ;
}
void Raycaster : : load_image ( std : : vector < uint32_t > & texture , const char * filename ) {
sf : : Image img ;
bool good = img . loadFromFile ( filename ) ;
dbc : : check ( good , format ( " failed to load {} " , filename ) ) ;
uint32_t * pixbuf = ( uint32_t * ) img . getPixelsPtr ( ) ;
std : : copy_n ( pixbuf , texture . size ( ) , texture . begin ( ) ) ;
}
void Raycaster : : load_textures ( ) {
void TexturePack : : load_textures ( ) {
// ZED: this needs to determine sprite vs. other textures
// so it can put the texture into the sprite rec immediately
// or....maybe just use SFML's sprite stuff?
for ( int i = 0 ; i < NUM_TEXTURES ; i + + ) {
texture [ i ] . resize ( TEXTURE_WIDTH * TEXTURE_HEIGHT ) ;
}
@ -72,18 +33,54 @@ void Raycaster::load_textures() {
load_image ( texture [ 8 ] , " assets/portal.png " ) ;
}
std : : vector < uint32_t > & TexturePack : : get ( size_t num ) {
return texture [ num ] ;
}
void TexturePack : : load_image ( std : : vector < uint32_t > & texture , const char * filename ) {
sf : : Image img ;
bool good = img . loadFromFile ( filename ) ;
dbc : : check ( good , format ( " failed to load {} " , filename ) ) ;
uint32_t * pixbuf = ( uint32_t * ) img . getPixelsPtr ( ) ;
std : : copy_n ( pixbuf , texture . size ( ) , texture . begin ( ) ) ;
}
Sprite & TexturePack : : get_sprite ( size_t sprite_num ) {
return SPRITE [ sprite_num ] ;
}
Raycaster : : Raycaster ( sf : : RenderWindow & window , Matrix & map ) :
$ window ( window ) ,
$ map ( map )
{
$ window . setVerticalSyncEnabled ( true ) ;
view_texture . create ( RAY_VIEW_WIDTH , RAY_VIEW_HEIGHT ) ;
view_sprite . setTexture ( view_texture ) ;
view_sprite . setPosition ( RAY_VIEW_X , 0 ) ;
pixels = make_unique < RGBA [ ] > ( RAY_VIEW_WIDTH * RAY_VIEW_HEIGHT ) ;
textures . load_textures ( ) ;
}
void Raycaster : : position_camera ( float player_x , float player_y , int tile_size ) {
// x and y start position
posX = player_x / tile_size ;
posY = player_y / tile_size ;
}
void Raycaster : : draw_pixel_buffer ( ) {
view_texture . update ( ( uint8_t * ) pixels , RAY_VIEW_WIDTH , RAY_VIEW_HEIGHT , 0 , 0 ) ;
view_texture . update ( ( uint8_t * ) pixels . get ( ) , RAY_VIEW_WIDTH , RAY_VIEW_HEIGHT , 0 , 0 ) ;
// BUG: can I do this once and just update it?
$ window . draw ( view_sprite ) ;
}
void Raycaster : : clear ( ) {
std : : fill_n ( ( uint32_t * ) pixels , RAY_VIEW_WIDTH * RAY_VIEW_HEIGHT , 0 ) ;
std : : fill_n ( pixels . get ( ) , RAY_VIEW_WIDTH * RAY_VIEW_HEIGHT , 0 ) ;
$ window . clear ( ) ;
}
void Raycaster : : cast_rays ( Matrix & map ) {
void Raycaster : : cast_rays ( ) {
int w = RAY_VIEW_WIDTH ;
int h = RAY_VIEW_HEIGHT ;
double perpWallDist ;
@ -141,7 +138,7 @@ void Raycaster::cast_rays(Matrix& map) {
side = 1 ;
}
if ( map [ mapY ] [ mapX ] > 0 ) hit = 1 ;
if ( $ map [ mapY ] [ mapX ] > 0 ) hit = 1 ;
}
if ( side = = 0 ) {
@ -158,7 +155,7 @@ void Raycaster::cast_rays(Matrix& map) {
int drawEnd = lineHeight / 2 + h / 2 + PITCH ;
if ( drawEnd > = h ) drawEnd = h - 1 ;
int texNum = MAP [ mapY ] [ mapX ] - 1 ;
auto & texture = textures . get ( $ map [ mapY ] [ mapX ] - 1 ) ;
// calculate value of wallX
double wallX ; // where exactly the wall was hit
@ -184,8 +181,7 @@ void Raycaster::cast_rays(Matrix& map) {
for ( int y = drawStart ; y < drawEnd ; y + + ) {
int texY = ( int ) texPos & ( TEXTURE_HEIGHT - 1 ) ;
texPos + = step ;
RGBA pixel { . out = texture [ texNum ] [ TEXTURE_HEIGHT * texY + texX ] } ;
RGBA_brightness ( pixel , perpWallDist ) ;
RGBA pixel = texture [ TEXTURE_HEIGHT * texY + texX ] ;
pixels [ pixcoord ( x , y ) ] = pixel ;
}
@ -198,10 +194,10 @@ void Raycaster::cast_rays(Matrix& map) {
for ( int i = 0 ; i < NUM_SPRITES ; i + + ) {
spriteOrder [ i ] = i ;
// this is just the distance calculation
spriteDistance [ i ] = ( ( posX - SPRITE [ i ] . x ) *
( posX - SPRITE [ i ] . x ) +
( posY - SPRITE [ i ] . y ) *
( posY - SPRITE [ i ] . y ) ) ;
spriteDistance [ i ] = ( ( posX - textures . SPRITE [ i ] . x ) *
( posX - textures . SPRITE [ i ] . x ) +
( posY - textures . SPRITE [ i ] . y ) *
( posY - textures . SPRITE [ i ] . y ) ) ;
}
sort_sprites ( spriteOrder , spriteDistance , NUM_SPRITES ) ;
@ -209,11 +205,10 @@ void Raycaster::cast_rays(Matrix& map) {
// after sorting the sprites, do the projection
for ( int i = 0 ; i < NUM_SPRITES ; i + + ) {
int sprite_index = spriteOrder [ i ] ;
Sprite & sprite_rec = SPRITE [ sprite_index ] ;
Sprite & sprite_rec = textures . get_sprite ( sprite_index ) ;
double spriteX = sprite_rec . x - posX ;
double spriteY = sprite_rec . y - posY ;
int sprite_texture_number = sprite_rec . texture ;
auto sprite_texture = texture [ sprite_texture_number ] ;
auto & sprite_texture = textures . get ( sprite_rec . texture ) ;
//transform sprite with the inverse camera matrix
// [ planeX dirX ] -1 [ dirY -dirX ]
@ -261,11 +256,11 @@ void Raycaster::cast_rays(Matrix& map) {
int d = ( y - vMoveScreen ) * 256 - h * 128 + spriteHeight * 128 ;
int texY = ( ( d * TEXTURE_HEIGHT ) / spriteHeight ) / 256 ;
//get current color from the texture
// BUG: this crashes sometimes when the math goes out of bounds
uint32_t color = sprite_texture [ TEXTURE_WIDTH * texY + texX ] ;
// poor person's transparency, get current color from the texture
if ( ( color & 0x00FFFFFF ) ! = 0 ) {
RGBA pixel { . out = color } ;
RGBA_brightness ( pixel , perpWallDist ) ;
RGBA pixel = color ;
pixels [ pixcoord ( stripe , y ) ] = pixel ;
}
}
@ -277,6 +272,8 @@ void Raycaster::cast_rays(Matrix& map) {
void Raycaster : : draw_ceiling_floor ( ) {
int screenHeight = RAY_VIEW_HEIGHT ;
int screenWidth = RAY_VIEW_WIDTH ;
auto & floorTexture = textures . get ( textures . floor ) ;
auto & ceilingTexture = textures . get ( textures . ceiling ) ;
for ( int y = screenHeight / 2 + 1 ; y < screenHeight ; + + y ) {
// rayDir for leftmost ray (x=0) and rightmost (x = w)
@ -329,30 +326,29 @@ void Raycaster::draw_ceiling_floor() {
// floorX cellX to find the texture x/y. How?
// FLOOR
color = texture [ floorTexture ] [ TEXTURE_WIDTH * ty + tx ] ;
pixels [ pixcoord ( x , y ) ] . out = color ;
color = floorTexture [ TEXTURE_WIDTH * ty + tx ] ;
pixels [ pixcoord ( x , y ) ] = color ;
// CEILING
color = texture [ ceilingTexture ] [ TEXTURE_WIDTH * ty + tx ] ;
pixels [ pixcoord ( x , screenHeight - y - 1 ) ] . out = color ;
color = ceilingTexture [ TEXTURE_WIDTH * ty + tx ] ;
pixels [ pixcoord ( x , screenHeight - y - 1 ) ] = color ;
}
}
}
void Raycaster : : render ( ) {
draw_ceiling_floor ( ) ;
cast_rays ( MAP ) ;
cast_rays ( ) ;
draw_pixel_buffer ( ) ;
$ window . display ( ) ;
}
bool Raycaster : : empty_space ( int new_x , int new_y ) {
dbc : : check ( ( size_t ) new_x < matrix : : width ( MAP ) ,
format ( " x={} too wide={} " , new_x , matrix : : width ( MAP ) ) ) ;
dbc : : check ( ( size_t ) new_y < matrix : : height ( MAP ) ,
format ( " y={} too high={} " , new_y , matrix : : height ( MAP ) ) ) ;
dbc : : check ( ( size_t ) new_x < matrix : : width ( $ map ) ,
format ( " x={} too wide={} " , new_x , matrix : : width ( $ map ) ) ) ;
dbc : : check ( ( size_t ) new_y < matrix : : height ( $ map ) ,
format ( " y={} too high={} " , new_y , matrix : : height ( $ map ) ) ) ;
return MAP [ new_y ] [ new_x ] = = 0 ;
return $ map [ new_y ] [ new_x ] = = 0 ;
}