Initial Client Implimented in GUI.
The code is implimented in this commit and is launchable with the BUILD_CLIENT compile option. Everything should be launchable by running the one function within src/nyqubel-client/client.hpp: start_nyqubel_client()
This commit is contained in:
parent
88809475cc
commit
0606ca3008
11
.gitmodules
vendored
11
.gitmodules
vendored
@ -65,3 +65,14 @@
|
||||
[submodule "lib/libdeflate"]
|
||||
path = lib/libdeflate
|
||||
url = https://github.com/cuberite/libdeflate
|
||||
[submodule "lib/libpdw"]
|
||||
path = lib/libpdw
|
||||
url = https://github.com/oneechanhax/libpdw
|
||||
branch = async
|
||||
[submodule "lib/libglez"]
|
||||
path = lib/libglez
|
||||
url = https://github.com/oneechanhax/libglez
|
||||
branch = rainbow
|
||||
[submodule "lib/libhydride"]
|
||||
path = lib/libhydride
|
||||
url = https://github.com/oneechanhax/libhydride
|
||||
|
@ -31,6 +31,9 @@ function(build_dependencies)
|
||||
# Enumerate all submodule libraries
|
||||
# SQLiteCpp needs to be included before sqlite so the lsqlite target is available:
|
||||
set(DEPENDENCIES expat fmt jsoncpp libdeflate libevent mbedtls SQLiteCpp)
|
||||
if (BUILD_CLIENT)
|
||||
set(DEPENDENCIES ${DEPENDENCIES} libglez libhydride libpdw)
|
||||
endif()
|
||||
foreach(DEPENDENCY ${DEPENDENCIES})
|
||||
# Check that the libraries are present:
|
||||
if (NOT EXISTS "${PROJECT_SOURCE_DIR}/lib/${DEPENDENCY}/CMakeLists.txt")
|
||||
@ -42,6 +45,7 @@ function(build_dependencies)
|
||||
# (mbedTLS also has test and example programs in their CMakeLists.txt, we don't want those):
|
||||
add_subdirectory("lib/${DEPENDENCY}" EXCLUDE_FROM_ALL)
|
||||
endforeach()
|
||||
|
||||
endfunction()
|
||||
|
||||
function(link_dependencies TARGET)
|
||||
@ -80,4 +84,24 @@ function(link_dependencies TARGET)
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES FreeBSD)
|
||||
target_link_libraries(${TARGET} PRIVATE kvm)
|
||||
endif()
|
||||
|
||||
if(BUILD_CLIENT)
|
||||
set(OpenGL_GL_PREFERENCE "GLVND")
|
||||
find_package(PNG REQUIRED) # We need to link all this again since we prebuilt them staticly
|
||||
find_package(GLEW REQUIRED)
|
||||
find_package(OpenGL REQUIRED)
|
||||
find_package(X11 REQUIRED)
|
||||
find_package(Freetype REQUIRED)
|
||||
|
||||
target_include_directories(
|
||||
${TARGET} SYSTEM PRIVATE
|
||||
lib/libpdw/include
|
||||
)
|
||||
|
||||
target_link_libraries(${TARGET} PRIVATE
|
||||
libpdw
|
||||
hydride
|
||||
glez
|
||||
${PNG_LIBRARIES} GL GLU GLEW ${FREETYPE_LIBRARIES} ${X11_X11_LIB} ${X11_Xext_LIB} ${X11_Xfixes_LIB})
|
||||
endif()
|
||||
endfunction()
|
||||
|
@ -1,4 +1,4 @@
|
||||
# This is the top-level CMakeLists.txt file for the Cuberite project
|
||||
|
||||
#
|
||||
# Use CMake to generate the build files for your platform
|
||||
|
||||
@ -11,6 +11,7 @@ project(
|
||||
LANGUAGES C CXX
|
||||
)
|
||||
|
||||
option(BUILD_CLIENT "Sets up the build to create a client rather than a server. This is in tesing and will result in a hybrid server/client setup." OFF)
|
||||
option(BUILD_TOOLS "Sets up additional executables to be built along with the server" OFF)
|
||||
option(BUILD_UNSTABLE_TOOLS "Sets up yet more executables to be built, these can be broken and generally are obsolete" OFF)
|
||||
option(NO_NATIVE_OPTIMIZATION "Disables CPU-specific optimisations for the current machine, allows use on other CPUs of the same platform" OFF)
|
||||
|
BIN
client-resources/logo.png
Normal file
BIN
client-resources/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 55 KiB |
BIN
client-resources/logo.xcf
Normal file
BIN
client-resources/logo.xcf
Normal file
Binary file not shown.
BIN
client-resources/opensans.ttf
Normal file
BIN
client-resources/opensans.ttf
Normal file
Binary file not shown.
1
lib/libglez
Submodule
1
lib/libglez
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 221db8e9721510449e7f14a644410b8c7aead09c
|
1
lib/libhydride
Submodule
1
lib/libhydride
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 30659e1877f036b090bafc1a1e76170b88ab9fda
|
1
lib/libpdw
Submodule
1
lib/libpdw
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 9cbc0a088d5e65a498c4ddab2beeb8643a76a865
|
@ -152,6 +152,7 @@ set(FOLDERS
|
||||
Generating HTTP Items mbedTLS++ Mobs Noise
|
||||
OSSupport Physics Protocol Registries Simulator
|
||||
Simulator/IncrementalRedstoneSimulator UI WorldStorage
|
||||
nyqubel-client
|
||||
)
|
||||
|
||||
# Add all child source directories:
|
||||
|
10
src/Root.cpp
10
src/Root.cpp
@ -67,7 +67,9 @@
|
||||
#include "Logger.h"
|
||||
#include "ClientHandle.h"
|
||||
|
||||
|
||||
#ifdef NYQUBEL_CLIENT
|
||||
#include "nyqubel-client/client.hpp"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@ -145,6 +147,12 @@ bool cRoot::Run(cSettingsRepositoryInterface & a_OverridesRepo)
|
||||
|
||||
LoadGlobalSettings();
|
||||
|
||||
#ifdef NYQUBEL_CLIENT
|
||||
start_nyqubel_client();
|
||||
|
||||
return s_NextState == NextState::Restart;
|
||||
#endif
|
||||
|
||||
LOG("Creating new server instance...");
|
||||
m_Server = new cServer();
|
||||
|
||||
|
14
src/nyqubel-client/CMakeLists.txt
Normal file
14
src/nyqubel-client/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
||||
if(BUILD_CLIENT)
|
||||
|
||||
target_sources(
|
||||
${CMAKE_PROJECT_NAME} PRIVATE
|
||||
client.cpp
|
||||
client.hpp
|
||||
|
||||
util/geometry.cpp
|
||||
util/geometry.hpp
|
||||
)
|
||||
|
||||
target_compile_definitions(${CMAKE_PROJECT_NAME} PUBLIC "-DNYQUBEL_CLIENT=1")
|
||||
|
||||
endif()
|
953
src/nyqubel-client/client.cpp
Normal file
953
src/nyqubel-client/client.cpp
Normal file
@ -0,0 +1,953 @@
|
||||
|
||||
/*
|
||||
* Libpdw: Primitives Done Well!
|
||||
* Copyright (C) 2022 Rebekah Rowe
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <bitset>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
#include <embed_resources.hpp>
|
||||
#include <glez/detail/render.hpp>
|
||||
#include <glez/color.hpp>
|
||||
#include <glez/draw.hpp>
|
||||
#include <glez/glez.hpp>
|
||||
|
||||
#include <hydride.h>
|
||||
|
||||
// xorg conflict
|
||||
#undef RootWindow
|
||||
|
||||
#include "libpdw/gui/widgets/slider.hpp"
|
||||
#include "libpdw/gui/widgets/titlebar.hpp"
|
||||
#include "libpdw/gui/canvas.hpp"
|
||||
#include "libpdw/gui/widgets/basebutton.hpp"
|
||||
#include "libpdw/gui/widgets/basewindow.hpp"
|
||||
#include "libpdw/gui/widgets/checkbox.hpp"
|
||||
#include "libpdw/gui/widgets/dropdown.hpp"
|
||||
|
||||
#include "libpdw/gui/ncc/logo.hpp"
|
||||
|
||||
namespace x11 {
|
||||
|
||||
using RawKey = decltype(XK_2);
|
||||
constexpr std::pair<std::string_view, RawKey> key_dict[] = { { "0", XK_0 }, { "1", XK_1 }, { "2", XK_2 },
|
||||
{ "3", XK_3 }, { "4", XK_4 }, { "5", XK_5 },
|
||||
{ "6", XK_6 }, { "7", XK_7 }, { "8", XK_8 },
|
||||
{ "9", XK_9 }, { "a", XK_A }, { "b", XK_B },
|
||||
{ "c", XK_C }, { "d", XK_D }, { "e", XK_E },
|
||||
{ "f", XK_F }, { "g", XK_G }, { "h", XK_H },
|
||||
{ "i", XK_I }, { "j", XK_J }, { "k", XK_K },
|
||||
{ "l", XK_L }, { "m", XK_M }, { "n", XK_N },
|
||||
{ "o", XK_O }, { "p", XK_P }, { "q", XK_Q },
|
||||
{ "r", XK_R }, { "s", XK_S }, { "t", XK_T },
|
||||
{ "u", XK_U }, { "v", XK_V }, { "w", XK_W },
|
||||
{ "x", XK_X }, { "y", XK_Y }, { "z", XK_Z },
|
||||
|
||||
{ "escape", XK_Escape }, { "{", XK_bracketleft },
|
||||
{ "}", XK_bracketright }, { ";", XK_semicolon },
|
||||
{ "'", XK_apostrophe }, { ",", XK_apostrophe },
|
||||
{ ".", XK_period }, { "/", XK_slash },
|
||||
{ "\\", XK_backslash }, { "minus", XK_minus },
|
||||
{ "=", XK_equal }, { "return", XK_Return },
|
||||
{ "space", XK_space }, { "backspace", XK_BackSpace },
|
||||
{ "tab", XK_Tab }, { "capslock", XK_Caps_Lock },
|
||||
|
||||
{ "insert", XK_Insert },
|
||||
{ "delete", XK_Delete },
|
||||
{ "home", XK_Home }, { "end", XK_End },
|
||||
{ "pageup", XK_Page_Up }, { "pagedown", XK_Page_Down },
|
||||
|
||||
{ "shift_r", XK_Shift_L }, { "shift_r", XK_Shift_R },
|
||||
{ "alt_l", XK_Alt_L }, { "alt_r", XK_Alt_R },
|
||||
{ "control_l", XK_Control_L }, { "control_l", XK_Control_R },
|
||||
|
||||
{ "0_pad", XK_KP_0 }, { "1_pad", XK_KP_1 }, { "2_pad", XK_KP_2 },
|
||||
{ "3_pad", XK_KP_3 }, { "4_pad", XK_KP_4 }, { "5_pad", XK_KP_5 },
|
||||
{ "6_pad", XK_KP_6 }, { "7_pad", XK_KP_7 }, { "8_pad", XK_KP_8 },
|
||||
{ "9_pad", XK_KP_9 },
|
||||
|
||||
{ "/_pad", XK_KP_Divide }, { "*_pad", XK_KP_Multiply },
|
||||
{ "-_pad", XK_KP_Subtract }, { "+_pad", XK_KP_Add },
|
||||
{ "enter_pad", XK_KP_Enter }, { "._pad", XK_KP_Decimal },
|
||||
|
||||
{ "up", XK_Up }, { "left", XK_Left },
|
||||
{ "down", XK_Down }, { "right", XK_Right },
|
||||
|
||||
{ "f1", XK_F1 }, { "f2", XK_F2 }, { "f3", XK_F3 },
|
||||
{ "f4", XK_F4 }, { "f5", XK_F5 }, { "f6", XK_F6 },
|
||||
{ "f7", XK_F7 }, { "f8", XK_F8 }, { "f9", XK_F9 },
|
||||
{ "f10", XK_F10 }, { "f11", XK_F11 }, { "f12", XK_F12 },
|
||||
|
||||
//{ "mouse_1", XK_Pointer_DfltBtnPrev },
|
||||
//{ "mouse_2", XK_Pointer_DfltBtnNext }
|
||||
{ "mouse_wheel_up", XK_Pointer_DfltBtnPrev },
|
||||
{ "mouse_wheel_down", XK_Pointer_DfltBtnNext } };
|
||||
constexpr auto key_dict_size = []() {
|
||||
std::size_t ret = 0;
|
||||
for (auto i : key_dict)
|
||||
ret++;
|
||||
return ret;
|
||||
}();
|
||||
std::pair<std::pair<int, int>, std::bitset<3>> QueryPointer(decltype(hydride_library.display) dis, decltype(hydride_library.window) win) {
|
||||
Window root_return, child_return;
|
||||
std::pair<int, int> mouse, root;
|
||||
unsigned int mask_return;
|
||||
if (!XQueryPointer(hydride_library.display, hydride_library.window, &root_return, &child_return, &root.first, &root.second, &mouse.first, &mouse.second, &mask_return))
|
||||
throw std::runtime_error("Unable to query pointer from X11");
|
||||
|
||||
std::bitset<3> ret_buttons;
|
||||
ret_buttons[0] = (mask_return & (Button1Mask));
|
||||
ret_buttons[1] = (mask_return & (Button2Mask));
|
||||
ret_buttons[2] = (mask_return & (Button3Mask));
|
||||
return { mouse, ret_buttons };
|
||||
}
|
||||
|
||||
using Keymap = std::array<char, 32>;
|
||||
bool PickFromKeymap(decltype(hydride_library.display) dis, Keymap map, decltype(XK_2) k) {
|
||||
int current_key = XKeysymToKeycode(dis, k);
|
||||
return (map[current_key / 8] & (1 << (current_key % 8)));
|
||||
}
|
||||
Keymap QueryKeymap(decltype(hydride_library.display) dis) {
|
||||
Keymap keys;
|
||||
XQueryKeymap(dis, keys.data());
|
||||
return keys;
|
||||
}
|
||||
bool QueryKey(decltype(hydride_library.display) dis, decltype(XK_2) k) {
|
||||
auto map = QueryKeymap(dis);
|
||||
return PickFromKeymap(dis, map, k);
|
||||
}
|
||||
|
||||
template <int size>
|
||||
class ChangeDetector { // generate async from sync
|
||||
std::pair<int, int> previous_mouse { -1, -1 };
|
||||
std::pair<int, int> previous_bounds { -1, -1 };
|
||||
std::bitset<size> previous_states;
|
||||
|
||||
public:
|
||||
ChangeDetector() {
|
||||
this->previous_states.reset();
|
||||
}
|
||||
bool UpdateKey(std::size_t k, bool state) {
|
||||
if (state == previous_states[k]) // Just to prevent issues, idk if we need this at runtime ;-;
|
||||
return false;
|
||||
previous_states.set(k, state);
|
||||
return true;
|
||||
}
|
||||
decltype(previous_mouse) UpdateMouse(const decltype(previous_mouse)& state) {
|
||||
if (state == previous_mouse) // Just to prevent issues, idk if we need this at runtime ;-;
|
||||
return { 0, 0 };
|
||||
|
||||
decltype(previous_mouse) delta = { state.first - previous_mouse.first, state.second - previous_mouse.second };
|
||||
previous_mouse = state;
|
||||
return delta;
|
||||
}
|
||||
decltype(previous_bounds) UpdateBounds(const decltype(previous_bounds)& state) {
|
||||
if (state == previous_bounds) // Just to prevent issues, idk if we need this at runtime ;-;
|
||||
return { 0, 0 };
|
||||
|
||||
decltype(previous_bounds) delta = { state.first - previous_bounds.first, state.second - previous_bounds.second };
|
||||
previous_bounds = state;
|
||||
return delta;
|
||||
}
|
||||
};
|
||||
|
||||
class X11Poller {
|
||||
ChangeDetector<key_dict_size> async_gen;
|
||||
decltype(hydride_library.display) display;
|
||||
decltype(hydride_library.window) window;
|
||||
|
||||
public:
|
||||
X11Poller(decltype(hydride_library.display) display, decltype(hydride_library.window) window)
|
||||
: display(display)
|
||||
, window(window) {
|
||||
UpdateKeys();
|
||||
UpdateMouse();
|
||||
}
|
||||
std::vector<std::pair<std::string_view, bool>> UpdateKeys() {
|
||||
auto km = QueryKeymap(display);
|
||||
|
||||
std::vector<std::pair<std::string_view, bool>> ret;
|
||||
for (std::size_t i = 0; i < key_dict_size; i++) {
|
||||
bool key_state = PickFromKeymap(display, km, key_dict[i].second);
|
||||
if (async_gen.UpdateKey(i, key_state))
|
||||
ret.push_back({ key_dict[i].first, key_state });
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
std::tuple<std::pair<int, int>, std::pair<int, int>, std::bitset<3>> UpdateMouse() {
|
||||
auto pointer_info = QueryPointer(this->display, this->window);
|
||||
|
||||
auto delta = async_gen.UpdateMouse(pointer_info.first);
|
||||
return { pointer_info.first, delta, pointer_info.second };
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace x11
|
||||
|
||||
#include "util/geometry.hpp"
|
||||
|
||||
namespace qubel {
|
||||
|
||||
enum VoxelTypes {
|
||||
kAir,
|
||||
kStone,
|
||||
kDirt,
|
||||
kSand,
|
||||
kGrass
|
||||
};
|
||||
|
||||
enum CardinalDirections {
|
||||
kNorth,
|
||||
kSouth,
|
||||
kEast,
|
||||
kWest // ,
|
||||
/*kUp,
|
||||
kDown*/
|
||||
};
|
||||
|
||||
class Chunk {
|
||||
public:
|
||||
// "typedefs" or templates go here lol
|
||||
static constexpr uint _dim_length = 2; // its in 2d!
|
||||
static constexpr uint _size_in_power = 16; // 8x8 size
|
||||
static constexpr std::size_t _chunk_array_size = _size_in_power * _size_in_power;
|
||||
|
||||
using BlockType = uint8_t;
|
||||
// Using a single digit to locate the exact voxel's byte in the chunk, for very fast use.
|
||||
using ChunkDataType = std::array<uint8_t, _chunk_array_size>;
|
||||
using ChunkVecType = geo::internal::BVec2<uint8_t>;
|
||||
ChunkDataType raw_chunk_data = {
|
||||
kStone,
|
||||
kStone,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kStone,
|
||||
kStone,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kGrass,
|
||||
kGrass,
|
||||
kGrass,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kGrass,
|
||||
kDirt,
|
||||
kDirt,
|
||||
kDirt,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kGrass,
|
||||
kGrass,
|
||||
kDirt,
|
||||
kDirt,
|
||||
kDirt,
|
||||
kDirt,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kSand,
|
||||
kSand,
|
||||
kDirt,
|
||||
kDirt,
|
||||
kDirt,
|
||||
kStone,
|
||||
kStone,
|
||||
kStone,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kSand,
|
||||
kSand,
|
||||
kDirt,
|
||||
kDirt,
|
||||
kStone,
|
||||
kStone,
|
||||
kStone,
|
||||
kStone,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kSand,
|
||||
kAir,
|
||||
kSand,
|
||||
kAir,
|
||||
kSand,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kSand,
|
||||
kAir,
|
||||
kSand,
|
||||
kAir,
|
||||
kSand,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kSand,
|
||||
kAir,
|
||||
kSand,
|
||||
kAir,
|
||||
kSand,
|
||||
kAir,
|
||||
kSand,
|
||||
kAir,
|
||||
kSand,
|
||||
kAir,
|
||||
kSand,
|
||||
kAir,
|
||||
kSand,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kSand,
|
||||
kAir,
|
||||
kSand,
|
||||
kAir,
|
||||
kAir,
|
||||
kSand,
|
||||
kAir,
|
||||
kSand,
|
||||
kAir,
|
||||
kAir,
|
||||
kSand,
|
||||
kAir,
|
||||
kSand,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kSand,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kSand,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kAir,
|
||||
kStone,
|
||||
};
|
||||
class LocalVoxel {
|
||||
public:
|
||||
std::size_t pos; // yes a single integer, x y and z can all exist due to the way chunking keeps it localized and x + (z * 64) means the values co-exist.
|
||||
// LocalVoxel(geo::internal::BVec2<uint8_t> raw_chunk_pos)
|
||||
//: pos(raw_chunk_pos) { }
|
||||
static LocalVoxel GetVoxelFromPosInChunk(geo::internal::BVec2<uint8_t> in_pos) { // basicly your 2d/3d position to a index, make sure ur in the chunk! lol
|
||||
assert(in_pos.x < _size_in_power && in_pos.y < _size_in_power);
|
||||
LocalVoxel index;
|
||||
index.pos = 0;
|
||||
return index.AddPos(in_pos);
|
||||
}
|
||||
LocalVoxel& AddPos(geo::internal::BVec2<uint8_t> in_pos) {
|
||||
this->pos += in_pos.x;
|
||||
this->pos += in_pos.y * _size_in_power;
|
||||
// if constexpr (_dim_length >= 3) // We gotta move these to a seperate class all-together... do this once the templates are split.
|
||||
// index.pos += in_pos.z * (_size_in_power * _size_in_power);
|
||||
return *this;
|
||||
}
|
||||
ChunkVecType ExtractVec() {
|
||||
ChunkVecType ret_pos;
|
||||
ret_pos.x = this->pos % _size_in_power;
|
||||
ret_pos.y = (this->pos / _size_in_power) % _size_in_power;
|
||||
// ret_pos.z = ((this->pos / _size_in_power) / _size_in_power) % _size_in_power;
|
||||
return ret_pos;
|
||||
}
|
||||
// tmp, TODO replace/add with chunk pointer or chunk x and y... both??? oof if so
|
||||
// need good way to keep the handle associated.
|
||||
// Local HANDLES AND "standard voxel"/global voxel in other words one for chunk and one inheriting with the extra details? ah genious!
|
||||
};
|
||||
static LocalVoxel GetVoxelFromPosInChunk(geo::internal::BVec2<uint8_t> in_pos) {
|
||||
return LocalVoxel::GetVoxelFromPosInChunk(in_pos);
|
||||
}
|
||||
BlockType GetVoxelType(LocalVoxel v) {
|
||||
return raw_chunk_data[v.pos];
|
||||
}
|
||||
class AxisIterator {
|
||||
public:
|
||||
bool end_flagged = false;
|
||||
ChunkVecType cur;
|
||||
using VecMaskType = glm::bvec2;
|
||||
const VecMaskType mask, reverse_mask; // stick it in reverse spongebob!
|
||||
constexpr AxisIterator(const ChunkVecType& src, glm::bvec2 mask, glm::bvec2 reverse_mask = { false, false })
|
||||
: cur(src)
|
||||
, mask(mask)
|
||||
, reverse_mask(reverse_mask) { }
|
||||
AxisIterator& operator++(int) {
|
||||
// new_iter.cur.AddPos(this->GetPosToAdd()); we cant do this cause we have to test it ;-;
|
||||
this->cur += this->GetPosToAdd();
|
||||
if (!IsPosValidWithinChunk(this->cur))
|
||||
this->end_flagged = true;
|
||||
return *this;
|
||||
}
|
||||
bool operator==(const AxisIterator& other) const {
|
||||
if (other.end_flagged)
|
||||
return this->end_flagged;
|
||||
|
||||
return other.cur == this->cur && other.mask == this->mask && other.reverse_mask == this->reverse_mask;
|
||||
}
|
||||
bool operator!=(const AxisIterator& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
static constexpr AxisIterator end() {
|
||||
AxisIterator ret({}, {});
|
||||
ret.end_flagged = true;
|
||||
return ret;
|
||||
}
|
||||
ChunkVecType GetPosToAdd() const {
|
||||
ChunkVecType pos_to_add = { 0, 0 };
|
||||
if (mask.x)
|
||||
pos_to_add.x = 1;
|
||||
if (mask.y)
|
||||
pos_to_add.y = 1;
|
||||
if (reverse_mask.x && pos_to_add.x)
|
||||
pos_to_add.x = -pos_to_add.x;
|
||||
if (reverse_mask.y && pos_to_add.y)
|
||||
pos_to_add.y = -pos_to_add.y;
|
||||
return pos_to_add;
|
||||
}
|
||||
static constexpr auto CreateCardinalMask(const CardinalDirections dir) {
|
||||
VecMaskType mask = { false, false }, reverse_mask = { false, false };
|
||||
switch (dir) {
|
||||
case CardinalDirections::kNorth:
|
||||
reverse_mask.y = true;
|
||||
case CardinalDirections::kSouth:
|
||||
mask.y = true;
|
||||
break;
|
||||
case CardinalDirections::kWest:
|
||||
reverse_mask.x = true;
|
||||
case CardinalDirections::kEast:
|
||||
mask.x = true;
|
||||
break;
|
||||
default:
|
||||
throw std::logic_error("Trying to access a cardinal Direction that does not work!");
|
||||
}
|
||||
return std::make_pair(mask, reverse_mask);
|
||||
}
|
||||
};
|
||||
enum MesherComplexity {
|
||||
kPlain,
|
||||
kNieve,
|
||||
kGreedy, // Just expand same type faces
|
||||
kIntrinsicGreedy, // Using bitwise operations :O
|
||||
kGlobalLattice // literally Impossible to recreate, meshing everything INCLUDING air, and rendering it straight up in shader
|
||||
};
|
||||
static constexpr float box_size = 25.0f;
|
||||
// glez::vertex not verbose enough for us sadly...
|
||||
struct ChunkMeshedQuad {
|
||||
geo::Box<geo::Vec2> quad;
|
||||
glez::rgba clr;
|
||||
};
|
||||
static constexpr glez::rgba chunk_textures[] = {
|
||||
glez::rgba(0, 0, 0, 0),
|
||||
glez::rgba(40, 40, 40),
|
||||
glez::rgba(120, 40, 40),
|
||||
glez::color::yellow,
|
||||
glez::color::green
|
||||
};
|
||||
std::vector<ChunkMeshedQuad> MeshChunk(MesherComplexity cmplxity) {
|
||||
std::vector<ChunkMeshedQuad> finished_quads;
|
||||
std::cout << "Start Meshing: ";
|
||||
auto start_time = std::chrono::high_resolution_clock::now();
|
||||
switch (cmplxity) {
|
||||
case MesherComplexity::kNieve: // I dont think this is possible in 2d for the time being...
|
||||
case MesherComplexity::kPlain: {
|
||||
std::cout << "Plain" << std::endl;
|
||||
for (uint dim_x = 0; dim_x < _size_in_power; dim_x++) {
|
||||
for (uint dim_y = 0; dim_y < _size_in_power; dim_y++) {
|
||||
LocalVoxel cube = GetVoxelFromPosInChunk({ dim_x, dim_y });
|
||||
auto type = this->GetVoxelType(cube);
|
||||
if (type == VoxelTypes::kAir)
|
||||
continue;
|
||||
ChunkMeshedQuad new_face;
|
||||
auto start = geo::Vec2(dim_x * box_size, dim_y * box_size);
|
||||
// auto end = /*start +*/ geo::Vec2(box_size, box_size);
|
||||
auto size = /*start +*/ geo::Vec2(box_size, box_size);
|
||||
new_face.quad = geo::Box<geo::Vec2>(start, size);
|
||||
new_face.clr = chunk_textures[type];
|
||||
|
||||
finished_quads.push_back(new_face);
|
||||
std::cout << " *Added quad! : {" << start.x << ", " << start.y << "} with size {" << size.x << ", " << size.y << "}" << std::endl;
|
||||
}
|
||||
}
|
||||
std::cout << "Plain ";
|
||||
break;
|
||||
}
|
||||
/*case MesherComplexity::kNieve: {
|
||||
|
||||
} */
|
||||
case MesherComplexity::kGreedy: {
|
||||
std::cout << "Greedy" << std::endl;
|
||||
std::bitset<_chunk_array_size> chunk_finished_checksum;
|
||||
auto FindOpenSpace = [&]() -> std::pair<std::size_t, std::optional<decltype(chunk_finished_checksum)::reference>> {
|
||||
for (std::size_t x = 0; x < _size_in_power; x++) {
|
||||
for (std::size_t y = 0; y < _size_in_power; y++) {
|
||||
auto vox = this->GetVoxelFromPosInChunk({ x, y });
|
||||
if (!chunk_finished_checksum[vox.pos])
|
||||
return { vox.pos, chunk_finished_checksum[vox.pos] };
|
||||
}
|
||||
}
|
||||
return { std::size_t(-1), {} };
|
||||
};
|
||||
while (!chunk_finished_checksum.all()) {
|
||||
auto unmeshed_face = FindOpenSpace();
|
||||
if (!unmeshed_face.second.has_value())
|
||||
throw std::logic_error("Greedy ChunkMesher checksum thinks there is a unmeshed chunk but unable to find it!");
|
||||
|
||||
LocalVoxel cube;
|
||||
cube.pos = unmeshed_face.first;
|
||||
auto type = this->GetVoxelType(cube);
|
||||
if (type == VoxelTypes::kAir) {
|
||||
chunk_finished_checksum[cube.pos] = true;
|
||||
continue;
|
||||
}
|
||||
{
|
||||
auto ext_cube = cube.ExtractVec();
|
||||
std::cout << "Greedy found Seed block \"" << (int)type << "\": {" << (int)ext_cube.x << ", " << (int)ext_cube.y << "}" << std::endl;
|
||||
}
|
||||
|
||||
ChunkVecType block_quad_size = { 1, 1 };
|
||||
auto src_block_loc = cube.ExtractVec();
|
||||
|
||||
// Need a better "search line down" func... instead of one block we need to check multiple and return how many are the same.
|
||||
constexpr auto south_dir_mask = AxisIterator::CreateCardinalMask(CardinalDirections::kSouth);
|
||||
auto SearchLineSouthForSameTypes = [&](ChunkVecType src_line, std::uint8_t max_size = _size_in_power) -> std::uint8_t {
|
||||
std::size_t alike_counter = 0;
|
||||
const auto end = AxisIterator::end();
|
||||
for (auto axis_crawl = AxisIterator(src_line, south_dir_mask.first, south_dir_mask.second); axis_crawl != end; axis_crawl++) {
|
||||
LocalVoxel block_to_check = GetVoxelFromPosInChunk(axis_crawl.cur);
|
||||
auto below_block_type = this->GetVoxelType(block_to_check);
|
||||
if (below_block_type != type)
|
||||
break;
|
||||
if (chunk_finished_checksum[block_to_check.pos])
|
||||
break;
|
||||
alike_counter++;
|
||||
if (alike_counter >= max_size)
|
||||
break;
|
||||
}
|
||||
return alike_counter;
|
||||
};
|
||||
auto same_blocks_south_count = SearchLineSouthForSameTypes(src_block_loc);
|
||||
assert(same_blocks_south_count);
|
||||
block_quad_size.y = same_blocks_south_count;
|
||||
|
||||
std::cout << " Found blocks going south: " << (int)block_quad_size.y << std::endl;
|
||||
|
||||
auto SearchLineEastForSameTypes = [&]() -> std::uint8_t {
|
||||
std::size_t alike_counter = 1;
|
||||
const auto end = AxisIterator::end();
|
||||
constexpr auto east_dir_mask = AxisIterator::CreateCardinalMask(CardinalDirections::kEast);
|
||||
auto side_axis_crawl = AxisIterator(src_block_loc, east_dir_mask.first, east_dir_mask.second);
|
||||
side_axis_crawl++; // starting one ahead
|
||||
// if (side_axis_crawl != end) {
|
||||
std::cout << " Searching More East!!" << std::endl;
|
||||
for (; side_axis_crawl != end; side_axis_crawl++) {
|
||||
LocalVoxel side_block_to_check = GetVoxelFromPosInChunk(side_axis_crawl.cur);
|
||||
auto below_block_type = this->GetVoxelType(side_block_to_check);
|
||||
if (below_block_type != type)
|
||||
break;
|
||||
|
||||
// here we go again, dip down to this max length
|
||||
auto additional_same_blocks_south_count = SearchLineSouthForSameTypes(side_axis_crawl.cur, same_blocks_south_count);
|
||||
assert(additional_same_blocks_south_count <= same_blocks_south_count);
|
||||
if (additional_same_blocks_south_count < same_blocks_south_count)
|
||||
break;
|
||||
alike_counter++;
|
||||
}
|
||||
//}
|
||||
return alike_counter;
|
||||
};
|
||||
if (src_block_loc.x + 1 < _size_in_power) { // only if we have room to check!
|
||||
auto same_blocks_east_count = SearchLineEastForSameTypes();
|
||||
block_quad_size.x = same_blocks_east_count;
|
||||
std::cout << " Found blocks going east: " << (int)block_quad_size.x << std::endl;
|
||||
}
|
||||
|
||||
ChunkMeshedQuad new_face;
|
||||
auto start = geo::Vec2(src_block_loc.x * box_size, src_block_loc.y * box_size);
|
||||
auto size = geo::Vec2(block_quad_size.x * box_size, block_quad_size.y * box_size);
|
||||
|
||||
new_face.quad = geo::Box<geo::Vec2>(start, size);
|
||||
new_face.clr = chunk_textures[type];
|
||||
std::cout << " *Added quad! : {" << start.x << ", " << start.y << "} with size {" << size.x << ", " << size.y << "}" << std::endl;
|
||||
finished_quads.push_back(new_face);
|
||||
|
||||
auto MarkAreaFinished = [&](ChunkVecType origin, ChunkVecType size) {
|
||||
assert(size.x && size.y);
|
||||
for (std::size_t x = 0; x < size.x; x++) {
|
||||
for (std::size_t y = 0; y < size.y; y++) {
|
||||
auto block_to_clear = origin + ChunkVecType(x, y);
|
||||
std::cout << " ------Marking Block Finished: {" << (int)block_to_clear.x << ", " << (int)block_to_clear.y << "}" << std::endl;
|
||||
chunk_finished_checksum[this->GetVoxelFromPosInChunk(block_to_clear).pos] = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
MarkAreaFinished(src_block_loc, block_quad_size);
|
||||
// mark it off of the chunk_finished_checksum by setting the chunk_finished_checksum[i] to 1
|
||||
}
|
||||
std::cout << "Greedy ";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Do nothing, no fail just no-op any mesher un-implimented.
|
||||
break;
|
||||
};
|
||||
auto end_time = std::chrono::high_resolution_clock::now(); // Calculate duration and convert to milliseconds
|
||||
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time).count();
|
||||
std::cout << "Meshing Finished!!! QuadCount: " << (int)finished_quads.size() << ", Within: " << duration << " microseconds" << std::endl;
|
||||
|
||||
return finished_quads;
|
||||
}
|
||||
static bool IsPosValidWithinChunk(ChunkVecType voxel_loc) {
|
||||
if (voxel_loc.x >= _size_in_power)
|
||||
return false;
|
||||
if (voxel_loc.y >= _size_in_power)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace qubel
|
||||
|
||||
class QubelMeshingTestWindow : public CBaseWindow {
|
||||
public:
|
||||
CCheckbox* activate;
|
||||
CCheckbox* wireframe;
|
||||
CDropdown* dropdown;
|
||||
QubelMeshingTestWindow(IWidget* parent)
|
||||
: CBaseWindow(parent, "qubelmesh_test_settings") {
|
||||
this->always_visible = false;
|
||||
this->hover = false;
|
||||
this->SetMaxSize(1270, 1000);
|
||||
this->SetPositionMode(PositionMode::FLOATING);
|
||||
|
||||
this->Add<CTitleBar>("~SimpleQubelMeshingTester~");
|
||||
|
||||
this->Add<CTextLabel>("activate_label", "Activate Viewing:");
|
||||
activate = this->Add<CCheckbox>("activate", false);
|
||||
|
||||
this->Add<CTextLabel>("spread_label", "VoxelSpread:");
|
||||
this->Add<CSlider>("spread")->SetStep(0.1f);
|
||||
|
||||
this->Add<CTextLabel>("wireframe_label", "Wireframe Mesh:");
|
||||
wireframe = this->Add<CCheckbox>("wireframe", true);
|
||||
|
||||
this->Add<CTextLabel>("wanted_mesher_label", "Meshing Algorithm:");
|
||||
dropdown = this->Add<CDropdown>("wanted_mesher");
|
||||
dropdown->AddValue("NoFaceOcclusion, Plain");
|
||||
dropdown->AddValue("Nieve");
|
||||
dropdown->AddValue("Greedy"); // Just expand same type faces
|
||||
dropdown->AddValue("Intrinsic Greedy"); // Using bitwise operations :O
|
||||
dropdown->AddValue("Global Lattice"); // literally Impossible to recreate, meshing everything INCLUDING air, and rendering it straight up in shader
|
||||
dropdown->SetSize(150, 16);
|
||||
dropdown->SetValue(2);
|
||||
|
||||
this->Add<CTextLabel>("binary_meshing_label", "Binary Meshing(ignore types):");
|
||||
this->Add<CCheckbox>("binary_meshing", false);
|
||||
}
|
||||
};
|
||||
|
||||
using namespace qubel;
|
||||
class QubelMeshingTestRenderingWindow : public CBaseWindow {
|
||||
public:
|
||||
const CTitleBar* titlebar;
|
||||
const QubelMeshingTestWindow* settings;
|
||||
Chunk world_slice;
|
||||
|
||||
class ChunkRenderer : public CBaseWidget {
|
||||
public:
|
||||
Chunk* world_slice;
|
||||
QubelMeshingTestWindow* settings;
|
||||
ChunkRenderer(IWidget* parent, QubelMeshingTestWindow* settings, Chunk* world_slice)
|
||||
: CBaseWidget("qubelmesh_test_renderer_sceneoutput", parent)
|
||||
, settings(settings)
|
||||
, world_slice(world_slice) {
|
||||
assert(settings && world_slice);
|
||||
settings->dropdown->SetCallback([&](CDropdown*, int value) {
|
||||
current_render_quads.clear();
|
||||
});
|
||||
}
|
||||
std::vector<Chunk::ChunkMeshedQuad> 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<int, int> {
|
||||
return std::pair<int, int>(vec_in.x, vec_in.y);
|
||||
};
|
||||
const auto ConvertGLMQuadToSTDPairQuad = [&](const geo::Box<geo::Vec2>& box_in) -> Canvas::TranslationMatrix {
|
||||
return Canvas::TranslationMatrix(ConvertGLMVecToSTDPairVec(box_in.origin), ConvertGLMVecToSTDPairVec(box_in.GetSize()));
|
||||
};
|
||||
for (const Chunk::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 Chunk::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()) {
|
||||
current_render_quads = world_slice->MeshChunk(Chunk::MesherComplexity(settings->dropdown->Value()));
|
||||
|
||||
std::pair<int, int> found_size;
|
||||
for (const Chunk::ChunkMeshedQuad& kinda_a_vert : current_render_quads) {
|
||||
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;
|
||||
this->SetSize(found_size.first, found_size.second);
|
||||
}
|
||||
}
|
||||
};
|
||||
ChunkRenderer* render_scene;
|
||||
|
||||
public:
|
||||
QubelMeshingTestRenderingWindow(IWidget* parent, QubelMeshingTestWindow* 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<CTitleBar>("QubelWorld Mesh Test uwu~");
|
||||
render_scene = this->Add<ChunkRenderer>(settings, &world_slice);
|
||||
}
|
||||
~QubelMeshingTestRenderingWindow() { }
|
||||
virtual bool AlwaysVisible() const override {
|
||||
return this->settings->activate->Value();
|
||||
}
|
||||
virtual bool IsVisible() const override {
|
||||
return this->settings->activate->Value() && this->CBaseWindow::IsVisible();
|
||||
}
|
||||
|
||||
public:
|
||||
// std::chrono::time_point<std::chrono::system_clock> last_update;
|
||||
};
|
||||
|
||||
int start_nyqubel_client() {
|
||||
hydride_init();
|
||||
|
||||
glez::init(hydride_library.width, hydride_library.height);
|
||||
|
||||
Canvas* canvas;
|
||||
x11::X11Poller x11_poller(hydride_library.display, hydride_library.window);
|
||||
{
|
||||
input::RefreshInput();
|
||||
|
||||
hydride_draw_begin();
|
||||
glez::begin();
|
||||
|
||||
canvas = new Canvas();
|
||||
canvas->Setup();
|
||||
|
||||
glez::end();
|
||||
hydride_draw_end();
|
||||
}
|
||||
|
||||
canvas->Add<ncc::Logo>()->SetOffset(500, 525);
|
||||
|
||||
auto mesh_test_settings_window = canvas->Add<QubelMeshingTestWindow>();
|
||||
auto mesh_test_rendering_window = canvas->Add<QubelMeshingTestRenderingWindow>(mesh_test_settings_window);
|
||||
mesh_test_settings_window->SetOffset(2000, 400);
|
||||
mesh_test_rendering_window->SetOffset(3000, 800);
|
||||
|
||||
bool client_exiting = false;
|
||||
mesh_test_settings_window->Add<CBaseButton>("exit_button", "Press to Quit-rite", [&](CBaseButton*) {
|
||||
client_exiting = true;
|
||||
std::cout << "User Requested Client quit." << std::endl;
|
||||
});
|
||||
|
||||
// Need a 856/480 size window.
|
||||
|
||||
hydride_show();
|
||||
while (1) {
|
||||
input::RefreshInput();
|
||||
// Must be called in that order.
|
||||
hydride_draw_begin();
|
||||
glez::begin();
|
||||
{
|
||||
x11_poller.UpdateKeys();
|
||||
x11_poller.UpdateMouse();
|
||||
|
||||
canvas->Update();
|
||||
}
|
||||
glez::end();
|
||||
hydride_draw_end();
|
||||
|
||||
if (client_exiting)
|
||||
break;
|
||||
}
|
||||
std::cout << "Client is Exiting!!!" << std::endl;
|
||||
return 0;
|
||||
}
|
4
src/nyqubel-client/client.hpp
Normal file
4
src/nyqubel-client/client.hpp
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
int start_nyqubel_client();
|
88
src/nyqubel-client/util/geometry.cpp
Normal file
88
src/nyqubel-client/util/geometry.cpp
Normal file
@ -0,0 +1,88 @@
|
||||
|
||||
/*
|
||||
* Nekohook: Free, fast and modular cheat software
|
||||
* Copyright (C) 2018 Rebekah Rowe
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <cstdlib> // rand()
|
||||
|
||||
#include "geometry.hpp"
|
||||
|
||||
namespace qubel::geo::internal {
|
||||
|
||||
Angle2& Angle2::Clamp() {
|
||||
|
||||
while (this->x > 89.0f) this->x -= 180.0f;
|
||||
while (this->x < -89.0f) this->x += 180.0f;
|
||||
|
||||
while (this->y > 180.0f) this->y -= 360.0f;
|
||||
while (this->y < -180.0f) this->y += 360.0f;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Returns angles to a point in space
|
||||
AngleBase<2> AngleBase<2>::PointTo(const Vec3& src_point, const Vec3& dest_point) {
|
||||
Vec3 aim_point = dest_point - src_point;
|
||||
|
||||
Angle2 out;
|
||||
out.y = atan2(aim_point.y, aim_point.x) * 180.0f / F_PI;
|
||||
out.x = atan2(0, sqrt(aim_point.x * aim_point.x + aim_point.y * aim_point.y)) * 180.0f / F_PI;
|
||||
|
||||
return out.Clamp();
|
||||
}
|
||||
|
||||
// A function to get the difference from angles, Please make sure inputs are
|
||||
// clamped
|
||||
AngleBase<2> AngleBase<2>::GetDelta(const AngleBase<2>& dest_angles) const {
|
||||
// Our output difference
|
||||
Angle2 diff;
|
||||
|
||||
// Yaw
|
||||
if (this->y != dest_angles.y) {
|
||||
// Check if yaw is on opposing poles
|
||||
if (this->y < -90 && dest_angles.y > 90)
|
||||
diff.y = this->y + 360 - dest_angles.y;
|
||||
else if (this->y > 90 && dest_angles.y < -90)
|
||||
diff.y = dest_angles.y + 360 - this->y;
|
||||
else
|
||||
diff.y = std::abs(this->y - dest_angles.y);
|
||||
}
|
||||
// Pitch
|
||||
if (this->x != dest_angles.x) diff.x = std::abs(this->x - dest_angles.x);
|
||||
|
||||
return diff;
|
||||
}
|
||||
// Use input angles and our eye position to get fov to a destination point
|
||||
float AngleBase<2>::GetFov(const Vec3& src, const Vec3& dest) const {
|
||||
return this->GetFov(PointTo(src, dest));
|
||||
}
|
||||
float AngleBase<2>::GetFov(const AngleBase<2>& pointed_angle) const {
|
||||
Angle2 delta = this->GetDelta(pointed_angle);
|
||||
return std::max<float>(delta.x, delta.y);
|
||||
}
|
||||
|
||||
Vec3 DirectionalMove(const Vec3& src, const AngleBase<2>& dir, float amt) {
|
||||
// Math I dont understand
|
||||
float sp = sinf(dir.x * F_PI / 180.f);
|
||||
float cp = cosf(dir.x * F_PI / 180.f);
|
||||
float sy = sinf(dir.y * F_PI / 180.f);
|
||||
float cy = cosf(dir.y * F_PI / 180.f);
|
||||
|
||||
return Vec3(cp * cy, cp * sy, -sp) * amt + src;
|
||||
}
|
||||
|
||||
} // namespace neko::math
|
475
src/nyqubel-client/util/geometry.hpp
Normal file
475
src/nyqubel-client/util/geometry.hpp
Normal file
@ -0,0 +1,475 @@
|
||||
|
||||
/*
|
||||
* Nekohook: Free, fast and modular cheat software
|
||||
* Copyright (C) 2018 Rebekah Rowe
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#include <glm/detail/qualifier.hpp>
|
||||
#include <glm/fwd.hpp>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/constants.hpp>
|
||||
#include <glm/geometric.hpp>
|
||||
|
||||
namespace qubel::geo {
|
||||
|
||||
namespace internal {
|
||||
|
||||
#if true // NEKOHOOK_GFX == opengl
|
||||
template <int _dim_length, typename T>
|
||||
using BVec = glm::vec<_dim_length, T>;
|
||||
template <typename T>
|
||||
using BVec2 = glm::vec<2, T>;
|
||||
template <typename T>
|
||||
using BVec3 = glm::vec<3, T>;
|
||||
using Vec2 = glm::vec2;
|
||||
using Vec3 = glm::vec3;
|
||||
using DVec3 = glm::dvec3;
|
||||
using IVec2 = glm::ivec2;
|
||||
using UVec2 = glm::uvec2;
|
||||
|
||||
constexpr float F_PI = glm::pi<float>();
|
||||
|
||||
template <class... T>
|
||||
auto Distance(T... in) { return glm::distance(in...); }
|
||||
|
||||
template <typename T>
|
||||
auto GetMaskOfVec2(const T& src, glm::bvec2 mask) {
|
||||
T ret = { 0, 0 };
|
||||
if (mask.x)
|
||||
ret.x = src.x;
|
||||
if (mask.y)
|
||||
ret.y = src.y;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T, int _length>
|
||||
class BoxBase;
|
||||
|
||||
template <typename T>
|
||||
class BoxBase<T, 2> {
|
||||
static_assert(T::length() == 2);
|
||||
|
||||
protected:
|
||||
BoxBase() { }
|
||||
BoxBase(T _first, T _second)
|
||||
: first(_first)
|
||||
, second(_second) { }
|
||||
|
||||
public:
|
||||
// TODO, rotation around origin?
|
||||
|
||||
// Data
|
||||
union {
|
||||
T first, origin;
|
||||
};
|
||||
union {
|
||||
T second, size;
|
||||
};
|
||||
|
||||
T GetMax() const { return this->origin + this->size; }
|
||||
T GetSize() const { return this->size; }
|
||||
|
||||
T GetPoint(int idx) const {
|
||||
switch (idx) {
|
||||
case 0:
|
||||
return this->origin;
|
||||
case 1:
|
||||
return { this->origin.x + this->size.x, this->origin.y };
|
||||
case 2:
|
||||
return { this->origin.x, this->origin.y + this->size.y };
|
||||
case 3:
|
||||
return this->origin + this->size;
|
||||
default:
|
||||
throw std::logic_error("Unknown point idx: " + std::to_string(idx));
|
||||
}
|
||||
}
|
||||
std::array<T, 4> GetPoints() const {
|
||||
T max = this->GetMax();
|
||||
return {
|
||||
this->origin,
|
||||
{ max.x, this->origin.y },
|
||||
{ this->origin.x, max.y },
|
||||
max
|
||||
};
|
||||
}
|
||||
|
||||
bool Contains(T in) const {
|
||||
if (in.x > this->origin.x && in.y > this->origin.y) {
|
||||
T max = this->GetMax();
|
||||
return (in.x < max.x && in.x < max.y);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SegmentIntersects(T src, T dest) const {
|
||||
if ((dest.x > this->min.x && src.x > this->min.x) && (dest.y > this->min.y && src.y > this->min.y)) {
|
||||
T max = this->GetMax();
|
||||
return (dest.x < max.x && src.x < max.x) || (dest.y < max.y && src.y < max.y);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
enum class Direction {
|
||||
kUp,
|
||||
kDown,
|
||||
kLeft,
|
||||
kRight,
|
||||
kPosX = kRight,
|
||||
kPosY = kDown,
|
||||
kNegX = kLeft,
|
||||
kNegY = kUp
|
||||
};
|
||||
void Expand(Direction dir, int amt) { // TODO: Bitmongering(nopey)
|
||||
switch (dir) {
|
||||
case Direction::kUp:
|
||||
this->origin.y -= amt;
|
||||
case Direction::kDown:
|
||||
this->size.y += amt;
|
||||
break;
|
||||
case Direction::kLeft:
|
||||
this->origin.x -= amt;
|
||||
case Direction::kRight:
|
||||
this->size.x += amt;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
void ExpandTo(T v) {
|
||||
if (this->origin.x > v.x)
|
||||
this->Expand(Direction::kNegX, this->origin.x - v.x);
|
||||
if (this->origin.y > v.y)
|
||||
this->Expand(Direction::kNegY, this->origin.y - v.y);
|
||||
T t_max = this->GetMax();
|
||||
if (t_max.x < v.x)
|
||||
this->Expand(Direction::kPosX, v.x - this->origin.x);
|
||||
if (t_max.y < v.y)
|
||||
this->Expand(Direction::kPosY, v.y - this->origin.y);
|
||||
}
|
||||
// TODO: Center around
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class BoxBase<T, 3> {
|
||||
static_assert(T::length() == 3);
|
||||
|
||||
protected:
|
||||
BoxBase() { }
|
||||
BoxBase(T _first, T _second)
|
||||
: first(_first)
|
||||
, second(_second) { }
|
||||
|
||||
public:
|
||||
// Data
|
||||
union {
|
||||
T first, min;
|
||||
};
|
||||
union {
|
||||
T second, max;
|
||||
};
|
||||
|
||||
auto operator[](const int idx) const {
|
||||
return this->data.at(idx);
|
||||
}
|
||||
|
||||
// Utility functions
|
||||
T GetSize() const { return this->max - this->min; }
|
||||
T& GetMax() const { return this->max; }
|
||||
|
||||
T GetPoint(int idx) const {
|
||||
switch (idx) {
|
||||
case 0:
|
||||
return this->min;
|
||||
case 1:
|
||||
return { this->max.x, this->min.y, this->min.z };
|
||||
case 2:
|
||||
return { this->max.x, this->max.y, this->min.z };
|
||||
case 3:
|
||||
return { this->min.x, this->max.y, this->max.z };
|
||||
case 4:
|
||||
return { this->min.x, this->min.y, this->max.z };
|
||||
case 5:
|
||||
return { this->max.x, this->min.y, this->max.z };
|
||||
case 6:
|
||||
return { this->min.x, this->max.y, this->min.z };
|
||||
case 7:
|
||||
return this->max;
|
||||
default:
|
||||
throw std::logic_error("GetPoint() is only available for 2 and 3 axis vectors");
|
||||
}
|
||||
}
|
||||
std::array<T, 8> GetPoints() const {
|
||||
return {
|
||||
this->min,
|
||||
{ this->max.x, this->min.y, this->min.z },
|
||||
{ this->max.x, this->max.y, this->min.z },
|
||||
{ this->min.x, this->max.y, this->max.z },
|
||||
{ this->min.x, this->min.y, this->max.z },
|
||||
{ this->max.x, this->min.y, this->max.z },
|
||||
{ this->min.x, this->max.y, this->min.z },
|
||||
this->max
|
||||
};
|
||||
}
|
||||
|
||||
bool Contains(T i) const {
|
||||
if (i.x > this->min.x || i.y > this->min.y || i.z > this->min.z)
|
||||
if (i.x < this->max.x || i.y < this->max.y || i.z < this->max.z)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Credits to cathook
|
||||
bool LineIntersects(T src, T dst) const {
|
||||
if (dst.x < this->min.x && src.x < this->min.x)
|
||||
return false;
|
||||
if (dst.y < this->min.y && src.y < this->min.y)
|
||||
return false;
|
||||
if (dst.z < this->min.z && src.z < this->min.z)
|
||||
return false;
|
||||
if (dst.x > this->max.x && src.x > this->max.x)
|
||||
return false;
|
||||
if (dst.y > this->max.y && src.y > this->max.y)
|
||||
return false;
|
||||
if (dst.z > this->max.z && src.z > this->max.z)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
enum Direction {
|
||||
kUp,
|
||||
kDown,
|
||||
kLeft,
|
||||
kRight,
|
||||
kForward,
|
||||
kBackward,
|
||||
kPosX = kUp,
|
||||
kPosY = kLeft,
|
||||
kPosZ = kForward,
|
||||
kNegX = kDown,
|
||||
kNegY = kRight,
|
||||
kNegZ = kBackward
|
||||
};
|
||||
void Expand(Direction dir, int amt) {
|
||||
switch (dir) {
|
||||
case Direction::kUp:
|
||||
this->max.y += amt;
|
||||
break;
|
||||
case Direction::kDown:
|
||||
this->min.y -= amt;
|
||||
break;
|
||||
case Direction::kLeft:
|
||||
this->min.x += amt;
|
||||
break;
|
||||
case Direction::kRight:
|
||||
this->min.x -= amt;
|
||||
break;
|
||||
case Direction::kForward:
|
||||
this->min.z += amt;
|
||||
break;
|
||||
case Direction::kBackward:
|
||||
this->max.z -= amt;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class Box : public BoxBase<T, T::length()> {
|
||||
using Parent = BoxBase<T, T::length()>;
|
||||
|
||||
public:
|
||||
using Direction = typename Parent::Direction;
|
||||
|
||||
Box() { }
|
||||
Box(T _first, T _second)
|
||||
: Parent(_first, _second) { }
|
||||
Box(std::pair<T, T> v)
|
||||
: Box(v.first, v.second) { }
|
||||
template <typename TT>
|
||||
Box(TT v)
|
||||
: Box(v.first, v.second) {
|
||||
static_assert(!std::is_same_v<std::pair<T, T>, TT>);
|
||||
}
|
||||
|
||||
template <typename TT>
|
||||
Box<T>& operator=(TT v) { *this = Box<T>(v.first, v.second); }
|
||||
|
||||
// Unary arithmetic operators
|
||||
bool operator==(T v) const {
|
||||
return this->first == v.first && this->second == v.second;
|
||||
}
|
||||
bool operator!=(T v) const {
|
||||
return !(*this == v);
|
||||
}
|
||||
Box<T> operator+(T v) const {
|
||||
return { this->min + v, this->max + v };
|
||||
}
|
||||
Box<T> operator-(T v) const {
|
||||
return { this->min - v, this->max - v };
|
||||
}
|
||||
|
||||
Box<T> operator*(typename T::value_type v) const {
|
||||
T center = this->GetCenter();
|
||||
T size = (this->GetSize() * v) / typename T::value_type(2);
|
||||
return { center - size, center + size };
|
||||
}
|
||||
Box<T> operator/(typename T::value_type v) const {
|
||||
T center = this->GetCenter();
|
||||
T delta = (this->GetSize() / v) / typename T::value_type(2);
|
||||
|
||||
return { center - delta, center + delta };
|
||||
}
|
||||
Box<T>& operator/=(typename T::value_type v) {
|
||||
return *this = *this / v;
|
||||
}
|
||||
|
||||
// Utility functions
|
||||
T GetCenter() const { return (this->first + this->second) / typename T::value_type(2); }
|
||||
void Expand(std::initializer_list<Direction> dirs, int amt) {
|
||||
auto end = dirs.end();
|
||||
for (auto i = dirs.begin(); i != end; i++)
|
||||
this->Expand(*i, amt);
|
||||
}
|
||||
void Shrink(Direction dir, int amt) { this->Expand(dir, -amt); }
|
||||
};
|
||||
|
||||
template <int T_length>
|
||||
class AngleBase;
|
||||
|
||||
template <>
|
||||
class AngleBase<1> {
|
||||
float data;
|
||||
|
||||
protected:
|
||||
template <typename... T>
|
||||
AngleBase(T... args)
|
||||
: data(args...) { }
|
||||
|
||||
public:
|
||||
operator float() const {
|
||||
return this->data;
|
||||
}
|
||||
operator float&() {
|
||||
return this->data;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class AngleBase<2> : public Vec2 {
|
||||
using Vec2::Vec2;
|
||||
using Parent = Vec2;
|
||||
|
||||
protected:
|
||||
template <typename... T>
|
||||
AngleBase(T... args)
|
||||
: Vec2(args...) {
|
||||
static_assert(!(std::is_same_v<Vec2, T> || ...));
|
||||
}
|
||||
|
||||
public:
|
||||
using Vec2::operator=;
|
||||
template <class T>
|
||||
AngleBase operator-(T in) { return *this - Vec2(in); }
|
||||
template <class T>
|
||||
AngleBase operator+(T in) { return *this + Vec2(in); }
|
||||
|
||||
AngleBase<2>& Clamp();
|
||||
AngleBase<2> Clamp() const;
|
||||
AngleBase<2> GetDelta(const AngleBase<2>& other_angles) const;
|
||||
float GetFov(const Vec3& view_src, const Vec3& dest_point) const;
|
||||
float GetFov(const AngleBase<2>& pointed_angle) const;
|
||||
static AngleBase<2> PointTo(const Vec3& src_point, const Vec3& dest_point);
|
||||
};
|
||||
|
||||
template <int T_Length>
|
||||
using Angle = AngleBase<T_Length>;
|
||||
using Angle1 = Angle<1>;
|
||||
using Angle2 = Angle<2>;
|
||||
|
||||
template <typename T_Origin, typename T_Angle>
|
||||
class Ray {
|
||||
private:
|
||||
const T_Origin origin;
|
||||
const T_Angle angle;
|
||||
|
||||
public:
|
||||
Ray(T_Origin origin, T_Angle angle)
|
||||
: origin(origin)
|
||||
, angle(angle) { }
|
||||
std::pair<T_Origin, T_Origin> Cast(float dist);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class Segment : public std::pair<T, T> {
|
||||
public:
|
||||
using Parent = std::pair<T, T>;
|
||||
using Parent::Parent;
|
||||
using Parent::operator=;
|
||||
template <typename TT>
|
||||
Segment(Ray<T, TT> r, float dist = 8192.0f)
|
||||
: Parent(r.Cast(dist)) { }
|
||||
Segment(const std::pair<T, T>& p)
|
||||
: Parent(p) { }
|
||||
Segment(std::pair<T, T>&& p)
|
||||
: Parent(std::move(p)) { }
|
||||
Segment(std::pair<T, T> p)
|
||||
: Parent(std::move(p)) { }
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
using Vec3 = internal::Vec3;
|
||||
|
||||
using Vec2 = internal::Vec2;
|
||||
|
||||
// idk if these should be in here, but its too useful not to...
|
||||
using DVec3 = internal::DVec3;
|
||||
using IVec2 = internal::IVec2;
|
||||
using UVec2 = internal::UVec2;
|
||||
///
|
||||
|
||||
template <class... T>
|
||||
auto Distance(T... in) { return internal::Distance(in...); }
|
||||
|
||||
template <class T>
|
||||
auto GetMaskOfVec2(const T& src, glm::bvec2 mask) { return internal::GetMaskOfVec2(src, mask); }
|
||||
|
||||
template <class T>
|
||||
using Box = internal::Box<T>;
|
||||
|
||||
template <int T>
|
||||
using Angle = internal::AngleBase<T>;
|
||||
|
||||
template <typename T_Origin, typename T_Angle>
|
||||
using Ray = internal::Ray<T_Origin, T_Angle>;
|
||||
|
||||
template <typename T>
|
||||
using Segment = internal::Segment<T>;
|
||||
using Segment2 = internal::Segment<Vec2>;
|
||||
using Segment3 = internal::Segment<Vec3>;
|
||||
|
||||
template <class T_Vec, class T_Float>
|
||||
using Sphereoid = std::pair<T_Vec, T_Float>;
|
||||
|
||||
} // namespace qubel::geo
|
Loading…
x
Reference in New Issue
Block a user