#define _USE_MATH_DEFINES #include #include #include #include "utils.h" #include "tinyraycaster.h" int wall_x_texcoord(const float hitx, const float hity, const Texture &tex_walls) { float x = hitx - floor(hitx+.5); // x and y contain (signed) fractional parts of hitx and hity, float y = hity - floor(hity+.5); // they vary between -0.5 and +0.5, and one of them is supposed to be very close to 0 int tex = x*tex_walls.size; if (std::abs(y)>std::abs(x)) // we need to determine whether we hit a "vertical" or a "horizontal" wall (w.r.t the map) tex = y*tex_walls.size; if (tex<0) // do not forget x_texcoord can be negative, fix that tex += tex_walls.size; assert(tex>=0 && tex<(int)tex_walls.size); return tex; } void draw_map(FrameBuffer &fb, const std::vector &sprites, const Texture &tex_walls, const Map &map, const size_t cell_w, const size_t cell_h) { for (size_t j=0; j &depth_buffer, const Player &player, const Texture &tex_sprites) { // absolute direction from the player to the sprite (in radians) float sprite_dir = atan2(sprite.y - player.y, sprite.x - player.x); while (sprite_dir - player.a > M_PI) sprite_dir -= 2*M_PI; // remove unncesessary periods from the relative direction while (sprite_dir - player.a < -M_PI) sprite_dir += 2*M_PI; size_t sprite_screen_size = std::min(2000, static_cast(fb.h/sprite.player_dist)); // screen sprite size int h_offset = (sprite_dir - player.a)*(fb.w/2)/(player.fov) + (fb.w/2)/2 - sprite_screen_size/2; // do not forget the 3D view takes only a half of the framebuffer, thus fb.w/2 for the screen width int v_offset = fb.h/2 - sprite_screen_size/2; for (size_t i=0; i=fb.w/2) continue; if (depth_buffer[h_offset+i]=fb.h) continue; uint32_t color = tex_sprites.get(i*tex_sprites.size/sprite_screen_size, j*tex_sprites.size/sprite_screen_size, sprite.tex_id); uint8_t r,g,b,a; unpack_color(color, r, g, b, a); if (a>128) fb.set_pixel(fb.w/2 + h_offset+i, v_offset+j, color); } } } void render(FrameBuffer &fb, const GameState &gs) { const Map &map = gs.map; const Player &player = gs.player; const std::vector &sprites = gs.monsters; const Texture &tex_walls = gs.tex_walls; const Texture &tex_monst = gs.tex_monst; fb.clear(pack_color(255, 255, 255)); // clear the screen const size_t cell_w = fb.w/(map.w*2); // size of one map cell on the screen const size_t cell_h = fb.h/map.h; std::vector depth_buffer(fb.w/2, 1e3); for (size_t i=0; i column = tex_walls.get_scaled_column(texid, x_texcoord, column_height); int pix_x = i + fb.w/2; // we are drawing at the right half of the screen, thus +fb.w/2 for (size_t j=0; j=0 && pix_y<(int)fb.h) { fb.set_pixel(pix_x, pix_y, column[j]); } } break; } // ray marching loop } // field of view ray sweeping draw_map(fb, sprites, tex_walls, map, cell_w, cell_h); for (size_t i=0; i