Commit 18c840b9 authored by Shu's avatar Shu 🍠
Browse files

Break parts in custom entities and display

parent d7012d15
......@@ -7,10 +7,11 @@ set(SIMD_LEVEL "avx2" CACHE STRING "SIMD processor acceleration (sse2, sse4.1, a
option(USE_FMA "Use fma" 1)
option(LOG_DEBUG "Show debug logs" 0)
option(LOG_TRACE "Show trace logs" 0)
option(NATIVE "Build with -march=native" 0)
find_program(CCACHE_FOUND ccache)
if(CCACHE_FOUND)
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
endif(CCACHE_FOUND)
add_subdirectory("deps/glfw")
......@@ -29,14 +30,17 @@ add_compile_definitions(FIXED_WINDOW=${FIXED_WINDOW} LOG_DEBUG=${LOG_DEBUG} LOG_
if(PROFILING)
add_compile_definitions(TRACY_ENABLE=1)
endif(PROFILING)
if(NATIVE)
add_definitions(-march=native)
endif()
if(SIMD_LEVEL EQUAL "avx2")
add_compile_definitions(FN_COMPILE_AVX2=1)
add_compile_definitions(FN_COMPILE_AVX2=1)
elseif(SIMD_LEVEL EQUAL "avx512f")
add_compile_definitions(FN_COMPILE_AVX512=1)
add_compile_definitions(FN_COMPILE_AVX512=1)
endif()
add_definitions(-m${SIMD_LEVEL})
if(USE_FMA)
add_definitions(-mfma)
add_definitions(-mfma)
endif(USE_FMA)
file(GLOB_RECURSE CORE_SOURCES "src/core/*.cpp" "deps/tracy/TracyClient.cpp")
......@@ -72,6 +76,13 @@ target_include_directories(univerxel-client PRIVATE ${CORE_HEADERS} ${CLIENT_HEA
# Resource client files + default zstd.dict
file(COPY resource/content DESTINATION ${CMAKE_BINARY_DIR})
# Serialize entity model
file(GLOB_RECURSE MODELS_SOURCES "src/client/render/api/Models.cpp")
add_executable(generate_models EXCLUDE_FROM_ALL "src/tools/generate_models.cpp" ${MODELS_SOURCES})
target_compile_features(generate_models PUBLIC cxx_std_17)
target_link_libraries(generate_models glm::glm_static)
target_include_directories(generate_models PRIVATE "deps/robin_hood" "deps/meshoptimizer")
# Docs
add_custom_target(docs
COMMAND doxygen ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile
......
......@@ -101,6 +101,7 @@ CMAKE_BUILD_TYPE | Level of optimization | `Release`
PROFILING | Tracy profiling | `0`
LOG_DEBUG | Debug logs | `0`
LOG_TRACE | Trace logs | `0`
NATIVE | Optimize for native CPU | `0`
1. Build Make
```sh
......
......@@ -34,7 +34,9 @@
- [x] Transparency
- [~] Entities
- [ ] Collide
- [ ] Get models
- [x] Get models
- [ ] Save in world
- [ ] Rotate
- [ ] Reduce compile unit count
- [~] Review documentation
- [ ] Clean kick
......@@ -81,6 +83,7 @@
- [x] QUIC protocol
- [~] 8 for 1 contouring problem
- [ ] Use in memory protocol (to replace server_handle)
- [ ] Remove SharedUniverse
- [ ] Octree
- [ ] Better Lod
- [ ] VK
......@@ -95,7 +98,8 @@
- https://www.youtube.com/watch?v=iikdcAA7cww
- Toon shading
- Eye adaptation
- [ ] Correct sRGB conversions
- GLSL gamma correction
- https://github.com/skurmedel/shaders/blob/master/glsl/gamma_correct.glsl
- [ ] Post processing
- https://learnopengl.com/Advanced-OpenGL/Anti-Aliasing
- Bloom
......
......@@ -6,7 +6,6 @@
// _/_____/
//
// Fast & memory efficient hashtable based on robin hood hashing for C++11/14/17/20
// version 3.8.0
// https://github.com/martinus/robin-hood-hashing
//
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
......@@ -36,7 +35,7 @@
// see https://semver.org/
#define ROBIN_HOOD_VERSION_MAJOR 3 // for incompatible API changes
#define ROBIN_HOOD_VERSION_MINOR 8 // for adding functionality in a backwards-compatible manner
#define ROBIN_HOOD_VERSION_MINOR 9 // for adding functionality in a backwards-compatible manner
#define ROBIN_HOOD_VERSION_PATCH 0 // for backwards-compatible bug fixes
#include <algorithm>
......@@ -132,46 +131,32 @@ static Counts& counts() {
#endif
// count leading/trailing bits
#if ((defined __i386 || defined __x86_64__) && defined __BMI__) || defined _M_IX86 || defined _M_X64
#if !defined(ROBIN_HOOD_DISABLE_INTRINSICS)
# ifdef _MSC_VER
# if ROBIN_HOOD(BITNESS) == 32
# define ROBIN_HOOD_PRIVATE_DEFINITION_BITSCANFORWARD() _BitScanForward
# else
# define ROBIN_HOOD_PRIVATE_DEFINITION_BITSCANFORWARD() _BitScanForward64
# endif
# include <intrin.h>
# pragma intrinsic(ROBIN_HOOD(BITSCANFORWARD))
# define ROBIN_HOOD_COUNT_TRAILING_ZEROES(x) \
[](size_t mask) noexcept -> int { \
unsigned long index; \
return ROBIN_HOOD(BITSCANFORWARD)(&index, mask) ? static_cast<int>(index) \
: ROBIN_HOOD(BITNESS); \
}(x)
# else
# include <x86intrin.h>
# if ROBIN_HOOD(BITNESS) == 32
# define ROBIN_HOOD_PRIVATE_DEFINITION_CTZ() __builtin_ctzl
# define ROBIN_HOOD_PRIVATE_DEFINITION_CLZ() __builtin_clzl
# else
# define ROBIN_HOOD_PRIVATE_DEFINITION_CTZ() __builtin_ctzll
# define ROBIN_HOOD_PRIVATE_DEFINITION_CLZ() __builtin_clzll
# endif
# define ROBIN_HOOD_COUNT_LEADING_ZEROES(x) ((x) ? ROBIN_HOOD(CLZ)(x) : ROBIN_HOOD(BITNESS))
# define ROBIN_HOOD_COUNT_TRAILING_ZEROES(x) ((x) ? ROBIN_HOOD(CTZ)(x) : ROBIN_HOOD(BITNESS))
# endif
# if ROBIN_HOOD(BITNESS) == 32
# define ROBIN_HOOD_PRIVATE_DEFINITION_CTZ() _tzcnt_u32
# else
# define ROBIN_HOOD_PRIVATE_DEFINITION_CTZ() _tzcnt_u64
# endif
# if defined __AVX2__ || defined __BMI__
# define ROBIN_HOOD_COUNT_TRAILING_ZEROES(x) ROBIN_HOOD(CTZ)(x)
# else
# define ROBIN_HOOD_COUNT_TRAILING_ZEROES(x) ROBIN_HOOD(CTZ)(x)
# endif
#elif defined _MSC_VER
# if ROBIN_HOOD(BITNESS) == 32
# define ROBIN_HOOD_PRIVATE_DEFINITION_BITSCANFORWARD() _BitScanForward
# else
# define ROBIN_HOOD_PRIVATE_DEFINITION_BITSCANFORWARD() _BitScanForward64
# endif
# include <intrin.h>
# pragma intrinsic(ROBIN_HOOD(BITSCANFORWARD))
# define ROBIN_HOOD_COUNT_TRAILING_ZEROES(x) \
[](size_t mask) noexcept -> int { \
unsigned long index; \
return ROBIN_HOOD(BITSCANFORWARD)(&index, mask) ? static_cast<int>(index) \
: ROBIN_HOOD(BITNESS); \
}(x)
#else
# if ROBIN_HOOD(BITNESS) == 32
# define ROBIN_HOOD_PRIVATE_DEFINITION_CTZ() __builtin_ctzl
# define ROBIN_HOOD_PRIVATE_DEFINITION_CLZ() __builtin_clzl
# else
# define ROBIN_HOOD_PRIVATE_DEFINITION_CTZ() __builtin_ctzll
# define ROBIN_HOOD_PRIVATE_DEFINITION_CLZ() __builtin_clzll
# endif
# define ROBIN_HOOD_COUNT_LEADING_ZEROES(x) ((x) ? ROBIN_HOOD(CLZ)(x) : ROBIN_HOOD(BITNESS))
# define ROBIN_HOOD_COUNT_TRAILING_ZEROES(x) ((x) ? ROBIN_HOOD(CTZ)(x) : ROBIN_HOOD(BITNESS))
#endif
// fallthrough
......@@ -195,6 +180,17 @@ static Counts& counts() {
# define ROBIN_HOOD_UNLIKELY(condition) __builtin_expect(condition, 0)
#endif
// detect if native wchar_t type is availiable in MSVC
#ifdef _MSC_VER
# ifdef _NATIVE_WCHAR_T_DEFINED
# define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_NATIVE_WCHART() 1
# else
# define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_NATIVE_WCHART() 0
# endif
#else
# define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_NATIVE_WCHART() 1
#endif
// workaround missing "is_trivially_copyable" in g++ < 5.0
// See https://stackoverflow.com/a/31798726/48181
#if defined(__GNUC__) && __GNUC__ < 5
......@@ -294,6 +290,13 @@ using index_sequence_for = make_index_sequence<sizeof...(T)>;
namespace detail {
// make sure we static_cast to the correct type for hash_int
#if ROBIN_HOOD(BITNESS) == 64
using SizeT = uint64_t;
#else
using SizeT = uint32_t;
#endif
template <typename T>
T rotr(T x, unsigned k) {
return (x >> k) | (x << (8U * sizeof(T) - k));
......@@ -315,14 +318,14 @@ inline T reinterpret_cast_no_cast_align_warning(void const* ptr) noexcept {
// make sure this is not inlined as it is slow and dramatically enlarges code, thus making other
// inlinings more difficult. Throws are also generally the slow path.
template <typename E, typename... Args>
ROBIN_HOOD(NOINLINE)
[[noreturn]] ROBIN_HOOD(NOINLINE)
#if ROBIN_HOOD(HAS_EXCEPTIONS)
void doThrow(Args&&... args) {
void doThrow(Args&&... args) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
throw E(std::forward<Args>(args)...);
}
#else
void doThrow(Args&&... ROBIN_HOOD_UNUSED(args) /*unused*/) {
void doThrow(Args&&... ROBIN_HOOD_UNUSED(args) /*unused*/) {
abort();
}
#endif
......@@ -388,7 +391,7 @@ public:
void reset() noexcept {
while (mListForFree) {
T* tmp = *mListForFree;
free(mListForFree);
std::free(mListForFree);
mListForFree = reinterpret_cast_no_cast_align_warning<T**>(tmp);
}
mHead = nullptr;
......@@ -423,7 +426,7 @@ public:
// calculate number of available elements in ptr
if (numBytes < ALIGNMENT + ALIGNED_SIZE) {
// not enough data for at least one element. Free and return.
free(ptr);
std::free(ptr);
} else {
add(ptr, numBytes);
}
......@@ -490,7 +493,7 @@ private:
// alloc new memory: [prev |T, T, ... T]
// std::cout << (sizeof(T*) + ALIGNED_SIZE * numElementsToAlloc) << " bytes" << std::endl;
size_t const bytes = ALIGNMENT + ALIGNED_SIZE * numElementsToAlloc;
add(assertNotNull<std::bad_alloc>(malloc(bytes)), bytes);
add(assertNotNull<std::bad_alloc>(std::malloc(bytes)), bytes);
return mHead;
}
......@@ -526,7 +529,7 @@ struct NodeAllocator<T, MinSize, MaxSize, true> {
// we are not using the data, so just free it.
void addOrFree(void* ptr, size_t ROBIN_HOOD_UNUSED(numBytes) /*unused*/) noexcept {
free(ptr);
std::free(ptr);
}
};
......@@ -670,7 +673,7 @@ inline constexpr bool operator>=(pair<A, B> const& x, pair<A, B> const& y) {
return !(x < y);
}
inline size_t hash_bytes(void const* ptr, size_t const len) noexcept {
inline size_t hash_bytes(void const* ptr, size_t len) noexcept {
static constexpr uint64_t m = UINT64_C(0xc6a4a7935bd1e995);
static constexpr uint64_t seed = UINT64_C(0xe17a1465);
static constexpr unsigned int r = 47;
......@@ -730,8 +733,8 @@ inline size_t hash_int(uint64_t x) noexcept {
//
// Instead of shifts, we use rotations so we don't lose any bits.
//
// Added a final multiplcation with a constant for more mixing. It is most important that the
// lower bits are well mixed.
// Added a final multiplcation with a constant for more mixing. It is most important that
// the lower bits are well mixed.
auto h1 = x * UINT64_C(0xA24BAED4963EE407);
auto h2 = detail::rotr(x, 32U) * UINT64_C(0x9FB21C651E98DF25);
auto h = detail::rotr(h1 + h2, 32U);
......@@ -739,14 +742,14 @@ inline size_t hash_int(uint64_t x) noexcept {
}
// A thin wrapper around std::hash, performing an additional simple mixing step of the result.
template <typename T>
template <typename T, typename Enable = void>
struct hash : public std::hash<T> {
size_t operator()(T const& obj) const
noexcept(noexcept(std::declval<std::hash<T>>().operator()(std::declval<T const&>()))) {
// call base hash
auto result = std::hash<T>::operator()(obj);
// return mixed of that, to be save against identity has
return hash_int(static_cast<uint64_t>(result));
return hash_int(static_cast<detail::SizeT>(result));
}
};
......@@ -769,21 +772,29 @@ struct hash<std::basic_string_view<CharT>> {
template <class T>
struct hash<T*> {
size_t operator()(T* ptr) const noexcept {
return hash_int(reinterpret_cast<size_t>(ptr));
return hash_int(reinterpret_cast<detail::SizeT>(ptr));
}
};
template <class T>
struct hash<std::unique_ptr<T>> {
size_t operator()(std::unique_ptr<T> const& ptr) const noexcept {
return hash_int(reinterpret_cast<size_t>(ptr.get()));
return hash_int(reinterpret_cast<detail::SizeT>(ptr.get()));
}
};
template <class T>
struct hash<std::shared_ptr<T>> {
size_t operator()(std::shared_ptr<T> const& ptr) const noexcept {
return hash_int(reinterpret_cast<size_t>(ptr.get()));
return hash_int(reinterpret_cast<detail::SizeT>(ptr.get()));
}
};
template <typename Enum>
struct hash<Enum, typename std::enable_if<std::is_enum<Enum>::value>::type> {
size_t operator()(Enum e) const noexcept {
using Underlying = typename std::underlying_type<Enum>::type;
return hash<Underlying>{}(static_cast<Underlying>(e));
}
};
......@@ -806,7 +817,9 @@ ROBIN_HOOD_HASH_INT(signed char);
ROBIN_HOOD_HASH_INT(unsigned char);
ROBIN_HOOD_HASH_INT(char16_t);
ROBIN_HOOD_HASH_INT(char32_t);
#if ROBIN_HOOD(HAS_NATIVE_WCHART)
ROBIN_HOOD_HASH_INT(wchar_t);
#endif
ROBIN_HOOD_HASH_INT(short);
ROBIN_HOOD_HASH_INT(unsigned short);
ROBIN_HOOD_HASH_INT(int);
......@@ -914,7 +927,8 @@ private:
static constexpr size_t InitialNumElements = sizeof(uint64_t);
static constexpr uint32_t InitialInfoNumBits = 5;
static constexpr uint8_t InitialInfoInc = 1U << InitialInfoNumBits;
static constexpr uint8_t InitialInfoHashShift = sizeof(size_t) * 8 - InitialInfoNumBits;
static constexpr size_t InfoMask = InitialInfoInc - 1U;
static constexpr uint8_t InitialInfoHashShift = 0;
using DataPool = detail::NodeAllocator<value_type, 4, 16384, IsFlat>;
// type needs to be wider than uint8_t.
......@@ -1247,7 +1261,7 @@ private:
Iter operator++(int) noexcept {
Iter tmp = *this;
++(*this);
return std::move(tmp);
return tmp;
}
reference operator*() const {
......@@ -1278,13 +1292,29 @@ private:
mInfo += sizeof(size_t);
mKeyVals += sizeof(size_t);
}
#if ROBIN_HOOD(LITTLE_ENDIAN)
auto inc = ROBIN_HOOD_COUNT_TRAILING_ZEROES(n) / 8;
#if defined(ROBIN_HOOD_DISABLE_INTRINSICS)
// we know for certain that within the next 8 bytes we'll find a non-zero one.
if (ROBIN_HOOD_UNLIKELY(0U == detail::unaligned_load<uint32_t>(mInfo))) {
mInfo += 4;
mKeyVals += 4;
}
if (ROBIN_HOOD_UNLIKELY(0U == detail::unaligned_load<uint16_t>(mInfo))) {
mInfo += 2;
mKeyVals += 2;
}
if (ROBIN_HOOD_UNLIKELY(0U == *mInfo)) {
mInfo += 1;
mKeyVals += 1;
}
#else
# if ROBIN_HOOD(LITTLE_ENDIAN)
auto inc = ROBIN_HOOD_COUNT_TRAILING_ZEROES(n) / 8;
# else
auto inc = ROBIN_HOOD_COUNT_LEADING_ZEROES(n) / 8;
#endif
# endif
mInfo += inc;
mKeyVals += inc;
#endif
}
friend class Table<IsFlat, MaxLoadFactor100, key_type, mapped_type, hasher, key_equal>;
......@@ -1306,10 +1336,11 @@ private:
typename std::conditional<std::is_same<::robin_hood::hash<key_type>, hasher>::value,
::robin_hood::detail::identity_hash<size_t>,
::robin_hood::hash<size_t>>::type;
*idx = Mix{}(WHash::operator()(key));
*info = mInfoInc + static_cast<InfoType>(*idx >> mInfoHashShift);
*idx &= mMask;
// the lower InitialInfoNumBits are reserved for info.
auto h = Mix{}(WHash::operator()(key));
*info = mInfoInc + static_cast<InfoType>((h & InfoMask) >> mInfoHashShift);
*idx = (h >> InitialInfoNumBits) & mMask;
}
// forwards the index by one, wrapping around at the end
......@@ -1448,13 +1479,19 @@ public:
using iterator = Iter<false>;
using const_iterator = Iter<true>;
Table() noexcept(noexcept(Hash()) && noexcept(KeyEqual()))
: WHash()
, WKeyEqual() {
ROBIN_HOOD_TRACE(this)
}
// Creates an empty hash map. Nothing is allocated yet, this happens at the first insert.
// This tremendously speeds up ctor & dtor of a map that never receives an element. The
// penalty is payed at the first insert, and not before. Lookup of this empty map works
// because everybody points to DummyInfoByte::b. parameter bucket_count is dictated by the
// standard, but we can ignore it.
explicit Table(
size_t ROBIN_HOOD_UNUSED(bucket_count) /*unused*/ = 0, const Hash& h = Hash{},
size_t ROBIN_HOOD_UNUSED(bucket_count) /*unused*/, const Hash& h = Hash{},
const KeyEqual& equal = KeyEqual{}) noexcept(noexcept(Hash(h)) && noexcept(KeyEqual(equal)))
: WHash(h)
, WKeyEqual(equal) {
......@@ -1535,7 +1572,7 @@ public:
auto const numElementsWithBuffer = calcNumElementsWithBuffer(o.mMask + 1);
mKeyVals = static_cast<Node*>(detail::assertNotNull<std::bad_alloc>(
malloc(calcNumBytesTotal(numElementsWithBuffer))));
std::malloc(calcNumBytesTotal(numElementsWithBuffer))));
// no need for calloc because clonData does memcpy
mInfo = reinterpret_cast<uint8_t*>(mKeyVals + numElementsWithBuffer);
mNumElements = o.mNumElements;
......@@ -1583,12 +1620,12 @@ public:
// no luck: we don't have the same array size allocated, so we need to realloc.
if (0 != mMask) {
// only deallocate if we actually have data!
free(mKeyVals);
std::free(mKeyVals);
}
auto const numElementsWithBuffer = calcNumElementsWithBuffer(o.mMask + 1);
mKeyVals = static_cast<Node*>(detail::assertNotNull<std::bad_alloc>(
malloc(calcNumBytesTotal(numElementsWithBuffer))));
std::malloc(calcNumBytesTotal(numElementsWithBuffer))));
// no need for calloc here because cloneData performs a memcpy.
mInfo = reinterpret_cast<uint8_t*>(mKeyVals + numElementsWithBuffer);
......@@ -2058,8 +2095,13 @@ private:
}
}
// don't destroy old data: put it into the pool instead
DataPool::addOrFree(oldKeyVals, calcNumBytesTotal(oldMaxElementsWithBuffer));
// this check is not necessary as it's guarded by the previous if, but it helps silence
// g++'s overeager "attempt to free a non-heap object 'map'
// [-Werror=free-nonheap-object]" warning.
if (oldKeyVals != reinterpret_cast_no_cast_align_warning<Node*>(&mMask)) {
// don't destroy old data: put it into the pool instead
DataPool::addOrFree(oldKeyVals, calcNumBytesTotal(oldMaxElementsWithBuffer));
}
}
}
......@@ -2103,7 +2145,7 @@ private:
// calloc also zeroes everything
mKeyVals = reinterpret_cast<Node*>(detail::assertNotNull<std::bad_alloc>(
calloc(1, calcNumBytesTotal(numElementsWithBuffer))));
std::calloc(1, calcNumBytesTotal(numElementsWithBuffer))));
mInfo = reinterpret_cast<uint8_t*>(mKeyVals + numElementsWithBuffer);
// set sentinel
......@@ -2290,7 +2332,7 @@ private:
// reports a compile error: attempt to free a non-heap object ‘fm’
// [-Werror=free-nonheap-object]
if (mKeyVals != reinterpret_cast_no_cast_align_warning<Node*>(&mMask)) {
free(mKeyVals);
std::free(mKeyVals);
}
}
......
......@@ -218,5 +218,4 @@ void main() {
float ratio = exp(vs.Depth * 0.69)-1;
color = mix(color, vec4(pow(FogColor, vec3(2.2)), 1), clamp(ratio, 0, 1));
#endif
color = pow(color, vec4(vec3(1.0 / 2.2), 1));
}
\ No newline at end of file
......@@ -144,44 +144,30 @@ void Client::run(server_handle* const localHandle) {
frustum = {camera.getFrustum()};
}
const auto offset = state.position.raw_as_long();
{ // Chunks
std::vector<glm::vec3> occlusion;
if (options.culling > 0) {
const auto ratio = options.culling * 2;
occlusion.reserve(glm::pow2(ratio * 2 - 1));
const auto [ch, cv] = player.getAngles();
const auto max_v = tan(options.camera.fov / 2.), max_h = Window::RATIO * max_v;
for(int iv = -ratio + 1; iv < ratio; iv++) {
const auto v = cv + max_v * iv / ratio;
for(int ih = -ratio + 1; ih < ratio; ih++) {
const auto h = ch + max_h * ih / ratio;
occlusion.emplace_back(cos(v) * sin(h), sin(v), cos(v) * cos(h));
}
}
}
{ // Solid
const auto pass = pipeline->beginWorldPass(true);
const auto draw = [&](glm::mat4 model, render::LodModel *const buffer, const contouring::Abstract::area_info &area, const voxel_pos &pos) {
reports.models_count++;
reports.tris_count += pass(buffer, model, glm::vec4(pos, std::get<1>(area)), std::get<2>(area));
};
if (options.culling > 0) {
state.contouring->getModels(draw, player.position, options.camera.far, occlusion, offset, options.voxel_density, true);
} else {
state.contouring->getModels(draw, frustum, offset, options.voxel_density, true);
std::vector<glm::vec3> occlusion;
if (options.culling > 0) {
const auto ratio = options.culling * 2;
occlusion.reserve(glm::pow2(ratio * 2 - 1));
const auto [ch, cv] = player.getAngles();
const auto max_v = tan(options.camera.fov / 2.), max_h = Window::RATIO * max_v;
for(int iv = -ratio + 1; iv < ratio; iv++) {
const auto v = cv + max_v * iv / ratio;
for(int ih = -ratio + 1; ih < ratio; ih++) {
const auto h = ch + max_h * ih / ratio;
occlusion.emplace_back(cos(v) * sin(h), sin(v), cos(v) * cos(h));
}
}
if (options.renderer.voxel.transparency) {
const auto pass = pipeline->beginWorldPass(false);
const auto draw = [&](glm::mat4 model, render::LodModel *const buffer, const contouring::Abstract::area_info &area, const voxel_pos &pos) {
reports.models_count++;
reports.tris_count += pass(buffer, model, glm::vec4(pos, std::get<1>(area)), std::get<2>(area));
};
if (options.culling > 0) {
state.contouring->getModels(draw, player.position, options.camera.far, occlusion, offset, options.voxel_density, false);
} else {
state.contouring->getModels(draw, frustum, offset, options.voxel_density, false);
}
}
{ // Solid
const auto pass = pipeline->beginWorldPass(true);
const auto draw = [&](glm::mat4 model, render::LodModel *const buffer, const contouring::Abstract::area_info &area, const voxel_pos &pos) {
reports.models_count++;
reports.tris_count += pass(buffer, model, glm::vec4(pos, std::get<1>(area)), std::get<2>(area));
};
if (options.culling > 0) {
state.contouring->getModels(draw, player.position, options.camera.far, occlusion, offset, options.voxel_density, true);
} else {
state.contouring->getModels(draw, frustum, offset, options.voxel_density, true);
}
}
{ // Entities
......@@ -203,6 +189,18 @@ void Client::run(server_handle* const localHandle) {
reports.tris_count += pass(model, options.editor.tool.shape, color);
}
}
if (options.renderer.voxel.transparency) {
const auto pass = pipeline->beginWorldPass(false);
const auto draw = [&](glm::mat4 model, render::LodModel *const buffer, const contouring::Abstract::area_info &area, const voxel_pos &pos) {
reports.models_count++;
reports.tris_count += pass(buffer, model, glm::vec4(pos, std::get<1>(area)), std::get<2>(area));
};
if (options.culling > 0) {
state.contouring->getModels(draw, player.position, options.camera.far, occlusion, offset, options.voxel_density, false);
} else {
state.contouring->getModels(draw, frustum, offset, options.voxel_density, false);
}
}
pipeline->postProcess();
render::UI::Get()->render();
pipeline->endFrame();
......
......@@ -31,6 +31,12 @@ namespace contouring {
virtual void onNotify(const area_<chunk_pos> &pos, const chunk_pos &offset, const world::ChunkContainer &data) = 0;
/// Display ImGui config
virtual void onGui() = 0;
/// Register entity from model
virtual void onEntityLoad(size_t id, std::istream&) = 0;
/// Register entity from area
virtual void onEntityLoad(size_t id, const glm::ucvec3& size, const std::vector<std::shared_ptr<world::Chunk>>&) = 0;
/// Free entity model
virtual void onEntityUnload(size_t id) = 0;
/// Get options
virtual std::string getOptions() const = 0;
/// Get camera recommended far range
......
......@@ -11,6 +11,12 @@
#include "optimizer.hpp"
namespace contouring {
constexpr auto PACK = [](const render::VertexData &v) {
return render::PackedVertexData(meshopt_quantizeHalf(v.Position.x), meshopt_quantizeHalf(v.Position.y),
meshopt_quantizeHalf(v.Position.z), v.Material,
meshopt_quantizeHalf(v.Normal.x), meshopt_quantizeHalf(v.Normal.y),
meshopt_quantizeHalf(v.Normal.z));
};
const std::vector<std::pair<float, float>> LEVELS = {{.001f, 9e-1f}, {.01f, 5e-1f}, {.1f, 1e-1f}, {.2, 1e-2f}, {.5, 5e-3f}};
FlatDualMC::FlatDualMC(const std::string &str) : Abstract() {
......@@ -43,10 +49,31 @@ namespace contouring {
#endif
std::vector<render::VertexData> tmp;
while (running) {
std::pair<area_<chunk_pos>, surrounding::corners> ctx;
loadQueue.wait();
if (loadQueue.pop(ctx)) {