adding loading screen

This commit is contained in:
2025-06-03 11:12:45 +02:00
parent 5910541b5c
commit 98dc056786
4 changed files with 111 additions and 49 deletions

View File

@@ -24,31 +24,12 @@ World::World(Scop::Scene& scene) : m_noisecollection(42), p_water_pipeline(std::
p_block_material = std::make_shared<Scop::Material>(material_params);
scene.LoadFont(GetResourcesPath() / "OpenSans_Bold.ttf", 32.0f);
Scop::Text& text = scene.CreateText("FPS:");
text.SetPosition(Scop::Vec2ui{ 30, 30 });
Scop::Text& fps_text = scene.CreateText("FPS:");
fps_text.SetPosition(Scop::Vec2ui{ 30, 30 });
std::thread(&World::GenerateWorld, this).detach();
Scop::Vec2ui32 loading_size;
Scop::Sprite& loading = scene.CreateSprite(std::make_shared<Scop::Texture>(Scop::LoadBMPFile(GetResourcesPath() / "loading.bmp", loading_size), loading_size.x, loading_size.y));
auto loading_update = [this, loading_size](Scop::NonOwningPtr<Scop::Scene> scene, Scop::NonOwningPtr<Scop::Sprite> sprite, Scop::Inputs& input, float delta)
{
if(!m_show_loading_screen && Scop::CommandLineInterface::Get().HasFlag("no-loading-screen"))
{
sprite->SetColor(Scop::Vec4f{ 0.0f });
return;
}
Scop::Vec2f scale = Scop::Vec2f{
static_cast<float>(Scop::ScopEngine::Get().GetWindow().GetWidth()) / static_cast<float>(loading_size.x),
static_cast<float>(Scop::ScopEngine::Get().GetWindow().GetHeight()) / static_cast<float>(loading_size.y),
};
sprite->SetScale(scale);
sprite->SetPosition(Scop::Vec2ui{ 0, 0 });
};
using sprite_hook = std::function<void(Scop::NonOwningPtr<Scop::Sprite>)>;
loading.AttachScript(std::make_shared<Scop::NativeSpriteScript>(sprite_hook{}, loading_update, sprite_hook{}));
SetupLoading();
auto narrator_update = [this](Scop::NonOwningPtr<Scop::Scene> scene, Scop::Inputs& input, float delta)
{
@@ -187,28 +168,52 @@ void World::GenerateWorld()
}
std::queue<std::reference_wrapper<Chunk>> mesh_generation_queue;
Scop::Vec2i x_range{ m_current_chunk_position.x - RENDER_DISTANCE - 1, m_current_chunk_position.x + RENDER_DISTANCE + 1 };
Scop::Vec2i z_range{ m_current_chunk_position.y - RENDER_DISTANCE - 1, m_current_chunk_position.y + RENDER_DISTANCE + 1 };
for(std::int32_t x = x_range.x; x <= x_range.y; x++)
{
for(std::int32_t z = z_range.x; z <= z_range.y; z++)
Scop::Vec2i x_range{ m_current_chunk_position.x - RENDER_DISTANCE - 1, m_current_chunk_position.x + RENDER_DISTANCE + 1 };
Scop::Vec2i z_range{ m_current_chunk_position.y - RENDER_DISTANCE - 1, m_current_chunk_position.y + RENDER_DISTANCE + 1 };
std::size_t range = (RENDER_DISTANCE + RENDER_DISTANCE + 2) * 2;
float progress = 0.0f;
m_loading_progress = 0;
float i = 0;
for(std::int32_t x = x_range.x; x <= x_range.y; x++, i++)
{
QUIT_CHECK();
auto res = m_chunks.try_emplace(Scop::Vec2i{ x, z }, *this, Scop::Vec2i{ x, z });
res.first->second.GenerateChunk();
if(!res.first->second.GetActor() && x > x_range.x && x < x_range.y && z > z_range.x && z < z_range.y)
mesh_generation_queue.push(std::ref(res.first->second));
for(std::int32_t z = z_range.x; z <= z_range.y; z++)
{
QUIT_CHECK();
auto res = m_chunks.try_emplace(Scop::Vec2i{ x, z }, *this, Scop::Vec2i{ x, z });
res.first->second.GenerateChunk();
progress = (i / range) * 30;
m_loading_progress = progress;
if(!res.first->second.GetActor() && x > x_range.x && x < x_range.y && z > z_range.x && z < z_range.y)
mesh_generation_queue.push(std::ref(res.first->second));
}
}
}
while(!mesh_generation_queue.empty())
{
QUIT_CHECK();
auto chunk = mesh_generation_queue.front();
mesh_generation_queue.pop();
chunk.get().GenerateMesh();
m_chunks_to_upload.Push(chunk);
float progress = 30.0f;
m_loading_progress = 30;
std::size_t range = mesh_generation_queue.size() - 30;
for(float i = 0.0f; !mesh_generation_queue.empty(); i++)
{
QUIT_CHECK();
auto chunk = mesh_generation_queue.front();
mesh_generation_queue.pop();
chunk.get().GenerateMesh();
m_chunks_to_upload.Push(chunk);
progress = ((i - 30.0f) / range) * 70;
m_loading_progress = progress + 30;
}
}
m_loading_progress = 100;
m_generation_status = GenerationState::Finished;
}
@@ -229,3 +234,65 @@ void World::Upload()
Scop::RenderCore::Get().WaitQueueIdle(KVF_GRAPHICS_QUEUE);
Scop::RenderCore::Get().ShouldStackSubmits(false);
}
void World::SetupLoading()
{
Scop::CPUBuffer default_pixels{ sizeof(std::uint32_t) };
default_pixels.GetDataAs<std::uint32_t>()[0] = 0xFFFFFFFF;
Scop::Sprite& progress_bar = m_scene.CreateSprite(std::make_shared<Scop::Texture>(std::move(default_pixels), 1, 1));
Scop::Text& loading_text = m_scene.CreateText("Loading...");
Scop::Vec2ui32 loading_size;
Scop::Sprite& loading = m_scene.CreateSprite(std::make_shared<Scop::Texture>(Scop::LoadBMPFile(GetResourcesPath() / "loading.bmp", loading_size), loading_size.x, loading_size.y));
auto loading_update = [this, loading_size, &progress_bar, &loading_text](Scop::NonOwningPtr<Scop::Scene> scene, Scop::NonOwningPtr<Scop::Sprite> sprite, Scop::Inputs& input, float delta)
{
static bool just_ended_loading = false;
static std::uint32_t last_percentage = 0;
if(!m_show_loading_screen || Scop::CommandLineInterface::Get().HasFlag("no-loading-screen"))
{
if(!just_ended_loading)
{
sprite->SetColor(Scop::Vec4f{ 0.0f });
progress_bar.SetColor(Scop::Vec4f{ 0.0f });
reinterpret_cast<Scop::FirstPerson3D*>(m_scene.GetCamera().get())->EnableCamera();
if(p_loading_text)
m_scene.RemoveText(*p_loading_text);
m_scene.RemoveText(loading_text);
m_scene.RemoveSprite(progress_bar);
just_ended_loading = true;
}
return;
}
reinterpret_cast<Scop::FirstPerson3D*>(m_scene.GetCamera().get())->DisableCamera();
Scop::Vec2f scale = Scop::Vec2f{
static_cast<float>(Scop::ScopEngine::Get().GetWindow().GetWidth()) / static_cast<float>(loading_size.x),
static_cast<float>(Scop::ScopEngine::Get().GetWindow().GetHeight()) / static_cast<float>(loading_size.y),
};
sprite->SetScale(scale);
sprite->SetPosition(Scop::Vec2ui{ 0, 0 });
if(last_percentage != m_loading_progress)
{
last_percentage = m_loading_progress;
if(p_loading_text)
m_scene.RemoveText(*p_loading_text);
p_loading_text = &m_scene.CreateText(std::to_string(m_loading_progress) + '%');
}
if(p_loading_text)
p_loading_text->SetPosition(Scop::Vec2ui{ (Scop::ScopEngine::Get().GetWindow().GetWidth() >> 1) + 70, (Scop::ScopEngine::Get().GetWindow().GetHeight() >> 1) - 55 });
loading_text.SetPosition(Scop::Vec2ui{ (Scop::ScopEngine::Get().GetWindow().GetWidth() >> 1) - 70, (Scop::ScopEngine::Get().GetWindow().GetHeight() >> 1) - 55 });
Scop::Vec2ui progress_size = Scop::Vec2ui{
static_cast<std::uint32_t>(static_cast<float>(m_loading_progress) * 4.0f),
25
};
progress_bar.SetScale(Scop::Vec2f(progress_size));
progress_bar.SetPosition(Scop::Vec2ui{ (Scop::ScopEngine::Get().GetWindow().GetWidth() >> 1) - 200, (Scop::ScopEngine::Get().GetWindow().GetHeight() >> 1) - (progress_size.y >> 1) + 25 });
};
using sprite_hook = std::function<void(Scop::NonOwningPtr<Scop::Sprite>)>;
loading.AttachScript(std::make_shared<Scop::NativeSpriteScript>(sprite_hook{}, loading_update, sprite_hook{}));
}

