Merge branch 'main' into dev

This commit is contained in:
MihailRis 2025-10-01 00:07:53 +03:00
commit 9963bc4134
23 changed files with 153 additions and 87 deletions

View File

@ -1,5 +1,4 @@
math.randomseed(43172)
for i = 1, 15 do
for i = 1, 3 do
debug.log(string.format("iteration %s", i))
local complete = false
@ -30,6 +29,7 @@ for i = 1, 15 do
end, "udp-data-sender")
end)
app.sleep_until(function () return complete end, nil, 5)
app.sleep_until(function () return complete end, nil, 1)
assert(complete, "timeout at iteration #"..i)
server:close()
end

View File

@ -39,7 +39,7 @@ function events.emit(event, ...)
local status, newres = xpcall(func, __vc__error, ...)
if not status then
debug.error("error in event ("..event..") handler: "..newres)
else
else
result = result or newres
end
end

View File

@ -67,12 +67,12 @@ function on_physics_update(delta)
mob.set_flight(player.is_flight(pid))
body:set_body_type(player.is_noclip(pid) and "kinematic" or "dynamic")
if hud and pid == hud.get_player() then
local pos = tsf:get_pos()
local rot = get_player_rotation(pid)
local front = mat4.mul(rot, {0, 0, -1})
local rot = get_player_rotation(pid)
local front = mat4.mul(rot, {0, 0, -1})
local pos = tsf:get_pos()
if hud and pid == hud.get_player() then
process_player_inputs(pid, rot, delta)
mob.look_at(vec3.add(pos, front))
end
mob.look_at(vec3.add(pos, front))
end

View File

@ -38,6 +38,10 @@ bool Font::isPrintableChar(uint codepoint) const {
}
}
int FontMetrics::calcWidth(std::wstring_view text, size_t offset, size_t length) const {
return std::min(text.length() - offset, length) * glyphInterval;
}
int Font::calcWidth(std::wstring_view text, size_t length) const {
return calcWidth(text, 0, length);
}

View File

@ -4,7 +4,9 @@
#include <string>
#include <vector>
#include <glm/glm.hpp>
#include "typedefs.hpp"
#include "FontMetics.hpp"
class Texture;
class Batch2D;
@ -90,4 +92,8 @@ public:
) const;
const Texture* getPage(int page) const;
FontMetrics getMetrics() const {
return {lineHeight, yoffset, glyphInterval};
}
};

View File

@ -0,0 +1,11 @@
#pragma once
#include <string>
struct FontMetrics {
int lineHeight;
int yoffset;
int glyphInterval = 8;
int calcWidth(std::wstring_view text, size_t offset=0, size_t length=-1) const;
};

View File

