diff --git a/src/nyqubel-client/client.cpp b/src/nyqubel-client/client.cpp index bbcf031a7..16d3081d8 100644 --- a/src/nyqubel-client/client.cpp +++ b/src/nyqubel-client/client.cpp @@ -222,7 +222,7 @@ enum CardinalDirections { kDown*/ }; -class FalseChunk { +class FalseChunk { // TODO, Hurry and figure out how to render a 3x3 of chunks, then move it around to a different area. Get the whole "Treadmilling" correct! we need to hurry to deprecate this or at least figure out its purpose with the server/client code interactions. public: // "typedefs" or templates go here lol static constexpr std::size_t _chunk_array_size = cChunkDef::Width * cChunkDef::Width; @@ -502,7 +502,7 @@ public: BlockType GetVoxelType(std::size_t v) const { return raw_chunk_data[v]; } - class AxisIterator { + class AxisIterator { // missing the y axis bool end_flagged = false; ChunkVecType cur; @@ -598,7 +598,7 @@ public: glez::color::black // bedrock }; static constexpr bool gfx_mesher_debuglog = false; - std::vector MeshChunk(MesherComplexity cmplxity) const { + std::vector MeshSingleDepthLayerOfChunk(MesherComplexity cmplxity, int depth = 0) const { // Only good for the TOP/BOTTOM face of the bottom row. Doesnt check if air is in front of the face. bool is_chunk_only_air = this->IsEmpty(); if (is_chunk_only_air) return {}; // Your fault you didnt check it first... @@ -780,14 +780,14 @@ public: } }; -} // namespace qubel +namespace test { -class QubelMeshingTestWindow : public CBaseWindow { +class WindowSettings : public CBaseWindow { public: CCheckbox* activate; CCheckbox* wireframe; CDropdown* dropdown; - QubelMeshingTestWindow(IWidget* parent) + WindowSettings(IWidget* parent) : CBaseWindow(parent, "qubelmesh_test_settings") { this->always_visible = false; this->hover = false; @@ -819,45 +819,255 @@ public: this->Add("binary_meshing", false); } }; +} // namespace test +namespace two_d { +class SkyRenderer : public CBaseWidget { + static constexpr bool debug_log = false; -using namespace qubel; -class QubelMeshingTestRenderingWindow : public CBaseWindow { +public: + SkyRenderer(IWidget* parent) + : CBaseWidget("qubelmesh_test_renderer_skybox", parent) { + this->SetPositionMode(FLOATING); + this->zindex = -999; + + this->UpdateTime(23000); + if (debug_log) + PrintDebug(); + } + virtual void Update() override { + this->CBaseWidget::Update(); + const auto psize = this->GetParent()->GetSize(); + this->SetSize(psize.first, psize.second); + this->UpdateTime(this->curtime + 1); + if (debug_log) + PrintDebug(); + } + virtual void Draw(ICanvas* the_drawing_machine) override { + this->CBaseWidget::Draw(the_drawing_machine); + the_drawing_machine->Rect({ { 0, 0 }, this->GetSize() }, this->GetAtmosphereColor()); + } + void UpdateTime(int time_of_day) { + this->curtime = time_of_day; + this->cur_external_planetary_rotation_angle = CalcCelestialAngle(time_of_day); + this->brightness_modifier = CalcBrightnessModifier(this->GetCelestialAngle()); + this->base_color = CalcBaseColor(this->GetBrightnessModifier()); + this->fog_color = CalcFogColor(this->GetCelestialAngle()); + this->atmosphere_color = this->CalcAtmosphereColor(); + } + void PrintDebug() const { + auto PrintColor = [](const glez::rgba& clr) { + std::cout << "{ " << clr.r << ", " << clr.g << ", " << clr.b << ", " << clr.a << " }"; + }; + std::cout << "SkyboxDebug: " + << "\n Curtime: " << this->curtime + << "\n CelestialAngle: " << this->GetCelestialAngle() + << "\n BrightnessModifier: " << this->GetBrightnessModifier(); + + std::cout << "\n FogColor: "; + PrintColor(this->GetWorldFogColor()); + std::cout << "\n Base/SkyColor: "; + PrintColor(this->GetWorldSkyColor()); + std::cout << "\n AirColor: "; + PrintColor(this->GetAtmosphereColor()); + std::cout << std::endl; + } + + float GetBrightnessModifier() const { return this->brightness_modifier; } + const glez::rgba& GetWorldSkyColor() const { return this->base_color; } + const glez::rgba& GetWorldFogColor() const { return this->fog_color; } + const glez::rgba& GetAtmosphereColor() const { return this->atmosphere_color; } + +private: + float GetCelestialAngle() const { return this->cur_external_planetary_rotation_angle; } + int curtime; + float cur_external_planetary_rotation_angle; + float brightness_modifier; + glez::rgba base_color; // worldskycolor + glez::rgba fog_color; + glez::rgba atmosphere_color; + + // Thank you very much for these foundational findings TrueCraft <3 + // These algorithms are kinda hard to recreate and not rip out as is, its MIT so its supposidly safe to add. + // Please Please Please!!! Be sure to keep these credits as they put the impressive work in. + // https://github.com/ddevault/TrueCraft/blob/master/TrueCraft.Client/Modules/SkyModule.cs + static float CalcCelestialAngle(int time_of_day) { + float x = (time_of_day % 24000) / 24000.0f - 0.25f; + if (debug_log) + std::cout << "First X: " << x << std::endl; + if (x < 0) + x = 0; + if (x > 1) + x = 1; + return x + ((1 - (cos(x * glm::pi()) + 1) / 2) - x) / 3; + } + static glez::rgba CalcBaseColor(float brightness_modifier) { + constexpr float temp = 0.8f / 3; + const auto raw_color = glm::rgbColor(glm::vec3(0.6222222f - temp * 0.05f, 0.5f + temp * 0.1f, brightness_modifier)); + glez::rgba ret; + ret.r = raw_color.r; + ret.g = raw_color.g; + ret.b = raw_color.b; + ret.a = 1.0f; + return ret; + } + static float CalcBrightnessModifier(float celestial_angle) { + float mod = cos(celestial_angle * glm::two_pi()) * 2 + 0.5f; + if (mod < 0) + mod = 0; + if (mod > 1) + mod = 1; + return mod; + } + static glez::rgba CalcFogColor(float celestial_angle) { + const float y = cos(celestial_angle * glm::two_pi()) * 2 + 0.5f; + if (debug_log) + std::cout << "fog color y: " << y << std::endl; + glez::rgba fog_color; + fog_color.r = 0.7529412f * y * 0.94f + 0.06f; + fog_color.g = 0.8470588f * y * 0.94f + 0.06f; + fog_color.b = 1.0f * y * 0.91f + 0.09f; + fog_color.a = 1.0f; + return fog_color; + // TODO, Nether at a constant (0.2, 0.03, 0.03) + } + glez::rgba CalcAtmosphereColor() const { + constexpr float blend_factor = 0.29f; // TODO: Compute based on view distance + const auto blend = [&](float src, float dest) -> float { + return dest + (src - dest) * blend_factor; + }; + const auto &fog = this->GetWorldFogColor(), sky = this->GetWorldSkyColor(); + glez::rgba air_color; + air_color.r = blend(sky.r, fog.r); + air_color.g = blend(sky.g, fog.g); + air_color.b = blend(sky.b, fog.b); + air_color.a = 1.0f; + return air_color; + } +}; +} // namespace two_d + +namespace topdown { + +class ChunkRenderer : public CBaseWidget { +public: + static constexpr std::pair min_size = { 856, 480 }; + const FalseChunk* world_slice; + const test::WindowSettings* settings; + ChunkRenderer(IWidget* parent, test::WindowSettings* settings, FalseChunk* world_slice) + : CBaseWidget("qubelmesh_test_renderer_sceneoutput", parent) + , world_slice(world_slice) + , settings(settings) { + assert(settings && world_slice); + settings->dropdown->SetCallback([&](CDropdown*, int value) { + current_render_quads.clear(); + }); + this->SetSize(ChunkRenderer::min_size.first, ChunkRenderer::min_size.second); + } + std::vector current_render_quads; + virtual void Draw(ICanvas* the_drawing_machine) override { + this->CBaseWidget::Draw(the_drawing_machine); + const auto ConvertGLMVecToSTDPairVec = [](const geo::Vec2& vec_in) -> std::pair { + return std::pair(vec_in.x, vec_in.y); + }; + const auto ConvertGLMQuadToSTDPairQuad = [&](const geo::Box& box_in) -> Canvas::TranslationMatrix { + return Canvas::TranslationMatrix(ConvertGLMVecToSTDPairVec(box_in.origin), ConvertGLMVecToSTDPairVec(box_in.GetSize())); + }; + for (const FalseChunk::ChunkMeshedQuad& kinda_a_vert : current_render_quads) + the_drawing_machine->Rect(ConvertGLMQuadToSTDPairQuad(kinda_a_vert.quad), kinda_a_vert.clr); + if (this->settings->wireframe->Value()) { + for (const FalseChunk::ChunkMeshedQuad& kinda_a_vert : current_render_quads) { + the_drawing_machine->Rect({ ConvertGLMQuadToSTDPairQuad(kinda_a_vert.quad) }, glez::color::black, Canvas::RectType::Outline); + the_drawing_machine->Line({ ConvertGLMQuadToSTDPairQuad(kinda_a_vert.quad) }, glez::color::black); + } + } + } + virtual void Update() override { + this->CBaseWidget::Update(); + if (current_render_quads.empty()) { + if (world_slice->IsEmpty()) + return; + current_render_quads = world_slice->MeshSingleDepthLayerOfChunk(FalseChunk::MesherComplexity(settings->dropdown->Value())); + + if (FalseChunk::gfx_mesher_debuglog) { + std::pair found_size; + for (const FalseChunk::ChunkMeshedQuad& kinda_a_vert : current_render_quads) { + const auto max_coord = kinda_a_vert.quad.GetMax(); + if (max_coord.x > found_size.first) + found_size.first = max_coord.x; + if (max_coord.y > found_size.second) + found_size.second = max_coord.y; + } + std::cout << "Created mesh with pixel size: " << found_size.first << ", " << found_size.second << std::endl; + } + } + } +}; + +class RenderingWindow : public CBaseWindow { public: const CTitleBar* titlebar; - const QubelMeshingTestWindow* settings; + const test::WindowSettings* settings; FalseChunk world_slice; - class ChunkRenderer : public CBaseWidget { + two_d::SkyRenderer* skybox; + +public: + RenderingWindow(IWidget* parent, test::WindowSettings* settings) + : CBaseWindow(parent, "qubelmesh_test_renderer_frame") + , settings(settings) { + assert(settings); + this->always_visible = false; + this->hover = false; + this->SetPositionMode(PositionMode::FLOATING); + this->SetMaxSize(1270, 1000); + this->zindex = -999; + + titlebar = this->Add("QubelWorld Mesh Test uwu~"); + /*render_scene =*/this->Add(settings, &world_slice); + skybox = this->Add(); + } + ~RenderingWindow() { } + virtual bool AlwaysVisible() const override { + return this->settings->activate->Value(); + } + virtual bool IsVisible() const override { + return this->settings->activate->Value() && this->CBaseWindow::IsVisible(); + } +}; + +} // namespace topdown + +// Isometric needs some extra stuff to make it work at all. We need a way to render block textures to a isometric block represented as a texture. +// Once we have textures with these isoblocks, it should be a matter of positioning the texture in the correct spot for each block.. +// We will require this eventually for the block selector as well as a potential isometric renderer should we want to impliment it. +/*namespace isometric { + +class RenderingWindow : public CBaseWindow { +public: + const CTitleBar* titlebar; + const test::WindowSettings* settings; + + class IsometricBlockRenderer : public CBaseWidget { public: static constexpr std::pair min_size = { 856, 480 }; - const FalseChunk* world_slice; - const QubelMeshingTestWindow* settings; - ChunkRenderer(IWidget* parent, QubelMeshingTestWindow* settings, FalseChunk* world_slice) - : CBaseWidget("qubelmesh_test_renderer_sceneoutput", parent) - , world_slice(world_slice) + const QubelTestWindowSettings* settings; + glez::texture texture; + IsometricBlockRenderer(IWidget* parent, QubelTestWindowSettings* settings) + : CBaseWidget("qubelmesh_test_renderer_isometric_block_test", parent) , settings(settings) { assert(settings && world_slice); - settings->dropdown->SetCallback([&](CDropdown*, int value) { - current_render_quads.clear(); - }); - this->SetSize(ChunkRenderer::min_size.first, ChunkRenderer::min_size.second); + this->texture = glez::texture::loadFromMemory(embeded_logo_png_rgba.data.begin, embeded_logo_png_rgba.data.size, embeded_logo_png_rgba.width, embeded_logo_png_rgba.height); + this->SetSize(500, 500); } - std::vector current_render_quads; virtual void Draw(ICanvas* the_drawing_machine) override { this->CBaseWidget::Draw(the_drawing_machine); - const auto ConvertGLMVecToSTDPairVec = [](const geo::Vec2& vec_in) -> std::pair { - return std::pair(vec_in.x, vec_in.y); - }; - const auto ConvertGLMQuadToSTDPairQuad = [&](const geo::Box& box_in) -> Canvas::TranslationMatrix { - return Canvas::TranslationMatrix(ConvertGLMVecToSTDPairVec(box_in.origin), ConvertGLMVecToSTDPairVec(box_in.GetSize())); - }; - for (const FalseChunk::ChunkMeshedQuad& kinda_a_vert : current_render_quads) - the_drawing_machine->Rect(ConvertGLMQuadToSTDPairQuad(kinda_a_vert.quad), kinda_a_vert.clr); - if (this->settings->wireframe->Value()) { - for (const FalseChunk::ChunkMeshedQuad& kinda_a_vert : current_render_quads) { - the_drawing_machine->Rect({ ConvertGLMQuadToSTDPairQuad(kinda_a_vert.quad) }, glez::color::black, Canvas::RectType::Outline); - the_drawing_machine->Line({ ConvertGLMQuadToSTDPairQuad(kinda_a_vert.quad) }, glez::color::black); - } + o + TranslationMatrix + Offset(TranslationMatrix tm) { + return { this->offset + tm.first, tm.second }; + + // virtual void Rect(TranslationMatrix tm, glez::rgba color, glez::texture& tx) override { + this->parent->Rect({ tm->GetOffset() + tm.first, tm.second }, color, tx); } } virtual void Update() override { @@ -881,134 +1091,12 @@ public: } } }; - ChunkRenderer* render_scene; - class SkyRenderer : public CBaseWidget { - static constexpr bool debug_log = false; + IsometricBlockRenderer* renderer_isometric_block; - public: - SkyRenderer(IWidget* parent) - : CBaseWidget("qubelmesh_test_renderer_skybox", parent) { - this->SetPositionMode(FLOATING); - this->zindex = -999; - - this->UpdateTime(23000); - if (debug_log) - PrintDebug(); - } - virtual void Update() override { - this->CBaseWidget::Update(); - const auto psize = this->GetParent()->GetSize(); - this->SetSize(psize.first, psize.second); - this->UpdateTime(this->curtime + 1); - if (debug_log) - PrintDebug(); - } - virtual void Draw(ICanvas* the_drawing_machine) override { - this->CBaseWidget::Draw(the_drawing_machine); - the_drawing_machine->Rect({ { 0, 0 }, this->GetSize() }, this->GetAtmosphereColor()); - } - void UpdateTime(int time_of_day) { - this->curtime = time_of_day; - this->cur_external_planetary_rotation_angle = CalcCelestialAngle(time_of_day); - this->brightness_modifier = CalcBrightnessModifier(this->GetCelestialAngle()); - this->base_color = CalcBaseColor(this->GetBrightnessModifier()); - this->fog_color = CalcFogColor(this->GetCelestialAngle()); - this->atmosphere_color = this->CalcAtmosphereColor(); - } - void PrintDebug() const { - auto PrintColor = [](const glez::rgba& clr) { - std::cout << "{ " << clr.r << ", " << clr.g << ", " << clr.b << ", " << clr.a << " }"; - }; - std::cout << "SkyboxDebug: " - << "\n Curtime: " << this->curtime - << "\n CelestialAngle: " << this->GetCelestialAngle() - << "\n BrightnessModifier: " << this->GetBrightnessModifier(); - - std::cout << "\n FogColor: "; - PrintColor(this->GetWorldFogColor()); - std::cout << "\n Base/SkyColor: "; - PrintColor(this->GetWorldSkyColor()); - std::cout << "\n AirColor: "; - PrintColor(this->GetAtmosphereColor()); - std::cout << std::endl; - } - - float GetBrightnessModifier() const { return this->brightness_modifier; } - const glez::rgba& GetWorldSkyColor() const { return this->base_color; } - const glez::rgba& GetWorldFogColor() const { return this->fog_color; } - const glez::rgba& GetAtmosphereColor() const { return this->atmosphere_color; } - - private: - float GetCelestialAngle() const { return this->cur_external_planetary_rotation_angle; } - int curtime; - float cur_external_planetary_rotation_angle; - float brightness_modifier; - glez::rgba base_color; // worldskycolor - glez::rgba fog_color; - glez::rgba atmosphere_color; - - // Thank you very much for these foundational findings TrueCraft <3 - // These algorithms are kinda hard to recreate and not rip out as is, its MIT so its supposidly safe to add. - // Please Please Please!!! Be sure to keep these credits as they put the impressive work in. - // https://github.com/ddevault/TrueCraft/blob/master/TrueCraft.Client/Modules/SkyModule.cs - static float CalcCelestialAngle(int time_of_day) { - float x = (time_of_day % 24000) / 24000.0f - 0.25f; - if (debug_log) - std::cout << "First X: " << x << std::endl; - if (x < 0) - x = 0; - if (x > 1) - x = 1; - return x + ((1 - (cos(x * glm::pi()) + 1) / 2) - x) / 3; - } - static glez::rgba CalcBaseColor(float brightness_modifier) { - constexpr float temp = 0.8f / 3; - const auto raw_color = glm::rgbColor(glm::vec3(0.6222222f - temp * 0.05f, 0.5f + temp * 0.1f, brightness_modifier)); - glez::rgba ret; - ret.r = raw_color.r; - ret.g = raw_color.g; - ret.b = raw_color.b; - ret.a = 1.0f; - return ret; - } - static float CalcBrightnessModifier(float celestial_angle) { - float mod = cos(celestial_angle * glm::two_pi()) * 2 + 0.5f; - if (mod < 0) - mod = 0; - if (mod > 1) - mod = 1; - return mod; - } - static glez::rgba CalcFogColor(float celestial_angle) { - const float y = cos(celestial_angle * glm::two_pi()) * 2 + 0.5f; - if (debug_log) - std::cout << "fog color y: " << y << std::endl; - glez::rgba fog_color; - fog_color.r = 0.7529412f * y * 0.94f + 0.06f; - fog_color.g = 0.8470588f * y * 0.94f + 0.06f; - fog_color.b = 1.0f * y * 0.91f + 0.09f; - fog_color.a = 1.0f; - return fog_color; - // TODO, Nether at a constant (0.2, 0.03, 0.03) - } - glez::rgba CalcAtmosphereColor() const { - constexpr float blend_factor = 0.29f; // TODO: Compute based on view distance - const auto blend = [&](float src, float dest) -> float { - return dest + (src - dest) * blend_factor; - }; - const auto &fog = this->GetWorldFogColor(), sky = this->GetWorldSkyColor(); - glez::rgba air_color; - air_color.r = blend(sky.r, fog.r); - air_color.g = blend(sky.g, fog.g); - air_color.b = blend(sky.b, fog.b); - air_color.a = 1.0f; - return air_color; - } - }; - SkyRenderer* skybox; + SkyRenderer* renderer_skybox; public: - QubelMeshingTestRenderingWindow(IWidget* parent, QubelMeshingTestWindow* settings) + MeshingTestRenderingWindow(IWidget* parent, QubelMeshingTestWindow* settings) : CBaseWindow(parent, "qubelmesh_test_renderer_frame") , settings(settings) { assert(settings); @@ -1029,10 +1117,10 @@ public: virtual bool IsVisible() const override { return this->settings->activate->Value() && this->CBaseWindow::IsVisible(); } - -public: - // std::chrono::time_point last_update; }; +} // namespace isometric*/ + +} // namespace qubel int start_nyqubel_client() { auto client_rendering_thread = std::thread([&]() { @@ -1057,13 +1145,13 @@ int start_nyqubel_client() { canvas->Add()->SetOffset(500, 525); - auto mesh_test_settings_window = canvas->Add(); - auto mesh_test_rendering_window = canvas->Add(mesh_test_settings_window); - mesh_test_settings_window->SetOffset(2000, 400); - mesh_test_rendering_window->SetOffset(3000, 800); + auto test_settings_window = canvas->Add(); + auto rendering_window = canvas->Add(test_settings_window); + test_settings_window->SetOffset(2000, 400); + rendering_window->SetOffset(3000, 800); bool client_exiting = false; - mesh_test_settings_window->Add("exit_button", "Press to Quit-rite", [&](CBaseButton*) { + test_settings_window->Add("exit_button", "Press to Quit-rite", [&](CBaseButton*) { client_exiting = true; std::cout << "User Requested Client quit." << std::endl; });