View File

@@ -47,6 +47,7 @@ class World
void UnloadChunks();
void GenerateWorld();
void Upload();
void SetupLoading();
private:
NoiseCollection m_noisecollection;
@@ -62,6 +63,8 @@ class World
Scop::Vec2i m_current_chunk_position;
std::atomic<GenerationState> m_generation_status = GenerationState::Ready;
Scop::NonOwningPtr<Scop::Text> p_fps_text;
Scop::NonOwningPtr<Scop::Text> p_loading_text;
std::atomic_uint32_t m_loading_progress = 0;
std::uint32_t m_last_fps_count = 0;
bool m_show_loading_screen = true;
};

View File

@@ -14,6 +14,9 @@ namespace Scop
void Update(class Inputs& input, float aspect, float timestep) override;
inline constexpr void EnableCamera() noexcept { m_inputs_blocked = false; }
inline constexpr void DisableCamera() noexcept { m_inputs_blocked = true; }
[[nodiscard]] inline constexpr std::string GetCameraType() override { return "FirstPerson3D"; }
[[nodiscard]] const Vec3f& GetPosition() const noexcept override { return m_position; }
[[nodiscard]] const Vec3f& GetUp() const noexcept { return c_up; }

View File

@@ -16,17 +16,6 @@ namespace Scop
m_view = Mat4f::LookAt(m_position, m_target, c_up);
m_proj = Mat4f::Perspective(RadianAnglef(m_fov), aspect, 0.1f, 100'000.f);
if(input.IsKeyPressed(SDL_SCANCODE_F1))
{
m_inputs_blocked = true;
input.ReleaseMouse();
}
if(input.IsKeyPressed(SDL_SCANCODE_F2))
{
m_inputs_blocked = false;
input.GrabMouse();
}
if(m_inputs_blocked)
return;