Major speed up in rendering by only doing it when we move, but drawing the rendered 3d view texture constantly.

master
Zed A. Shaw 10 months ago
parent 0260e3d345
commit b43553a563
  1. 1
      assets/enemies.json
  2. 5
      gui_fsm.cpp
  3. 10
      main_ui.cpp
  4. 3
      main_ui.hpp
  5. 32
      raycaster.cpp
  6. 2
      raycaster.hpp
  7. 3
      status_ui.cpp

@ -21,7 +21,6 @@
}, },
{"_type": "Combat", "hp": 20, "max_hp": 20, "damage": 1, "dead": false}, {"_type": "Combat", "hp": 20, "max_hp": 20, "damage": 1, "dead": false},
{"_type": "Motion", "dx": 0, "dy": 0, "random": false}, {"_type": "Motion", "dx": 0, "dy": 0, "random": false},
{"_type": "LightSource", "strength": 40, "radius": 1.2},
{"_type": "EnemyConfig", "hearing_distance": 5}, {"_type": "EnemyConfig", "hearing_distance": 5},
{"_type": "Sprite", "name": "armored_knight"} {"_type": "Sprite", "name": "armored_knight"}
] ]

@ -248,6 +248,9 @@ namespace gui {
case KEY::Escape: case KEY::Escape:
event(Event::CLOSE); event(Event::CLOSE);
break; break;
case KEY::Space:
event(Event::ATTACK);
break;
case KEY::P: case KEY::P:
$main_ui.debug(); $main_ui.debug();
break; break;
@ -259,9 +262,9 @@ namespace gui {
} }
void FSM::draw_gui() { void FSM::draw_gui() {
$main_ui.draw();
$status_ui.draw($window); $status_ui.draw($window);
$combat_ui.draw($window); $combat_ui.draw($window);
$main_ui.draw();
} }
void FSM::render() { void FSM::render() {

@ -65,13 +65,15 @@ namespace gui {
$rayview.init_shaders(); $rayview.init_shaders();
$rayview.set_position(RAY_VIEW_X, RAY_VIEW_Y); $rayview.set_position(RAY_VIEW_X, RAY_VIEW_Y);
$rayview.position_camera($player.x + 0.5, $player.y + 0.5); $rayview.position_camera($player.x + 0.5, $player.y + 0.5);
$overlay_ui.render(); $overlay_ui.render();
} }
void MainUI::draw() { void MainUI::draw() {
auto start = std::chrono::high_resolution_clock::now(); auto start = std::chrono::high_resolution_clock::now();
if($needs_render) $rayview.render();
$rayview.draw($window); $rayview.draw($window);
auto end = std::chrono::high_resolution_clock::now(); auto end = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration<double>(end - start); auto elapsed = std::chrono::duration<double>(end - start);
$stats.sample(1/elapsed.count()); $stats.sample(1/elapsed.count());
@ -85,16 +87,20 @@ namespace gui {
} }
bool MainUI::play_rotate() { bool MainUI::play_rotate() {
return $camera.play_rotate($rayview); bool done = $camera.play_rotate($rayview);
$needs_render = !done;
return done;
} }
// this could be an optional that returs a Point // this could be an optional that returs a Point
std::optional<Point> MainUI::play_move() { std::optional<Point> MainUI::play_move() {
if($camera.play_move($rayview)) { if($camera.play_move($rayview)) {
$needs_render = false;
return std::make_optional<Point>({ return std::make_optional<Point>({
size_t($camera.target_x), size_t($camera.target_x),
size_t($camera.target_y)}); size_t($camera.target_y)});
} else { } else {
$needs_render = true;
return std::nullopt; return std::nullopt;
} }
} }

@ -11,6 +11,7 @@ namespace gui {
class MainUI { class MainUI {
public: public:
bool $needs_render = true;
Point $player{0,0}; Point $player{0,0};
Stats $stats; Stats $stats;
sf::RenderWindow& $window; sf::RenderWindow& $window;
@ -26,9 +27,9 @@ namespace gui {
void draw_stats(); void draw_stats();
void draw_blood(); void draw_blood();
std::optional<Point> play_move();
void plan_rotate(int dir); void plan_rotate(int dir);
bool play_rotate(); bool play_rotate();
std::optional<Point> play_move();
Point plan_move(int dir, bool strafe); Point plan_move(int dir, bool strafe);
void abort_plan(); void abort_plan();

@ -23,6 +23,11 @@ union ColorConv {
uint32_t as_int; uint32_t as_int;
}; };
/* It's hard to believe, but this is faster than any bitfiddling
* I could devise. Just use a union with a struct, do the math
* and I guess the compiler can handle it better than shifting
* bits around.
*/
inline uint32_t new_lighting(uint32_t pixel, int level) { inline uint32_t new_lighting(uint32_t pixel, int level) {
float factor = level * PERCENT; float factor = level * PERCENT;
@ -38,8 +43,7 @@ Raycaster::Raycaster(int width, int height) :
$view_texture(sf::Vector2u{(unsigned int)width, (unsigned int)height}), $view_texture(sf::Vector2u{(unsigned int)width, (unsigned int)height}),
$view_sprite($view_texture), $view_sprite($view_texture),
$width(width), $height(height), $width(width), $height(height),
$zbuffer(width), $zbuffer(width)
$anim(256, 256, 10, "assets/monster-1.ogg")
{ {
$view_sprite.setPosition({0, 0}); $view_sprite.setPosition({0, 0});
$pixels = make_unique<RGBA[]>($width * $height); $pixels = make_unique<RGBA[]>($width * $height);
@ -99,6 +103,7 @@ void Raycaster::sprite_casting(sf::RenderTarget &target) {
// calculate width the the sprite // calculate width the the sprite
// same as height of sprite, given that it's square // same as height of sprite, given that it's square
int sprite_width = abs(int($height / transform_y)); int sprite_width = abs(int($height / transform_y));
// CUT
int draw_start_x = -sprite_width / 2 + sprite_screen_x; int draw_start_x = -sprite_width / 2 + sprite_screen_x;
if(draw_start_x < 0) draw_start_x = 0; if(draw_start_x < 0) draw_start_x = 0;
@ -119,8 +124,6 @@ void Raycaster::sprite_casting(sf::RenderTarget &target) {
//calculate lowest and highest pixel to fill in current stripe //calculate lowest and highest pixel to fill in current stripe
int draw_start_y = -sprite_height / 2 + $height / 2; int draw_start_y = -sprite_height / 2 + $height / 2;
if(draw_start_y < 0) draw_start_y = 0; if(draw_start_y < 0) draw_start_y = 0;
int draw_end_y = sprite_height / 2 + $height / 2;
if(draw_end_y >= $height) draw_end_y = $height - 1;
int tex_x = int(texture_width * (draw_start_x - (-sprite_width / 2 + sprite_screen_x)) * texture_width / sprite_width) / texture_width; int tex_x = int(texture_width * (draw_start_x - (-sprite_width / 2 + sprite_screen_x)) * texture_width / sprite_width) / texture_width;
int tex_render_width = tex_x_end - tex_x; int tex_render_width = tex_x_end - tex_x;
@ -130,14 +133,22 @@ void Raycaster::sprite_casting(sf::RenderTarget &target) {
float x = float(draw_start_x + $screen_pos_x); float x = float(draw_start_x + $screen_pos_x);
float y = float(draw_start_y + $screen_pos_y); float y = float(draw_start_y + $screen_pos_y);
float sprite_w = float(sprite_width) / float(texture_width);
float sprite_h = float(sprite_height) / float(texture_height); if(x < $screen_pos_x) fmt::println("X < rayview left bounds");
if(y < $screen_pos_y) fmt::println("Y < rayview top bounds");
if(x >= SCREEN_WIDTH) fmt::println("OUT OF BOUNDS X");
if(y >= $height) fmt::println("OUT OF BOUNDS Y");
float sprite_scale_w = float(sprite_width) / float(texture_width);
float sprite_scale_h = float(sprite_height) / float(texture_height);
int d = y * texture_height - $height * half_height + sprite_height * half_height; int d = y * texture_height - $height * half_height + sprite_height * half_height;
int tex_y = ((d * texture_height) / sprite_height) / texture_height; int tex_y = ((d * texture_height) / sprite_height) / texture_height;
sf_sprite->setScale({sprite_w, sprite_h}); sf_sprite->setScale({sprite_scale_w, sprite_scale_h});
$anim.step(*sf_sprite, tex_x, tex_y, tex_render_width, texture_height); sf_sprite->setTextureRect(sf::IntRect({
{tex_x, tex_y},
{tex_render_width, texture_height}}));
sf_sprite->setPosition({x, y}); sf_sprite->setPosition({x, y});
$brightness.setUniform("offsetFactor", sf::Glsl::Vec2{0.0f, 0.0f}); $brightness.setUniform("offsetFactor", sf::Glsl::Vec2{0.0f, 0.0f});
@ -333,10 +344,13 @@ void Raycaster::draw_ceiling_floor() {
} }
} }
void Raycaster::draw(sf::RenderTarget& target) { void Raycaster::render() {
draw_ceiling_floor(); draw_ceiling_floor();
cast_rays(); cast_rays();
draw_pixel_buffer(); draw_pixel_buffer();
}
void Raycaster::draw(sf::RenderTarget& target) {
target.draw($view_sprite); target.draw($view_sprite);
sprite_casting(target); sprite_casting(target);
} }

@ -39,7 +39,6 @@ struct Raycaster {
Matrix $map; Matrix $map;
std::unordered_map<DinkyECS::Entity, textures::SpriteTexture> $sprites; std::unordered_map<DinkyECS::Entity, textures::SpriteTexture> $sprites;
std::vector<double> $zbuffer; // width std::vector<double> $zbuffer; // width
Animator $anim;
Raycaster(int width, int height); Raycaster(int width, int height);
@ -47,6 +46,7 @@ struct Raycaster {
void draw_ceiling_floor(); void draw_ceiling_floor();
void draw_pixel_buffer(); void draw_pixel_buffer();
void sprite_casting(sf::RenderTarget& target); void sprite_casting(sf::RenderTarget& target);
void render();
void draw(sf::RenderTarget& target); void draw(sf::RenderTarget& target);
void sort_sprites(std::vector<int>& order, std::vector<double>& dist, int amount); void sort_sprites(std::vector<int>& order, std::vector<double>& dist, int amount);

@ -17,8 +17,7 @@ namespace gui {
"[button7 | button8 | button9]" "[button7 | button8 | button9]"
"[*%(100,300)log_view]" "[*%(100,300)log_view]"
"[_]" "[_]"
"[_]" "[_]");
);
} }
void StatusUI::render() { void StatusUI::render() {