@ -25,6 +25,9 @@ void TextureAnimator::update(float delta) {
std::unordered_set<uint> changedTextures;
for (auto& elem : animations) {
if (elem.frames.empty()) {
continue;
}
elem.timer += delta;
size_t frameNum = elem.currentFrame;
Frame frame = elem.frames[elem.currentFrame];

View File

@ -27,8 +27,7 @@ void HandsRenderer::renderHands(
auto& skeleton = *this->skeleton;
const auto& config = *skeleton.config;
// render
modelBatch.setLightsOffset(camera.position);
config.update(skeleton, glm::mat4(1.0f), glm::vec3());
config.render(assets, modelBatch, skeleton, glm::mat4(1.0f), glm::vec3());
config.render(assets, modelBatch, skeleton, glm::mat3(1.0f), glm::vec3());
}

View File

@ -11,10 +11,11 @@
using namespace gui;
void LabelCache::prepare(Font* font, size_t wrapWidth) {
if (font != this->font) {
void LabelCache::prepare(std::ptrdiff_t fontId, FontMetrics metrics, size_t wrapWidth) {
if (fontId != this->fontId) {
resetFlag = true;
this->font = font;
this->fontId = fontId;
this->metrics = metrics;
}
if (wrapWidth != this->wrapWidth) {
resetFlag = true;
@ -41,7 +42,7 @@ void LabelCache::update(std::wstring_view text, bool multiline, bool wrap) {
lines.clear();
lines.push_back(LineScheme {0, false});
if (font == nullptr) {
if (fontId == 0) {
wrap = false;
}
@ -52,7 +53,7 @@ void LabelCache::update(std::wstring_view text, bool multiline, bool wrap) {
lines.push_back(LineScheme {i+1, false});
len = 0;
} else if (i > 0 && i+1 < text.length() && wrap && text[i+1] != L'\n') {
size_t width = font->calcWidth(text, i-len-1, i-(i-len)+2);
size_t width = metrics.calcWidth(text, i-len-1, i-(i-len)+2);
if (width >= wrapWidth) {
// starting a fake line
lines.push_back(LineScheme {i+1, true});
@ -60,20 +61,20 @@ void LabelCache::update(std::wstring_view text, bool multiline, bool wrap) {
}
}
}
if (font != nullptr) {
if (fontId != 0) {
int maxWidth = 0;
for (int i = 0; i < lines.size() - 1; i++) {
const auto& next = lines[i + 1];
const auto& cur = lines[i];
maxWidth = std::max(
font->calcWidth(
metrics.calcWidth(
text.substr(cur.offset, next.offset - cur.offset)
),
maxWidth
);
}
maxWidth = std::max(
font->calcWidth(
metrics.calcWidth(
text.substr(lines[lines.size() - 1].offset)
),
maxWidth
@ -105,8 +106,8 @@ Label::Label(GUI& gui, const std::wstring& text, std::string fontName)
Label::~Label() = default;
glm::vec2 Label::calcSize() {
auto font = cache.font;
uint lineHeight = font->getLineHeight();
auto& metrics = cache.metrics;
uint lineHeight = metrics.lineHeight;
if (cache.lines.size() > 1) {
lineHeight *= lineInterval;
}
@ -114,12 +115,12 @@ glm::vec2 Label::calcSize() {
if (multiline) {
return glm::vec2(
cache.multilineWidth,
lineHeight * cache.lines.size() + font->getYOffset()
lineHeight * cache.lines.size() + metrics.yoffset
);
}
return glm::vec2 (
cache.font->calcWidth(view),
lineHeight * cache.lines.size() + font->getYOffset()
cache.metrics.calcWidth(view),
lineHeight * cache.lines.size() + metrics.yoffset
);
}
@ -135,7 +136,7 @@ void Label::setText(std::wstring text) {
this->text = std::move(text);
cache.update(this->text, multiline, textWrap);
if (cache.font && autoresize) {
if (cache.fontId != 0 && autoresize) {
setSize(calcSize());
}
}
@ -203,7 +204,11 @@ uint Label::getLinesNumber() const {
void Label::draw(const DrawContext& pctx, const Assets& assets) {
auto batch = pctx.getBatch2D();
auto font = assets.get<Font>(fontName);
cache.prepare(font, static_cast<size_t>(glm::abs(getSize().x)));
cache.prepare(
reinterpret_cast<ptrdiff_t>(font),
font->getMetrics(),
static_cast<size_t>(glm::abs(getSize().x))
);
if (supplier) {
setText(supplier());

View File

@ -3,6 +3,8 @@
#include "UINode.hpp"
#include "constants.hpp"
#include "graphics/core/FontMetics.hpp"
class Font;
struct FontStylesScheme;
@ -13,14 +15,16 @@ namespace gui {
};
struct LabelCache {
Font* font = nullptr;
ptrdiff_t fontId = 0;
FontMetrics metrics;
std::vector<LineScheme> lines;
/// @brief Reset cache flag
bool resetFlag = true;
size_t wrapWidth = -1;
int multilineWidth = 0;
void prepare(Font* font, size_t wrapWidth);
void prepare(std::ptrdiff_t fontId, FontMetrics metrics, size_t wrapWidth);
void update(std::wstring_view text, bool multiline, bool wrap);
size_t getTextLineOffset(size_t line) const;

View File

@ -231,8 +231,6 @@ TextBox::~TextBox() = default;
void TextBox::draw(const DrawContext& pctx, const Assets& assets) {
Container::draw(pctx, assets);
font = assets.get<Font>(label->getFontName());
if (!isFocused()) {
return;
}
@ -244,7 +242,8 @@ void TextBox::draw(const DrawContext& pctx, const Assets& assets) {
auto subctx = pctx.sub();
subctx.setScissors(glm::vec4(pos.x, pos.y, size.x, size.y));
const int lineHeight = font->getLineHeight() * label->getLineInterval();
const int lineHeight =
rawTextCache.metrics.lineHeight * label->getLineInterval();
glm::vec2 lcoord = label->calcPos();
lcoord.y -= 2;
auto batch = pctx.getBatch2D();
@ -256,7 +255,7 @@ void TextBox::draw(const DrawContext& pctx, const Assets& assets) {
if (editable && static_cast<int>((time - caretLastMove) * 2) % 2 == 0) {
uint line = rawTextCache.getLineByTextIndex(caret);
uint lcaret = caret - rawTextCache.getTextLineOffset(line);
int width = font->calcWidth(input, lcaret);
int width = rawTextCache.metrics.calcWidth(input, 0, lcaret);
batch->rect(
lcoord.x + width,
lcoord.y + label->getLineYOffset(line),
@ -272,10 +271,10 @@ void TextBox::draw(const DrawContext& pctx, const Assets& assets) {
uint endLine = label->getLineByTextIndex(selectionEnd);
batch->setColor(glm::vec4(0.8f, 0.9f, 1.0f, 0.25f));
int start = font->calcWidth(
int start = rawTextCache.metrics.calcWidth(
labelText, selectionStart - label->getTextLineOffset(startLine)
);
int end = font->calcWidth(
int end = rawTextCache.metrics.calcWidth(
labelText, selectionEnd - label->getTextLineOffset(endLine)
);
int lineY = label->getLineYOffset(startLine);
@ -346,7 +345,14 @@ void TextBox::draw(const DrawContext& pctx, const Assets& assets) {
}
}
void TextBox::drawBackground(const DrawContext& pctx, const Assets&) {
void TextBox::drawBackground(const DrawContext& pctx, const Assets& assets) {
auto font = assets.get<Font>(label->getFontName());
rawTextCache.prepare(
reinterpret_cast<ptrdiff_t>(font),
font->getMetrics(),
label->getSize().x
);
glm::vec2 pos = calcPos();
auto batch = pctx.getBatch2D();
@ -375,7 +381,11 @@ void TextBox::drawBackground(const DrawContext& pctx, const Assets&) {
}
void TextBox::refreshLabel() {
rawTextCache.prepare(font, static_cast<size_t>(getSize().x));
rawTextCache.prepare(
rawTextCache.fontId,
rawTextCache.metrics,
static_cast<size_t>(getSize().x)
);
rawTextCache.update(input, multiline, false);
label->setColor(textColor * glm::vec4(input.empty() ? 0.5f : 1.0f));
@ -412,13 +422,13 @@ void TextBox::refreshLabel() {
lineNumbersLabel->setColor(glm::vec4(1, 1, 1, 0.25f));
}
if (autoresize && font) {
if (autoresize && rawTextCache.fontId) {
auto size = getSize();
int newy = glm::min(
static_cast<int>(parent->getSize().y),
static_cast<int>(
label->getLinesNumber() * label->getLineInterval() *
font->getLineHeight()
rawTextCache.metrics.lineHeight
) + 1
);
if (newy != static_cast<int>(size.y)) {
@ -430,9 +440,9 @@ void TextBox::refreshLabel() {
}
}
if (multiline && font) {
if (multiline && rawTextCache.fontId) {
setScrollable(true);
uint height = label->getLinesNumber() * font->getLineHeight() *
uint height = label->getLinesNumber() * rawTextCache.metrics.lineHeight *
label->getLineInterval();
label->setSize(glm::vec2(label->getSize().x, height));
actualLength = height;
@ -644,14 +654,14 @@ size_t TextBox::normalizeIndex(int index) {
/// @param y screen Y position
/// @return non-normalized character index
int TextBox::calcIndexAt(int x, int y) const {
if (font == nullptr) return 0;
if (rawTextCache.fontId == 0) return 0;
const auto& labelText = label->getText();
glm::vec2 lcoord = label->calcPos();
uint line = label->getLineByYOffset(y - lcoord.y);
line = std::min(line, label->getLinesNumber() - 1);
size_t lineLength = getLineLength(line);
uint offset = 0;
while (lcoord.x + font->calcWidth(labelText, offset) < x &&
while (lcoord.x + rawTextCache.metrics.calcWidth(labelText, offset) < x &&
offset < lineLength - 1) {
offset++;
}
@ -1177,19 +1187,19 @@ size_t TextBox::getCaret() const {
void TextBox::setCaret(size_t position) {
const auto& labelText = label->getText();
caret = std::min(static_cast<size_t>(position), input.length());
if (font == nullptr) {
if (rawTextCache.fontId == 0) {
return;
}
int width = label->getSize().x;
rawTextCache.prepare(font, width);
rawTextCache.prepare(rawTextCache.fontId, rawTextCache.metrics, width);
rawTextCache.update(input, multiline, label->isTextWrapping());
caretLastMove = gui.getWindow().time();
uint line = rawTextCache.getLineByTextIndex(caret);
int offset = label->getLineYOffset(line) + getContentOffset().y;
uint lineHeight = font->getLineHeight() * label->getLineInterval();
uint lineHeight = rawTextCache.metrics.lineHeight * label->getLineInterval();
if (scrollStep == 0) {
scrollStep = lineHeight;
}
@ -1201,7 +1211,7 @@ void TextBox::setCaret(size_t position) {
}
int lcaret = caret - rawTextCache.getTextLineOffset(line);
int realoffset =
font->calcWidth(labelText, lcaret) - static_cast<int>(textOffset) + 2;
rawTextCache.metrics.calcWidth(labelText, lcaret) - static_cast<int>(textOffset) + 2;
if (realoffset - width > 0) {
setTextOffset(textOffset + realoffset - width);

View File

@ -52,7 +52,6 @@ namespace gui {
int textInitX = 0;
/// @brief Last time of the caret was moved (used for blink animation)
double caretLastMove = 0.0;
Font* font = nullptr;
// Note: selection does not include markup
size_t selectionStart = 0;

View File

@ -152,8 +152,9 @@ static void read_uinode(
if (element.has("pressed-color")) {
node.setPressedColor(element.attr("pressed-color").asColor());
}
const auto& alignName = element.attr("align", "").getText();
node.setAlign(align_from_string(alignName, node.getAlign()));
node.setAlign(
align_from_string(element.attr("align", "").getText(), node.getAlign())
);
if (element.has("gravity")) {
node.setGravity(gravity_from_string(element.attr("gravity").getText()));

View File

@ -33,8 +33,7 @@ static int l_tostring(lua::State* L) {
lua::pop(L);
return lua::pushlstring(L, buffer.data(), size);
} else {
lua::bytearray_as_string(L, 1);
return 1;
return lua::pushlstring(L, lua::bytearray_as_string(L, 1));
}
}

View File

@ -133,7 +133,6 @@ dv::value lua::tovalue(State* L, int idx) {
auto bytes = std::make_shared<dv::objects::Bytes>(
reinterpret_cast<const ubyte*>(data.data()), data.size()
);
pop(L);
return bytes;
}
}

View File

@ -768,9 +768,12 @@ namespace lua {
}
inline std::string_view bytearray_as_string(lua::State* L, int idx) {
lua::requireglobal(L, "Bytearray_as_string");
lua::pushvalue(L, idx);
lua::requireglobal(L, "Bytearray_as_string");
lua::pushvalue(L, -2);
lua::call(L, 1, 1);
return lua::tolstring(L, -1);
auto view = lua::tolstring(L, -1);
lua::pop(L, 2);
return view;
}
}

View File

@ -379,7 +379,6 @@ public:
}
totalDownload += size;
}
logger.debug() << "read " << size << " bytes from " << to_string(addr);
}
}
@ -697,7 +696,8 @@ public:
while (open) {
int size = recv(descriptor, buffer.data(), buffer.size(), 0);
if (size <= 0) {
logger.error() <<id <<"udp connection " << id << handle_socket_error(" recv error").what();
logger.error() << "udp connection " << id
<< handle_socket_error(" recv error").what();
if (!open) break;
closesocket(descriptor);
state = ConnectionState::CLOSED;

View File

@ -412,7 +412,7 @@ void Entities::render(
const auto& size = transform.size;
if (!frustum || frustum->isBoxVisible(pos - size, pos + size)) {
const auto* rigConfig = skeleton.config;
rigConfig->render(assets, batch, skeleton, transform.combined, pos);
rigConfig->render(assets, batch, skeleton, transform.rot, pos);
}
}
}

View File

@ -1,14 +1,14 @@
#include "rigging.hpp"
#include <glm/ext/matrix_transform.hpp>
#include <glm/gtx/matrix_decompose.hpp>
#include "assets/Assets.hpp"
#include "coders/json.hpp"
#include "data/dv_util.hpp"
#include "graphics/commons/Model.hpp"
#include "graphics/render/ModelBatch.hpp"
#include <glm/ext/matrix_transform.hpp>
#include <glm/gtx/matrix_decompose.hpp>
using namespace rigging;
void ModelReference::refresh(const Assets& assets) {
@ -122,21 +122,26 @@ size_t SkeletonConfig::update(
return count;
}
static glm::mat4 build_matrix(const glm::mat3& rot, const glm::vec3& pos) {
glm::mat4 combined(1.0f);
combined = glm::translate(combined, pos);
combined = combined * glm::mat4(rot);
return combined;
}
void SkeletonConfig::update(
Skeleton& skeleton, const glm::mat4& matrix, const glm::vec3& position
Skeleton& skeleton, const glm::mat3& rotation, const glm::vec3& position
) const {
if (skeleton.interpolation.isEnabled()) {
const auto& interpolation = skeleton.interpolation;
glm::vec3 scale, translation, skew;
glm::quat rotation;
glm::vec4 perspective;
glm::decompose(matrix, scale, rotation, translation, skew, perspective);
auto delta = interpolation.getCurrent() - position;
auto interpolatedMatrix = glm::translate(matrix, delta);
update(0, skeleton, root.get(), interpolatedMatrix);
update(
0,
skeleton,
root.get(),
build_matrix(rotation, interpolation.getCurrent())
);
} else {
update(0, skeleton, root.get(), matrix);
update(0, skeleton, root.get(), rotation);
}
}
@ -144,10 +149,10 @@ void SkeletonConfig::render(
const Assets& assets,
ModelBatch& batch,
Skeleton& skeleton,
const glm::mat4& matrix,
const glm::mat3& rotation,
const glm::vec3& position
) const {
update(skeleton, matrix, position);
update(skeleton, rotation, position);
if (!skeleton.visible) {
return;

View File

@ -120,7 +120,7 @@ namespace rigging {
void update(
Skeleton& skeleton,
const glm::mat4& matrix,
const glm::mat3& rotation,
const glm::vec3& position
) const;
@ -128,7 +128,7 @@ namespace rigging {
const Assets& assets,
ModelBatch& batch,
Skeleton& skeleton,
const glm::mat4& matrix,
const glm::mat3& rotation,
const glm::vec3& position
) const;

View File

@ -1,9 +1,11 @@
#include "WorldRegions.hpp"
#include <cstring>
#include "WorldRegions.hpp"
#include "debug/Logger.hpp"
#include "util/data_io.hpp"
static debug::Logger logger("regions-layer");
#define REGION_FORMAT_MAGIC ".VOXREG"
static io::path get_region_filename(int x, int z) {
@ -20,31 +22,39 @@ static void fetch_chunks(WorldRegion* region, int x, int z, regfile* file) {
int chunk_z = (i / REGION_SIZE) + z * REGION_SIZE;
if (chunks[i] == nullptr) {
chunks[i] = RegionsLayer::readChunkData(
chunk_x, chunk_z, sizes[i][0], sizes[i][1], file);
chunk_x, chunk_z, sizes[i][0], sizes[i][1], file
);
}
}
}
regfile::regfile(io::path filename) : file(std::move(filename)) {
regfile::regfile(io::path filename) : file(filename), filename(filename) {
if (file.length() < REGION_HEADER_SIZE)
throw std::runtime_error("incomplete region file header");
throw std::runtime_error(
"incomplete region file header in " + filename.string()
);
char header[REGION_HEADER_SIZE];
file.read(header, REGION_HEADER_SIZE);
// avoid of use strcmp_s
if (std::string(header, std::strlen(REGION_FORMAT_MAGIC)) !=
REGION_FORMAT_MAGIC) {
throw std::runtime_error("invalid region file magic number");
throw std::runtime_error(
"invalid region file magic number in " + filename.string()
);
}
version = header[8];
if (static_cast<uint>(version) > REGION_FORMAT_VERSION) {
throw illegal_region_format(
"region format " + std::to_string(version) + " is not supported"
"region format " + std::to_string(version) +
" is not supported in " + filename.string()
);
}
}
std::unique_ptr<ubyte[]> regfile::read(int index, uint32_t& size, uint32_t& srcSize) {
std::unique_ptr<ubyte[]> regfile::read(
int index, uint32_t& size, uint32_t& srcSize
) {
size_t file_size = file.length();
size_t table_offset = file_size - REGION_CHUNKS_COUNT * 4;
@ -62,12 +72,17 @@ std::unique_ptr<ubyte[]> regfile::read(int index, uint32_t& size, uint32_t& srcS
file.read(reinterpret_cast<char*>(&buff32), 4);
srcSize = dataio::le2h(buff32);
if (offset + size > file_size) {
logger.error() << "corrupted region " << filename.string()
<< " chunk offset detected at "
<< (table_offset + index * 4);
return nullptr;
}
auto data = std::make_unique<ubyte[]>(size);
file.read(reinterpret_cast<char*>(data.get()), size);
return data;
}
void RegionsLayer::closeRegFile(glm::ivec2 coord) {
openRegFiles.erase(coord);
regFilesCv.notify_one();
@ -192,7 +207,7 @@ void RegionsLayer::writeRegion(int x, int z, WorldRegion* entry) {
char header[REGION_HEADER_SIZE] = REGION_FORMAT_MAGIC;
header[8] = REGION_FORMAT_VERSION;
header[9] = static_cast<ubyte>(compression); // FIXME
header[9] = static_cast<ubyte>(compression); // FIXME
std::ofstream file(io::resolve(filename), std::ios::out | std::ios::binary);
file.write(header, REGION_HEADER_SIZE);
@ -213,7 +228,7 @@ void RegionsLayer::writeRegion(int x, int z, WorldRegion* entry) {
auto sizevec = sizes[i];
uint32_t compressedSize = sizevec[0];
uint32_t srcSize = sizevec[1];
intbuf = dataio::h2le(compressedSize);
file.write(reinterpret_cast<const char*>(&intbuf), 4);
offset += 4;

View File

@ -238,8 +238,10 @@ std::unique_ptr<light_t[]> WorldRegions::getLights(int x, int z) {
auto data = compression::decompress(
bytes, size, srcSize, layer.compression
);
assert(srcSize == LIGHTMAP_DATA_LEN);
return Lightmap::decode(data.get());
if (srcSize == LIGHTMAP_DATA_LEN) {
return Lightmap::decode(data.get());
}
return nullptr;
}
ChunkInventoriesMap WorldRegions::fetchInventories(int x, int z) {

View File

@ -52,6 +52,7 @@ public:
struct regfile {
io::rafile file;
io::path filename;
int version;
bool inUse = false;